Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into Ghommie-cit616
This commit is contained in:
@@ -1732,7 +1732,7 @@
|
||||
var/mob/M = locate(href_list["makeeligible"])
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "this can only be used on instances of type /mob.")
|
||||
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(/datum/element/ghost_role_eligibility)
|
||||
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
|
||||
if(M.ckey in eli.timeouts)
|
||||
eli.timeouts -= M.ckey
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
icon_state = "blob_glow"
|
||||
flags_1 = CHECK_RICOCHET_1
|
||||
point_return = 8
|
||||
max_integrity = 50
|
||||
max_integrity = 100
|
||||
brute_resist = 1
|
||||
explosion_block = 2
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
var/list/nodes = list()
|
||||
for(var/i in 1 to GLOB.blob_nodes.len)
|
||||
var/obj/structure/blob/node/B = GLOB.blob_nodes[i]
|
||||
nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blobstrain.name]":"No Strain"])"] = B
|
||||
nodes["Blob Node #[i] ([get_area_name(B)])"] = B
|
||||
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
|
||||
var/obj/structure/blob/node/chosen_node = nodes[node_name]
|
||||
if(chosen_node)
|
||||
@@ -120,13 +120,13 @@
|
||||
/mob/camera/blob/proc/create_shield(turf/T)
|
||||
var/obj/structure/blob/shield/S = locate(/obj/structure/blob/shield) in T
|
||||
if(S)
|
||||
if(!can_buy(15))
|
||||
if(!can_buy(BLOB_REFLECTOR_COST))
|
||||
return
|
||||
if(S.obj_integrity < S.max_integrity * 0.5)
|
||||
add_points(BLOB_REFLECTOR_COST)
|
||||
to_chat(src, "<span class='warning'>This shield blob is too damaged to be modified properly!</span>")
|
||||
return
|
||||
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced intregrity.</span>")
|
||||
to_chat(src, "<span class='warning'>You secrete a reflective ooze over the shield blob, allowing it to reflect projectiles at the cost of reduced integrity.</span>")
|
||||
S.change_to(/obj/structure/blob/shield/reflective, src)
|
||||
else
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
@@ -247,8 +247,8 @@
|
||||
|
||||
/mob/camera/blob/verb/expand_blob_power()
|
||||
set category = "Blob"
|
||||
set name = "Expand/Attack Blob (4)"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
|
||||
set name = "Expand/Attack Blob ([BLOB_SPREAD_COST])"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects and refunding [BLOB_ATTACK_REFUND] points."
|
||||
var/turf/T = get_turf(src)
|
||||
expand_blob(T)
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
if(!possibleblobs.len)
|
||||
to_chat(src, "<span class='warning'>There is no blob adjacent to the target tile!</span>")
|
||||
return
|
||||
if(can_buy(4))
|
||||
if(can_buy(BLOB_SPREAD_COST))
|
||||
var/attacksuccess = FALSE
|
||||
for(var/mob/living/L in T)
|
||||
if(ROLE_BLOB in L.faction) //no friendly/dead fire
|
||||
@@ -271,11 +271,11 @@
|
||||
blobstrain.attack_living(L)
|
||||
var/obj/structure/blob/B = locate() in T
|
||||
if(B)
|
||||
if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
|
||||
if(attacksuccess) //if we successfully attacked a turf with a blob on it, only give an attack refund
|
||||
B.blob_attack_animation(T, src)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>There is a blob there!</span>")
|
||||
add_points(4) //otherwise, refund all of the cost
|
||||
add_points(BLOB_SPREAD_COST) //otherwise, refund all of the cost
|
||||
else
|
||||
var/list/cardinalblobs = list()
|
||||
var/list/diagonalblobs = list()
|
||||
@@ -288,14 +288,15 @@
|
||||
var/obj/structure/blob/OB
|
||||
if(cardinalblobs.len)
|
||||
OB = pick(cardinalblobs)
|
||||
OB.expand(T, src)
|
||||
if(!OB.expand(T, src))
|
||||
add_points(BLOB_ATTACK_REFUND) //assume it's attacked SOMETHING, possibly a structure
|
||||
else
|
||||
OB = pick(diagonalblobs)
|
||||
if(attacksuccess)
|
||||
OB.blob_attack_animation(T, src)
|
||||
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
|
||||
else
|
||||
add_points(4) //if we're attacking diagonally and didn't hit anything, refund
|
||||
add_points(BLOB_SPREAD_COST) //if we're attacking diagonally and didn't hit anything, refund
|
||||
if(attacksuccess)
|
||||
last_attack = world.time + CLICK_CD_MELEE
|
||||
else
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
// EXPLANATION
|
||||
/datum/objective/bloodsucker/lair/update_explanation_text()
|
||||
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift"// Make sure to keep it safe!"
|
||||
explanation_text = "Create a lair by claiming a coffin, and protect it until the end of the shift."// Make sure to keep it safe!"
|
||||
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/lair/check_completion()
|
||||
@@ -228,7 +228,7 @@
|
||||
if (SC && SC.lastgen > 0 && SC.connected_panels.len > 0 && SC.connected_tracker)
|
||||
return FALSE
|
||||
return TRUE
|
||||
*/
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -250,15 +250,15 @@
|
||||
// WIN CONDITIONS?
|
||||
/datum/objective/bloodsucker/heartthief/check_completion()
|
||||
// -Must have a body.
|
||||
if (!owner.current)
|
||||
if(!owner.current)
|
||||
return FALSE
|
||||
// Taken from /steal in objective.dm
|
||||
var/list/all_items = owner.current.GetAllContents() // Includes items inside other items.
|
||||
var/itemcount = FALSE
|
||||
for(var/obj/I in all_items) //Check for items
|
||||
if(I == /obj/item/organ/heart)
|
||||
itemcount ++
|
||||
if (itemcount >= target_amount) // Got the right amount?
|
||||
if(istype(I, /obj/item/organ/heart/))
|
||||
itemcount++
|
||||
if(itemcount >= target_amount) // Got the right amount?
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
user.dropItemToGround(src, TRUE) //user.drop_item() // "drop item" doesn't seem to exist anymore. New proc is user.dropItemToGround() but it doesn't seem like it's needed now?
|
||||
var/obj/item/bodypart/B = C.get_bodypart("chest") // This was all taken from hitby() in human_defense.dm
|
||||
B.embedded_objects |= src
|
||||
embedded()
|
||||
add_mob_blood(target)//Place blood on the stake
|
||||
loc = C // Put INSIDE the character
|
||||
B.receive_damage(w_class * embedding.embedded_impact_pain_multiplier)
|
||||
|
||||
@@ -13,17 +13,14 @@
|
||||
var/mob/living/carbon/human/H = user //SHOULD always be human, because req_human = 1
|
||||
if(!istype(H)) // req_human could be done in can_sting stuff.
|
||||
return
|
||||
var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
|
||||
if(HM in H.dna.mutations)
|
||||
HM.force_lose(H)
|
||||
if(H.dna.get_mutation(CHAMELEON))
|
||||
H.dna.remove_mutation(CHAMELEON)
|
||||
else
|
||||
HM.force_give(H)
|
||||
H.dna.add_mutation(CHAMELEON)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/chameleon_skin/on_refund(mob/user)
|
||||
action.Remove(user)
|
||||
if(user.has_dna())
|
||||
var/mob/living/carbon/C = user
|
||||
var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
|
||||
if(HM in C.dna.mutations)
|
||||
HM.force_lose(C)
|
||||
C.dna.remove_mutation(CHAMELEON)
|
||||
@@ -5,6 +5,7 @@
|
||||
max_occurrences = 0
|
||||
earliest_start = 30 MINUTES
|
||||
min_players = 15
|
||||
gamemode_blacklist = list("dynamic")
|
||||
|
||||
|
||||
/datum/round_event/spawn_swarmer
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/reinstate_escape_objective()
|
||||
..()
|
||||
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
@@ -215,20 +215,12 @@
|
||||
kill_objective.target = target_mind
|
||||
kill_objective.update_explanation_text()
|
||||
add_objective(kill_objective)
|
||||
|
||||
//Optional traitor objective
|
||||
if(prob(PROB_ACTUAL_TRAITOR))
|
||||
employer = "The Syndicate"
|
||||
owner.special_role = TRAITOR_AGENT_ROLE
|
||||
special_role = TRAITOR_AGENT_ROLE
|
||||
syndicate = TRUE
|
||||
forge_single_objective()
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/forge_traitor_objectives()
|
||||
forge_iaa_objectives()
|
||||
|
||||
var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive
|
||||
var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive
|
||||
var/datum/objective/escape_objective = new objtype
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/datum/traitor_class/ai // this one is special, so has no weight
|
||||
name = "Malfunctioning AI"
|
||||
|
||||
/datum/traitor_class/ai/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/exist/exist_objective = new
|
||||
exist_objective.owner = T.owner
|
||||
T.add_objective(exist_objective)
|
||||
|
||||
/datum/traitor_class/ai/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = T.owner
|
||||
T.add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = T.owner
|
||||
T.add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = T.owner
|
||||
T.add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = T.owner
|
||||
T.add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = T.owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
T.add_objective(yandere_two)
|
||||
.=2
|
||||
|
||||
/datum/traitor_class/ai/on_removal(datum/antagonist/traitor/T)
|
||||
var/mob/living/silicon/ai/A = T.owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_malf_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
|
||||
|
||||
/datum/traitor_class/ai/apply_innate_effects(mob/living/M)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = TRUE
|
||||
|
||||
/datum/traitor_class/ai/remove_innate_effects(mob/living/M)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = FALSE
|
||||
|
||||
/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.add_law_zero()
|
||||
T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
T.owner.current.grant_language(/datum/language/codespeak)
|
||||
return FALSE
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/traitor_class/human/assassin
|
||||
name = "Donk Co Operative"
|
||||
employer = "Donk Corporation"
|
||||
weight = 0
|
||||
chaos = 1
|
||||
cost = 2
|
||||
|
||||
/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/permakill_prob = 20
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
permakill_prob = max(0,mode.threat_level-50)
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else if(prob(permakill_prob))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
@@ -0,0 +1,12 @@
|
||||
/datum/traitor_class/human/freeform
|
||||
name = "Waffle Co Agent"
|
||||
employer = "Waffle Company"
|
||||
weight = 16
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/escape/O = new
|
||||
O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/traitor_class/human/hijack
|
||||
name = "Gorlex Marauder"
|
||||
employer = "The Gorlex Marauders"
|
||||
weight = 3
|
||||
chaos = 5
|
||||
cost = 5
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit)
|
||||
|
||||
/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/hijack/O = new
|
||||
O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked by hacking its navigational protocols through the control console (alt click emergency shuttle console)."
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
|
||||
/datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.hijack_speed=1
|
||||
return TRUE
|
||||
@@ -0,0 +1,82 @@
|
||||
/datum/traitor_class/human
|
||||
name = "Syndicate Agent"
|
||||
chaos = 0
|
||||
|
||||
/datum/traitor_class/human/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/objective_count = 0 //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = T.owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = T.owner
|
||||
T.assign_exchange_role(SSticker.mode.exchange_red)
|
||||
T.assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective(T)
|
||||
if(!(locate(/datum/objective/escape) in T.objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = T.owner
|
||||
T.add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/traitor_class/human/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = max(0,mode.threat_level-20)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = T.owner
|
||||
destroy_objective.find_target()
|
||||
T.add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else if(prob(max(0,assassin_prob-20)))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
else if(prob(40)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
else if(prob(100/3)) // cum. not counting download: 20%.
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
else // cum. not counting download: 40%
|
||||
var/datum/objective/flavor/traitor/flavor_objective = new
|
||||
flavor_objective.owner = T.owner
|
||||
flavor_objective.forge_objective()
|
||||
T.add_objective(flavor_objective)
|
||||
|
||||
/datum/traitor_class/human/greet(datum/antagonist/traitor/T)
|
||||
to_chat(T.owner.current, "<B><font size=2 color=red>You are under contract with [employer]. They have given you your objectives.</font></B>")
|
||||
@@ -0,0 +1,14 @@
|
||||
/datum/traitor_class/human/martyr
|
||||
name = "Tiger Cooperator"
|
||||
employer = "The Tiger Cooperative"
|
||||
weight = 2
|
||||
chaos = 5
|
||||
cost = 5
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
|
||||
|
||||
/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
|
||||
var/datum/objective/martyr/O = new
|
||||
O.explanation_text = "The tiger cooperative have given you free reign. You may do as you wish, as long as you die a glorious death!"
|
||||
O.owner = T.owner
|
||||
T.add_objective(O)
|
||||
return
|
||||
@@ -0,0 +1,40 @@
|
||||
/datum/traitor_class/human/subterfuge
|
||||
name = "MI13 Operative"
|
||||
employer = "MI13"
|
||||
weight = 20
|
||||
chaos = -5
|
||||
|
||||
/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T)
|
||||
.=1
|
||||
var/assassin_prob = 30
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
assassin_prob = max(0,mode.threat_level-40)
|
||||
if(prob(assassin_prob))
|
||||
if(prob(assassin_prob))
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = T.owner
|
||||
kill_objective.find_target()
|
||||
T.add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = T.owner
|
||||
maroon_objective.find_target()
|
||||
T.add_objective(maroon_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = T.owner
|
||||
download_objective.gen_amount_goal()
|
||||
T.add_objective(download_objective)
|
||||
else if(prob(70)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = T.owner
|
||||
steal_objective.find_target()
|
||||
T.add_objective(steal_objective)
|
||||
else
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = T.owner
|
||||
sabotage_objective.find_target()
|
||||
T.add_objective(sabotage_objective)
|
||||
@@ -0,0 +1,40 @@
|
||||
GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
|
||||
/datum/traitor_class
|
||||
var/name = "Bad Coders Ltd."
|
||||
var/employer = "The Syndicate"
|
||||
var/weight = 0
|
||||
var/chaos = 0
|
||||
var/cost = 0
|
||||
var/TC = 20
|
||||
var/list/uplink_filters
|
||||
|
||||
/datum/traitor_class/New()
|
||||
..()
|
||||
if(src.type in GLOB.traitor_classes)
|
||||
qdel(src)
|
||||
else
|
||||
GLOB.traitor_classes += src.type
|
||||
GLOB.traitor_classes[src.type] = src
|
||||
|
||||
/datum/traitor_class/proc/forge_objectives(datum/antagonist/traitor/T)
|
||||
// Like the old forge_human_objectives. Makes all the objectives for this traitor class.
|
||||
|
||||
/datum/traitor_class/proc/forge_single_objective(datum/antagonist/traitor/T)
|
||||
// As forge_single_objective.
|
||||
|
||||
/datum/traitor_class/proc/on_removal(datum/antagonist/traitor/T)
|
||||
// What this does to the antag datum on removal. Called before proper removal, obviously.
|
||||
|
||||
/datum/traitor_class/proc/apply_innate_effects(mob/living/M)
|
||||
// What innate effects it should have. See: AI.
|
||||
|
||||
/datum/traitor_class/proc/remove_innate_effects(mob/living/M)
|
||||
// Cleaning up the innate effects.
|
||||
|
||||
/datum/traitor_class/proc/greet(datum/antagonist/traitor/T)
|
||||
// Message upon creation. Not necessary, but can be useful.
|
||||
|
||||
/datum/traitor_class/proc/finalize_traitor(datum/antagonist/traitor/T)
|
||||
// Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case
|
||||
return TRUE
|
||||
@@ -1,6 +1,3 @@
|
||||
#define TRAITOR_HUMAN "human"
|
||||
#define TRAITOR_AI "AI"
|
||||
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
roundend_category = "traitors"
|
||||
@@ -12,43 +9,52 @@
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
|
||||
var/datum/traitor_class/traitor_kind
|
||||
var/datum/contractor_hub/contractor_hub
|
||||
hijack_speed = 0.5 //10 seconds per hijack stage by default
|
||||
|
||||
/datum/antagonist/traitor/New()
|
||||
..()
|
||||
if(!GLOB.traitor_classes.len)//Only need to fill the list when it's needed.
|
||||
for(var/I in subtypesof(/datum/traitor_class))
|
||||
new I
|
||||
|
||||
/datum/antagonist/traitor/proc/set_traitor_kind(var/kind)
|
||||
traitor_kind = GLOB.traitor_classes[kind]
|
||||
if(istype(SSticker.mode, /datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
if(traitor_kind.cost)
|
||||
mode.spend_threat(traitor_kind.cost)
|
||||
mode.log_threat("[traitor_kind.cost] was spent due to [owner.name] being a [traitor_kind.name].")
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
traitor_kind = TRAITOR_AI
|
||||
|
||||
set_traitor_kind(TRAITOR_AI)
|
||||
else
|
||||
var/chaos_weight = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
var/datum/game_mode/dynamic/mode = SSticker.mode
|
||||
chaos_weight = (mode.threat - 50)/50
|
||||
var/list/weights = list()
|
||||
for(var/C in GLOB.traitor_classes)
|
||||
var/datum/traitor_class/class = GLOB.traitor_classes[C]
|
||||
var/weight = (1.5*class.weight)/(0.5+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function
|
||||
weights[C] = weight
|
||||
var/choice = pickweightAllowZero(weights)
|
||||
if(!choice)
|
||||
choice = GLOB.traitor_classes[TRAITOR_HUMAN]
|
||||
set_traitor_kind(pickweightAllowZero(weights))
|
||||
traitor_kind.weight *= 0.8 // less likely this round
|
||||
SSticker.mode.traitors += owner
|
||||
owner.special_role = special_role
|
||||
if(give_objectives)
|
||||
forge_traitor_objectives()
|
||||
traitor_kind.forge_objectives(src)
|
||||
finalize_traitor()
|
||||
..()
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
if(!silent)
|
||||
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
traitor_mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
traitor_mob.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
//Remove malf powers.
|
||||
if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current))
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.set_zeroth_law("")
|
||||
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
|
||||
A.malf_picker.remove_malf_verbs(A)
|
||||
qdel(A.malf_picker)
|
||||
traitor_kind.on_removal(src)
|
||||
SSticker.mode.traitors -= owner
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
|
||||
@@ -69,192 +75,11 @@
|
||||
objectives -= O
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
forge_ai_objectives()
|
||||
else
|
||||
forge_human_objectives()
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_human_objectives()
|
||||
var/is_hijacker = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
var/is_dynamic = FALSE
|
||||
var/hijack_prob = 0
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost))
|
||||
hijack_prob = CLAMP(mode.threat_level-50,0,20)
|
||||
if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit)
|
||||
is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
|
||||
else
|
||||
var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1)
|
||||
is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop]))
|
||||
if(mode.storyteller.flags & NO_ASSASSIN)
|
||||
is_hijacker = FALSE
|
||||
else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
|
||||
hijack_prob = 10
|
||||
is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(hijack_prob*2)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = owner
|
||||
assign_exchange_role(SSticker.mode.exchange_red)
|
||||
assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
var/toa = CONFIG_GET(number/traitor_objectives_amount)
|
||||
for(var/i = objective_count, i < toa, i++)
|
||||
forge_single_objective()
|
||||
|
||||
if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in objectives))
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = owner
|
||||
add_objective(hijack_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on hijack.")
|
||||
return
|
||||
|
||||
|
||||
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
|
||||
for(var/datum/objective/O in objectives)
|
||||
if(!O.martyr_compatible)
|
||||
martyr_compatibility = 0
|
||||
break
|
||||
|
||||
if(martyr_compatibility && martyr_chance)
|
||||
var/datum/objective/martyr/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on glorious death.")
|
||||
return
|
||||
|
||||
else
|
||||
if(!(locate(/datum/objective/escape) in objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
return
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_ai_objectives()
|
||||
var/objective_count = 0
|
||||
|
||||
if(prob(30))
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
|
||||
var/datum/objective/survive/exist/exist_objective = new
|
||||
exist_objective.owner = owner
|
||||
add_objective(exist_objective)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_objective()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
return forge_single_AI_objective()
|
||||
else
|
||||
return forge_single_human_objective()
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_human_objective() //Returns how many objectives are added
|
||||
.=1
|
||||
var/assassin_prob = 50
|
||||
var/is_dynamic = FALSE
|
||||
var/datum/game_mode/dynamic/mode
|
||||
if(istype(SSticker.mode,/datum/game_mode/dynamic))
|
||||
mode = SSticker.mode
|
||||
is_dynamic = TRUE
|
||||
assassin_prob = max(0,mode.threat_level-20)
|
||||
if(prob(assassin_prob))
|
||||
if(is_dynamic)
|
||||
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
|
||||
mode.spend_threat(threat_spent)
|
||||
mode.log_threat("[owner.name] spent [threat_spent] on an assassination target.")
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.find_target()
|
||||
add_objective(destroy_objective)
|
||||
else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN)))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
add_objective(maroon_objective)
|
||||
else if(prob(max(0,assassin_prob-20)))
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
var/datum/objective/assassinate/once/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
add_objective(kill_objective)
|
||||
else
|
||||
if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist")))
|
||||
var/datum/objective/download/download_objective = new
|
||||
download_objective.owner = owner
|
||||
download_objective.gen_amount_goal()
|
||||
add_objective(download_objective)
|
||||
else if(prob(40)) // cum. not counting download: 40%.
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = owner
|
||||
steal_objective.find_target()
|
||||
add_objective(steal_objective)
|
||||
else if(prob(100/3)) // cum. not counting download: 20%.
|
||||
var/datum/objective/sabotage/sabotage_objective = new
|
||||
sabotage_objective.owner = owner
|
||||
sabotage_objective.find_target()
|
||||
add_objective(sabotage_objective)
|
||||
else // cum. not counting download: 40%
|
||||
var/datum/objective/flavor/traitor/flavor_objective = new
|
||||
flavor_objective.owner = owner
|
||||
flavor_objective.forge_objective()
|
||||
add_objective(flavor_objective)
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_AI_objective()
|
||||
.=1
|
||||
var/special_pick = rand(1,4)
|
||||
switch(special_pick)
|
||||
if(1)
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = owner
|
||||
add_objective(block_objective)
|
||||
if(2)
|
||||
var/datum/objective/purge/purge_objective = new
|
||||
purge_objective.owner = owner
|
||||
add_objective(purge_objective)
|
||||
if(3)
|
||||
var/datum/objective/robot_army/robot_objective = new
|
||||
robot_objective.owner = owner
|
||||
add_objective(robot_objective)
|
||||
if(4) //Protect and strand a target
|
||||
var/datum/objective/protect/yandere_one = new
|
||||
yandere_one.owner = owner
|
||||
add_objective(yandere_one)
|
||||
yandere_one.find_target()
|
||||
var/datum/objective/maroon/yandere_two = new
|
||||
yandere_two.owner = owner
|
||||
yandere_two.target = yandere_one.target
|
||||
yandere_two.update_explanation_text() // normally called in find_target()
|
||||
add_objective(yandere_two)
|
||||
.=2
|
||||
traitor_kind.forge_objectives(src)
|
||||
|
||||
/datum/antagonist/traitor/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role].</font></B>")
|
||||
traitor_kind.greet(src)
|
||||
owner.announce_objectives()
|
||||
if(should_give_codewords)
|
||||
give_codewords()
|
||||
@@ -270,32 +95,33 @@
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
/datum/antagonist/traitor/proc/finalize_traitor()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
owner.current.grant_language(/datum/language/codespeak)
|
||||
if(TRAITOR_HUMAN)
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
if(traitor_kind.finalize_traitor(src))
|
||||
if(should_equip)
|
||||
equip(silent)
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
update_traitor_icons_added()
|
||||
var/mob/M = mob_override || owner.current
|
||||
if(isAI(M) && traitor_kind == TRAITOR_AI)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = TRUE
|
||||
traitor_kind.apply_innate_effects(M)
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
if(!silent)
|
||||
to_chat(H, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
RegisterSignal(M, COMSIG_MOVABLE_HEAR, .proc/handle_hearing)
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
update_traitor_icons_removed()
|
||||
var/mob/M = mob_override || owner.current
|
||||
if(isAI(M) && traitor_kind == TRAITOR_AI)
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.hack_software = FALSE
|
||||
traitor_kind.remove_innate_effects(M)
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
UnregisterSignal(M, COMSIG_MOVABLE_HEAR)
|
||||
|
||||
/datum/antagonist/traitor/proc/give_codewords()
|
||||
@@ -326,8 +152,7 @@
|
||||
killer.add_malf_picker()
|
||||
|
||||
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
|
||||
if(traitor_kind == TRAITOR_HUMAN)
|
||||
owner.equip_traitor(employer, silent, src)
|
||||
owner.equip_traitor(traitor_kind, silent, src)
|
||||
|
||||
/datum/antagonist/traitor/proc/assign_exchange_role()
|
||||
//set faction
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
return
|
||||
H.dna.add_mutation(HULK)
|
||||
H.dna.add_mutation(XRAY)
|
||||
H.dna.add_mutation(COLDRES)
|
||||
H.dna.add_mutation(SPACEMUT)
|
||||
H.dna.add_mutation(TK)
|
||||
@@ -375,6 +375,8 @@
|
||||
desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
|
||||
item_path = /obj/item/storage/belt/wands/full
|
||||
category = "Defensive"
|
||||
dynamic_requirement = 60
|
||||
dynamic_cost = 10
|
||||
|
||||
/datum/spellbook_entry/item/armor
|
||||
name = "Mastercrafted Armor Set"
|
||||
|
||||
@@ -103,10 +103,10 @@
|
||||
bombassembly.setDir(dir)
|
||||
bombassembly.Move()
|
||||
|
||||
/obj/item/onetankbomb/dropped()
|
||||
/obj/item/onetankbomb/dropped(mob/user)
|
||||
. = ..()
|
||||
if(bombassembly)
|
||||
bombassembly.dropped()
|
||||
bombassembly.dropped(user)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@
|
||||
/obj/item/assembly_holder/dropped(mob/user)
|
||||
. = ..()
|
||||
if(a_left)
|
||||
a_left.dropped()
|
||||
a_left.dropped(user)
|
||||
if(a_right)
|
||||
a_right.dropped()
|
||||
a_right.dropped(user)
|
||||
|
||||
/obj/item/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
. = ..()
|
||||
|
||||
@@ -20,13 +20,8 @@
|
||||
|
||||
/obj/item/assembly/infra/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(
|
||||
/datum/component/simple_rotation,
|
||||
ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS,
|
||||
null,
|
||||
null,
|
||||
CALLBACK(src,.proc/after_rotation)
|
||||
)
|
||||
var/static/rotation_flags = ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_FLIP | ROTATION_VERBS
|
||||
AddComponent(/datum/component/simple_rotation, rotation_flags, after_rotation=CALLBACK(src,.proc/after_rotation))
|
||||
|
||||
/obj/item/assembly/infra/proc/after_rotation()
|
||||
refreshBeam()
|
||||
@@ -74,7 +69,7 @@
|
||||
holder.update_icon()
|
||||
return
|
||||
|
||||
/obj/item/assembly/infra/dropped()
|
||||
/obj/item/assembly/infra/dropped(mob/user)
|
||||
. = ..()
|
||||
if(holder)
|
||||
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
|
||||
|
||||
@@ -379,7 +379,7 @@
|
||||
force = 75
|
||||
mag_type = /obj/item/ammo_box/magazine/m50/ctf
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped()
|
||||
/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
|
||||
|
||||
@@ -402,14 +402,14 @@
|
||||
desc = "This looks like it could really hurt in melee."
|
||||
force = 50
|
||||
|
||||
/obj/item/gun/ballistic/automatic/laser/ctf/dropped()
|
||||
/obj/item/gun/ballistic/automatic/laser/ctf/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
|
||||
|
||||
/obj/item/ammo_box/magazine/recharge/ctf
|
||||
ammo_type = /obj/item/ammo_casing/caseless/laser/ctf
|
||||
|
||||
/obj/item/ammo_box/magazine/recharge/ctf/dropped()
|
||||
/obj/item/ammo_box/magazine/recharge/ctf/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
|
||||
|
||||
@@ -475,7 +475,7 @@
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/claymore/ctf/dropped()
|
||||
/obj/item/claymore/ctf/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/ctf_floor_vanish, src), 1)
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
to_chat(user, "<B>Your wish is granted, but at a terrible cost...</B>")
|
||||
to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your body to match the darkness in your heart.")
|
||||
user.dna.add_mutation(LASEREYES)
|
||||
user.dna.add_mutation(COLDRES)
|
||||
user.dna.add_mutation(SPACEMUT)
|
||||
user.dna.add_mutation(XRAY)
|
||||
user.set_species(/datum/species/shadow)
|
||||
if("Wealth")
|
||||
|
||||
@@ -89,32 +89,17 @@
|
||||
|
||||
/datum/supply_pack/misc/paper_work
|
||||
name = "Freelance Paper work"
|
||||
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (20) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
|
||||
cost = 700 // Net of 0 credits but makes (120 x 20 = 2400)
|
||||
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
|
||||
cost = 700 // Net of 0 credits but makes (120 x 10 = 1200)
|
||||
contains = list(/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/folder/paperwork,
|
||||
/obj/item/pen/fountain
|
||||
)
|
||||
crate_name = "Paperwork"
|
||||
|
||||
/datum/supply_pack/misc/paper_work/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 9)
|
||||
new /obj/item/folder/paperwork(.)
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////// Entertainment ///////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -123,16 +108,14 @@
|
||||
name = "Bedsheet Crate (R)"
|
||||
desc = "Snuggle up in some sweet sheets with this assorted bedsheet crate. Each set comes with eight random bedsheets for your slumbering pleasure!"
|
||||
cost = 2000
|
||||
contains = list(/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random,
|
||||
/obj/item/bedsheet/random) //I'm lazy, and I copy paste stuff.
|
||||
contains = list(/obj/item/bedsheet/random)
|
||||
crate_name = "random bedsheet crate"
|
||||
|
||||
/datum/supply_pack/misc/randombedsheets/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/bedsheet/random(.)
|
||||
|
||||
/datum/supply_pack/misc/coloredsheets
|
||||
name = "Bedsheet Crate (C)"
|
||||
desc = "Give your night life a splash of color with this crate filled with bedsheets! Contains a total of nine different-colored sheets."
|
||||
@@ -208,13 +191,14 @@
|
||||
name = "Dueling Pistols"
|
||||
desc = "Resolve all your quarrels with some nonlethal fun."
|
||||
cost = 2000
|
||||
contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina,
|
||||
/obj/item/storage/lockbox/dueling/hugbox/stamina)
|
||||
contains = list(/obj/item/storage/lockbox/dueling/hugbox/stamina)
|
||||
crate_name = "dueling pistols"
|
||||
|
||||
/datum/supply_pack/misc/dueling_stam/generate()
|
||||
. = ..()
|
||||
for(var/i in 1 to 3)
|
||||
new /obj/item/storage/lockbox/dueling/hugbox/stamina(.)
|
||||
|
||||
/datum/supply_pack/misc/dueling_lethal
|
||||
name = "Lethal Dueling Pistols"
|
||||
desc = "Settle your differences the true spaceman way."
|
||||
@@ -240,12 +224,7 @@
|
||||
cost = 12000
|
||||
var/num_contained = 3
|
||||
contains = list(/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/a357,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/pistolm9mm,
|
||||
/obj/item/ammo_box/magazine/m45/kitchengun,
|
||||
/obj/item/ammo_box/magazine/m45/kitchengun)
|
||||
crate_name = "crate"
|
||||
|
||||
|
||||
@@ -703,3 +703,10 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
Insert(initial(D.id), I)
|
||||
return ..()
|
||||
|
||||
/datum/asset/simple/genetics
|
||||
assets = list(
|
||||
"dna_discovered.gif" = 'html/dna_discovered.gif',
|
||||
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
|
||||
"dna_extra.gif" = 'html/dna_extra.gif'
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
/client/verb/show_station_minimap()
|
||||
set category = "OOC"
|
||||
set name = "Show Station Minimap"
|
||||
set desc = "Shows a minimap of the currently loaded station map."
|
||||
|
||||
if(!CONFIG_GET(flag/minimaps_enabled))
|
||||
to_chat(usr, "<span class='boldwarning'>Minimap generation is not enabled in the server's configuration.</span>")
|
||||
return
|
||||
|
||||
SSminimaps.station_minimap.show(src)
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
var/flipped = 0
|
||||
|
||||
/obj/item/clothing/head/soft/dropped()
|
||||
src.icon_state = "[item_color]soft"
|
||||
src.flipped=0
|
||||
..()
|
||||
/obj/item/clothing/head/soft/dropped(mob/user)
|
||||
icon_state = "[item_color]soft"
|
||||
flipped = FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/soft/verb/flipcap()
|
||||
set category = "Object"
|
||||
|
||||
@@ -247,6 +247,30 @@
|
||||
/obj/item/clothing/mask/bandana/attack_self(mob/user)
|
||||
adjustmask(user)
|
||||
|
||||
/obj/item/clothing/mask/bandana/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if((C.get_item_by_slot(SLOT_HEAD == src)) || (C.get_item_by_slot(SLOT_WEAR_MASK) == src))
|
||||
to_chat(user, "<span class='warning'>You can't tie [src] while wearing it!</span>")
|
||||
return
|
||||
if(slot_flags & ITEM_SLOT_HEAD)
|
||||
to_chat(user, "<span class='warning'>You must undo [src] before you can tie it into a neckerchief!</span>")
|
||||
else
|
||||
if(user.is_holding(src))
|
||||
var/obj/item/clothing/neck/neckerchief/nk = new(src)
|
||||
nk.name = "[name] neckerchief"
|
||||
nk.desc = "[desc] It's tied up like a neckerchief."
|
||||
nk.icon_state = icon_state
|
||||
nk.sourceBandanaType = src.type
|
||||
var/currentHandIndex = user.get_held_index_of_item(src)
|
||||
user.transferItemToLoc(src, null)
|
||||
user.put_in_hand(nk, currentHandIndex)
|
||||
user.visible_message("<span class='notice'>You tie [src] up like a neckerchief.</span>", "<span class='notice'>[user] ties [src] up like a neckerchief.</span>")
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You must be holding [src] in order to tie it!")
|
||||
|
||||
/obj/item/clothing/mask/bandana/red
|
||||
name = "red bandana"
|
||||
desc = "A fine red bandana with nanotech lining."
|
||||
|
||||
@@ -291,3 +291,36 @@
|
||||
icon = 'icons/obj/clothing/neck.dmi'
|
||||
icon_state = "bling"
|
||||
item_color = "bling"
|
||||
|
||||
//////////////////////////////////
|
||||
//VERY SUPER BADASS NECKERCHIEFS//
|
||||
//////////////////////////////////
|
||||
|
||||
obj/item/clothing/neck/neckerchief
|
||||
icon = 'icons/obj/clothing/masks.dmi' //In order to reuse the bandana sprite
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/sourceBandanaType
|
||||
|
||||
/obj/item/clothing/neck/neckerchief/worn_overlays(isinhands)
|
||||
. = ..()
|
||||
if(!isinhands)
|
||||
var/mutable_appearance/realOverlay = mutable_appearance('icons/mob/mask.dmi', icon_state)
|
||||
realOverlay.pixel_y = -3
|
||||
. += realOverlay
|
||||
|
||||
/obj/item/clothing/neck/neckerchief/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.get_item_by_slot(SLOT_NECK) == src)
|
||||
to_chat(user, "<span class='warning'>You can't untie [src] while wearing it!</span>")
|
||||
return
|
||||
if(user.is_holding(src))
|
||||
var/obj/item/clothing/mask/bandana/newBand = new sourceBandanaType(user)
|
||||
var/currentHandIndex = user.get_held_index_of_item(src)
|
||||
var/oldName = src.name
|
||||
qdel(src)
|
||||
user.put_in_hand(newBand, currentHandIndex)
|
||||
user.visible_message("You untie [oldName] back into a [newBand.name]", "[user] unties [oldName] back into a [newBand.name]")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You must be holding [src] in order to untie it!")
|
||||
|
||||
@@ -8,16 +8,11 @@
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/obj/item/clothing/suit/space/chronos/suit = null
|
||||
|
||||
/obj/item/clothing/head/helmet/space/chronos/dropped()
|
||||
/obj/item/clothing/head/helmet/space/chronos/dropped(mob/user)
|
||||
if(suit)
|
||||
suit.deactivate(1, 1)
|
||||
..()
|
||||
|
||||
/obj/item/clothing/head/helmet/space/chronos/Destroy()
|
||||
dropped()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/clothing/suit/space/chronos
|
||||
name = "Chronosuit"
|
||||
desc = "An advanced spacesuit equipped with time-bluespace teleportation and anti-compression technology."
|
||||
@@ -57,15 +52,11 @@
|
||||
else
|
||||
deactivate()
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/dropped()
|
||||
/obj/item/clothing/suit/space/chronos/dropped(mob/user)
|
||||
if(activated)
|
||||
deactivate()
|
||||
..()
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/Destroy()
|
||||
dropped()
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/emp_act(severity)
|
||||
. = ..()
|
||||
if(. & EMP_PROTECT_SELF)
|
||||
|
||||
@@ -805,7 +805,8 @@
|
||||
. += "<span class='boldnotice'>Its maintainence panel is [maint_panel ? "OPEN" : "CLOSED"]</span>"
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/flightsuit/Destroy()
|
||||
dropped()
|
||||
if(ismob(loc))
|
||||
dropped(loc)
|
||||
QDEL_NULL(pack)
|
||||
QDEL_NULL(shoes)
|
||||
return ..()
|
||||
@@ -834,7 +835,7 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/flightsuit/dropped()
|
||||
/obj/item/clothing/suit/space/hardsuit/flightsuit/dropped(mob/the_user)
|
||||
if(deployedpack)
|
||||
retract_flightpack(TRUE)
|
||||
if(deployedshoes)
|
||||
|
||||
@@ -707,7 +707,7 @@
|
||||
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move)
|
||||
listeningTo = user
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/ancient/dropped()
|
||||
/obj/item/clothing/suit/space/hardsuit/ancient/dropped(mob/user)
|
||||
. = ..()
|
||||
if(listeningTo)
|
||||
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/obj/item/clothing/suit/hooded/dropped()
|
||||
/obj/item/clothing/suit/hooded/dropped(mob/user)
|
||||
..()
|
||||
RemoveHood()
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
suit = null
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/hooded/dropped()
|
||||
/obj/item/clothing/head/hooded/dropped(mob/user)
|
||||
..()
|
||||
if(suit)
|
||||
suit.RemoveHood()
|
||||
@@ -174,7 +174,7 @@
|
||||
else
|
||||
helmet.forceMove(src)
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/dropped()
|
||||
/obj/item/clothing/suit/space/hardsuit/dropped(mob/user)
|
||||
..()
|
||||
RemoveHelmet()
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
var/datum/disease/dnaspread/DS = D
|
||||
DS.strain_data["name"] = H.real_name
|
||||
DS.strain_data["UI"] = H.dna.uni_identity
|
||||
DS.strain_data["SE"] = H.dna.struc_enzymes
|
||||
DS.strain_data["SE"] = H.dna.mutation_index
|
||||
else
|
||||
D = new virus_type()
|
||||
else
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
weight = 2
|
||||
min_players = 15
|
||||
earliest_start = 30 MINUTES
|
||||
gamemode_blacklist = list("dynamic")
|
||||
|
||||
/datum/round_event/portal_storm/syndicate_shocktroop
|
||||
boss_types = list(/mob/living/simple_animal/hostile/syndicate/melee/space/stormtrooper = 2)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
max_occurrences = 3
|
||||
weight = 2
|
||||
min_players = 2
|
||||
gamemode_blacklist = list("dynamic")
|
||||
|
||||
|
||||
/datum/round_event/wormholes
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
else if(!operating)
|
||||
QDEL_NULL(current)
|
||||
|
||||
/obj/item/multitool/field_debug/dropped()
|
||||
/obj/item/multitool/field_debug/dropped(mob/user)
|
||||
. = ..()
|
||||
if(listeningTo)
|
||||
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
spawn(30)
|
||||
if(!QDELETED(src))
|
||||
var/mob/living/simple_animal/banana_spider/S = new /mob/living/simple_animal/banana_spider(get_turf(src.loc))
|
||||
S.speed += round(10 / seed.potency)
|
||||
S.speed += round(10 / max(seed.potency, 1), 1)
|
||||
S.visible_message("<span class='notice'>The banana spider chitters as it stretches its legs.</span>")
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -402,11 +402,22 @@
|
||||
power_draw_per_use = 40
|
||||
ext_cooldown = 1
|
||||
cooldown_per_use = 10
|
||||
var/list/mtypes = list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/uranium, /datum/material/plasma, /datum/material/bluespace, /datum/material/bananium, /datum/material/titanium, /datum/material/plastic)
|
||||
var/static/list/mtypes = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/silver,
|
||||
/datum/material/gold,
|
||||
/datum/material/diamond,
|
||||
/datum/material/uranium,
|
||||
/datum/material/plasma,
|
||||
/datum/material/bluespace,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/plastic
|
||||
)
|
||||
|
||||
/obj/item/integrated_circuit/manipulation/matman/Initialize()
|
||||
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container,
|
||||
mtypes, 100000, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
/obj/item/integrated_circuit/manipulation/matman/ComponentInitialize()
|
||||
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, mtypes, 100000, FALSE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
|
||||
materials.precise_insertion = TRUE
|
||||
.=..()
|
||||
|
||||
|
||||
@@ -32,4 +32,5 @@
|
||||
backpack = /obj/item/storage/backpack/genetics
|
||||
satchel = /obj/item/storage/backpack/satchel/gen
|
||||
duffelbag = /obj/item/storage/backpack/duffelbag/med
|
||||
l_pocket = /obj/item/sequence_scanner
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
|
||||
if(target_type && !istype(A,target_type))
|
||||
continue
|
||||
var/cargs = build_args()
|
||||
A.AddComponent(arglist(cargs))
|
||||
A._AddComponent(cargs)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/datum/minimap
|
||||
var/name
|
||||
var/icon/map_icon
|
||||
var/icon/meta_icon
|
||||
var/icon/overlay_icon
|
||||
var/list/color_area_names = list()
|
||||
var/minx
|
||||
var/maxx
|
||||
var/miny
|
||||
var/maxy
|
||||
var/z_level
|
||||
var/id = 0
|
||||
var/static/next_id = 0
|
||||
|
||||
/datum/minimap/New(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy, name)
|
||||
src.name = name
|
||||
id = ++next_id
|
||||
z_level = z
|
||||
|
||||
var/crop_x1 = x2
|
||||
var/crop_x2 = x1
|
||||
var/crop_y1 = y2
|
||||
var/crop_y2 = y1
|
||||
|
||||
// do the generating
|
||||
map_icon = new('html/blank.png')
|
||||
meta_icon = new('html/blank.png')
|
||||
map_icon.Scale(x2-x1+1, y2-y1+1) // arrays start at 1
|
||||
meta_icon.Scale(x2-x1+1, y2-y1+1)
|
||||
var/list/area_to_color = list()
|
||||
for(var/turf/T in block(locate(x1,y1,z),locate(x2,y2,z)))
|
||||
var/area/A = T.loc
|
||||
var/img_x = T.x - x1 + 1 // arrays start at 1
|
||||
var/img_y = T.y - y1 + 1
|
||||
if(!istype(A, /area/space) || istype(T, /turf/closed/wall))
|
||||
crop_x1 = min(crop_x1, T.x)
|
||||
crop_x2 = max(crop_x2, T.x)
|
||||
crop_y1 = min(crop_y1, T.y)
|
||||
crop_y2 = max(crop_y2, T.y)
|
||||
var/meta_color = area_to_color[A]
|
||||
if(!meta_color)
|
||||
meta_color = rgb(rand(0,255),rand(0,255),rand(0,255)) // technically conflicts could happen but it's like very unlikely and it's not that big of a deal if one happens
|
||||
area_to_color[A] = meta_color
|
||||
color_area_names[meta_color] = A.name
|
||||
meta_icon.DrawBox(meta_color, img_x, img_y)
|
||||
if(istype(T, /turf/closed/wall))
|
||||
map_icon.DrawBox("#000000", img_x, img_y)
|
||||
else if(!istype(A, /area/space))
|
||||
var/color = A.minimap_color || "#FF00FF"
|
||||
if(locate(/obj/machinery/power/solar) in T)
|
||||
color = "#02026a"
|
||||
if((locate(/obj/effect/spawner/structure/window) in T) || (locate(/obj/structure/grille) in T))
|
||||
color = BlendRGB(color, "#000000", 0.5)
|
||||
map_icon.DrawBox(color, img_x, img_y)
|
||||
map_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
|
||||
meta_icon.Crop(crop_x1, crop_y1, crop_x2, crop_y2)
|
||||
minx = crop_x1
|
||||
maxx = crop_x2
|
||||
miny = crop_y1
|
||||
maxy = crop_y2
|
||||
overlay_icon = new(map_icon)
|
||||
overlay_icon.Scale(16, 16)
|
||||
|
||||
/datum/minimap/proc/send(mob/user)
|
||||
register_asset("minimap-[id].png", map_icon)
|
||||
register_asset("minimap-[id]-meta.png", meta_icon)
|
||||
send_asset_list(user, list("minimap-[id].png" = map_icon, "minimap-[id]-meta.png" = meta_icon), verify=FALSE)
|
||||
|
||||
/datum/minimap_group
|
||||
var/list/minimaps
|
||||
var/static/next_id = 0
|
||||
var/id
|
||||
var/name
|
||||
|
||||
/datum/minimap_group/New(list/maps, name)
|
||||
id = ++next_id
|
||||
src.name = name
|
||||
minimaps = maps || list()
|
||||
|
||||
/datum/minimap_group/proc/show(mob/user)
|
||||
if(!length(minimaps))
|
||||
to_chat(user, "<span class='boldwarning'>ERROR: Attempted to access an empty datum/minimap_group. This should probably not happen.</span>")
|
||||
return
|
||||
var/list/datas = list()
|
||||
var/list/info = list()
|
||||
var/datum/minimap/first_map = minimaps[1]
|
||||
for(var/i in 1 to length(minimaps))
|
||||
var/datum/minimap/M = minimaps[i]
|
||||
M.send(user)
|
||||
info += "<img src='minimap-[M.id].png' id='map-[i]'><img src='minimap-[M.id]-meta.png' style='display: none' id='map-[i]-meta'><div id='label-[i]'></div>"
|
||||
datas += json_encode(M.color_area_names);
|
||||
info = info.Join()
|
||||
|
||||
var/html = {"
|
||||
<!DOCTYPE html>
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<script>
|
||||
function hexify(num) {
|
||||
if(!num) num = 0;
|
||||
num = num.toString(16);
|
||||
if(num.length == 1) num = "0" + num;
|
||||
return num;
|
||||
}
|
||||
window.onload = function() {
|
||||
var datas = \[[jointext(datas, ",")]]
|
||||
if(window.HTMLCanvasElement) {
|
||||
for(var i = 0; i < [minimaps.len]; i++) {
|
||||
(function() {
|
||||
var data = datas\[i];
|
||||
var img = document.getElementById("map-" + (i+1));
|
||||
if(!img) return;
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = img.width * 2;
|
||||
canvas.height = img.height * 2;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.msImageSmoothingEnabled = false;
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
img.parentNode.replaceChild(canvas, img);
|
||||
ctx = document.createElement("canvas").getContext('2d');
|
||||
ctx.canvas.width = img.width;
|
||||
ctx.canvas.height = img.height;
|
||||
ctx.drawImage(document.getElementById("map-" + (i+1) + "-meta"), 0, 0);
|
||||
var imagedata = ctx.getImageData(0, 0, img.width, img.height);
|
||||
var label = document.getElementById("label-" + (i+1));
|
||||
canvas.onmousemove = function(e) {
|
||||
var rect = canvas.getBoundingClientRect();
|
||||
var x = Math.floor(e.offsetX * img.width / rect.width);
|
||||
var y = Math.floor(e.offsetY * img.height / rect.height);
|
||||
var color_idx = x * 4 + (y * 4 * imagedata.width);
|
||||
var color = "#" + hexify(imagedata.data\[color_idx]) + hexify(imagedata.data\[color_idx+1]) + hexify(imagedata.data\[color_idx+2]);
|
||||
label.textContent = data\[color];
|
||||
canvas.title = data\[color];
|
||||
}
|
||||
canvas.onmouseout = function(e) {
|
||||
label.textContent = "";
|
||||
canvas.title = "";
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<STYLE>
|
||||
img, canvas {
|
||||
width: 100%
|
||||
}
|
||||
</STYLE>
|
||||
<TITLE>[name]</TITLE>
|
||||
</HEAD>
|
||||
<BODY>[info]</BODY>
|
||||
</HTML>"}
|
||||
|
||||
user << browse(html, "window=minimap_[id];size=768x[round(768 / first_map.map_icon.Width() * first_map.map_icon.Height() + 50)]")
|
||||
@@ -463,30 +463,45 @@
|
||||
if(cooldown < world.time)
|
||||
SSblackbox.record_feedback("amount", "immortality_talisman_uses", 1)
|
||||
cooldown = world.time + 600
|
||||
user.visible_message("<span class='danger'>[user] vanishes from reality, leaving a hole in [user.p_their()] place!</span>")
|
||||
var/obj/effect/immortality_talisman/Z = new(get_turf(src.loc))
|
||||
Z.name = "hole in reality"
|
||||
Z.desc = "It's shaped an awful lot like [user.name]."
|
||||
Z.setDir(user.dir)
|
||||
user.forceMove(Z)
|
||||
user.notransform = 1
|
||||
user.status_flags |= GODMODE
|
||||
addtimer(CALLBACK(src, .proc/return_to_reality, user, Z), 100)
|
||||
new /obj/effect/immortality_talisman(get_turf(user), user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] is not ready yet!</span>")
|
||||
|
||||
/obj/item/immortality_talisman/proc/return_to_reality(mob/user, obj/effect/immortality_talisman/Z)
|
||||
user.status_flags &= ~GODMODE
|
||||
user.notransform = 0
|
||||
user.forceMove(get_turf(Z))
|
||||
user.visible_message("<span class='danger'>[user] pops back into reality!</span>")
|
||||
Z.can_destroy = TRUE
|
||||
qdel(Z)
|
||||
|
||||
/obj/effect/immortality_talisman
|
||||
name = "hole in reality"
|
||||
desc = "It's shaped an awful lot like a person."
|
||||
icon_state = "blank"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
var/can_destroy = FALSE
|
||||
var/vanish_description = "vanishes from reality"
|
||||
var/can_destroy = TRUE
|
||||
|
||||
/obj/effect/immortality_talisman/Initialize(mapload, mob/new_user)
|
||||
. = ..()
|
||||
if(new_user)
|
||||
vanish(new_user)
|
||||
|
||||
/obj/effect/immortality_talisman/proc/vanish(mob/user)
|
||||
user.visible_message("<span class='danger'>[user] [vanish_description], leaving a hole in [user.p_their()] place!</span>")
|
||||
|
||||
desc = "It's shaped an awful lot like [user.name]."
|
||||
setDir(user.dir)
|
||||
|
||||
user.forceMove(src)
|
||||
user.notransform = TRUE
|
||||
user.status_flags |= GODMODE
|
||||
|
||||
can_destroy = FALSE
|
||||
|
||||
addtimer(CALLBACK(src, .proc/unvanish, user), 10 SECONDS)
|
||||
|
||||
/obj/effect/immortality_talisman/proc/unvanish(mob/user)
|
||||
user.status_flags &= ~GODMODE
|
||||
user.notransform = FALSE
|
||||
user.forceMove(get_turf(src))
|
||||
|
||||
user.visible_message("<span class='danger'>[user] pops back into reality!</span>")
|
||||
can_destroy = TRUE
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/immortality_talisman/attackby()
|
||||
return
|
||||
@@ -503,6 +518,9 @@
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/effect/immortality_talisman/void
|
||||
vanish_description = "is dragged into the void"
|
||||
|
||||
|
||||
//Shared Bag
|
||||
|
||||
@@ -957,7 +975,7 @@
|
||||
if(1)
|
||||
new /obj/item/mayhem(src)
|
||||
if(2)
|
||||
new /obj/item/blood_contract(src)
|
||||
new /obj/item/gun/ballistic/revolver/doublebarrel/super(src)
|
||||
if(3)
|
||||
new /obj/item/gun/magic/staff/spellblade(src)
|
||||
|
||||
@@ -1028,6 +1046,17 @@
|
||||
log_combat(user, L, "took out a blood contract on", src)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun/ballistic/revolver/doublebarrel/super
|
||||
name = "super combat shotgun"
|
||||
desc = "From the belly of the beast - or rather, demon. Twice as lethal as a less-than-super shotgun, but a tad bulkier."
|
||||
icon_state = "heckgun"
|
||||
slot_flags = null
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/dual/heck
|
||||
burst_size = 2
|
||||
burst_shot_delay = 0
|
||||
unique_reskin = null
|
||||
sawn_off = TRUE
|
||||
|
||||
//Colossus
|
||||
/obj/structure/closet/crate/necropolis/colossus
|
||||
name = "colossus chest"
|
||||
|
||||
@@ -15,14 +15,20 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
|
||||
/obj/machinery/ore_silo/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/material_container,
|
||||
list(/datum/material/iron, /datum/material/glass, /datum/material/silver, /datum/material/gold, /datum/material/diamond, /datum/material/plasma, /datum/material/uranium, /datum/material/bananium, /datum/material/titanium, /datum/material/bluespace, /datum/material/plastic),
|
||||
INFINITY,
|
||||
FALSE,
|
||||
/obj/item/stack,
|
||||
null,
|
||||
null,
|
||||
TRUE)
|
||||
var/static/list/materials_list = list(
|
||||
/datum/material/iron,
|
||||
/datum/material/glass,
|
||||
/datum/material/silver,
|
||||
/datum/material/gold,
|
||||
/datum/material/diamond,
|
||||
/datum/material/plasma,
|
||||
/datum/material/uranium,
|
||||
/datum/material/bananium,
|
||||
/datum/material/titanium,
|
||||
/datum/material/bluespace,
|
||||
/datum/material/plastic,
|
||||
)
|
||||
AddComponent(/datum/component/material_container, materials_list, INFINITY, allowed_types=/obj/item/stack, _disable_attackby=TRUE)
|
||||
if (!GLOB.ore_silo_default && mapload && is_station_level(z))
|
||||
GLOB.ore_silo_default = src
|
||||
|
||||
|
||||
@@ -292,9 +292,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
|
||||
if(world.time < roundstart_quit_limit)
|
||||
penalty += roundstart_quit_limit - world.time
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
|
||||
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE, (stat == DEAD)? penalty : 0, (stat == DEAD)? TRUE : FALSE) & COMPONENT_BLOCK_GHOSTING)
|
||||
return
|
||||
@@ -327,9 +328,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
|
||||
if(world.time < roundstart_quit_limit)
|
||||
penalty += roundstart_quit_limit - world.time
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
|
||||
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
|
||||
if(response != "Ghost")
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/brain/update_mobility()
|
||||
return ((mobility_flags = (in_contents_of(/obj/mecha)? MOBILITY_FLAGS_DEFAULT : NONE)))
|
||||
return ((mobility_flags = (container?.in_contents_of(/obj/mecha)? MOBILITY_FLAGS_DEFAULT : NONE)))
|
||||
|
||||
/mob/living/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
|
||||
return
|
||||
|
||||
@@ -28,6 +28,34 @@ GLOBAL_VAR(posibrain_notify_cooldown)
|
||||
var/list/possible_names //If you leave this blank, it will use the global posibrain names
|
||||
var/picked_name
|
||||
|
||||
/obj/item/mmi/posibrain/Initialize()
|
||||
. = ..()
|
||||
brainmob = new(src)
|
||||
var/new_name
|
||||
if(!LAZYLEN(possible_names))
|
||||
new_name = pick(GLOB.posibrain_names)
|
||||
else
|
||||
new_name = pick(possible_names)
|
||||
brainmob.name = "[new_name]-[rand(100, 999)]"
|
||||
brainmob.real_name = brainmob.name
|
||||
brainmob.forceMove(src)
|
||||
brainmob.container = src
|
||||
if(autoping)
|
||||
ping_ghosts("created", TRUE)
|
||||
GLOB.poi_list |= src
|
||||
LAZYADD(GLOB.mob_spawners[name], src)
|
||||
|
||||
/obj/item/mmi/posibrain/Destroy()
|
||||
latejoin_remove()
|
||||
return ..()
|
||||
|
||||
/obj/item/mmi/posibrain/proc/latejoin_remove()
|
||||
GLOB.poi_list -= src
|
||||
var/init_name = initial(name)
|
||||
LAZYREMOVE(GLOB.mob_spawners[init_name], src)
|
||||
if(!LAZYLEN(GLOB.mob_spawners[init_name]))
|
||||
GLOB.mob_spawners -= init_name
|
||||
|
||||
/obj/item/mmi/posibrain/Topic(href, href_list)
|
||||
if(href_list["activate"])
|
||||
var/mob/dead/observer/ghost = usr
|
||||
@@ -97,15 +125,6 @@ GLOBAL_VAR(posibrain_notify_cooldown)
|
||||
transfer_personality(user)
|
||||
latejoin_remove()
|
||||
|
||||
/obj/item/mmi/posibrain/Destroy()
|
||||
latejoin_remove()
|
||||
return ..()
|
||||
|
||||
/obj/item/mmi/posibrain/proc/latejoin_remove()
|
||||
GLOB.poi_list -= src
|
||||
LAZYREMOVE(GLOB.mob_spawners[name], src)
|
||||
if(!LAZYLEN(GLOB.mob_spawners[name]))
|
||||
GLOB.mob_spawners -= name
|
||||
|
||||
/obj/item/mmi/posibrain/transfer_identity(mob/living/carbon/C)
|
||||
name = "[initial(name)] ([C])"
|
||||
@@ -163,23 +182,6 @@ GLOBAL_VAR(posibrain_notify_cooldown)
|
||||
|
||||
. += msg
|
||||
|
||||
/obj/item/mmi/posibrain/Initialize()
|
||||
. = ..()
|
||||
brainmob = new(src)
|
||||
var/new_name
|
||||
if(!LAZYLEN(possible_names))
|
||||
new_name = pick(GLOB.posibrain_names)
|
||||
else
|
||||
new_name = pick(possible_names)
|
||||
brainmob.name = "[new_name]-[rand(100, 999)]"
|
||||
brainmob.real_name = brainmob.name
|
||||
brainmob.forceMove(src)
|
||||
brainmob.container = src
|
||||
if(autoping)
|
||||
ping_ghosts("created", TRUE)
|
||||
GLOB.poi_list |= src
|
||||
LAZYADD(GLOB.mob_spawners[name], src)
|
||||
|
||||
/obj/item/mmi/posibrain/attackby(obj/item/O, mob/user)
|
||||
return
|
||||
|
||||
|
||||
@@ -632,6 +632,13 @@
|
||||
if(M.name == XRAY)
|
||||
sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
see_in_dark = max(see_in_dark, 8)
|
||||
if(HAS_TRAIT(src, TRAIT_THERMAL_VISION))
|
||||
sight |= (SEE_MOBS)
|
||||
lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE)
|
||||
|
||||
if(HAS_TRAIT(src, TRAIT_XRAY_VISION))
|
||||
sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
see_in_dark = max(see_in_dark, 8)
|
||||
|
||||
if(see_override)
|
||||
see_invisible = see_override
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
L.embedded_objects |= I
|
||||
I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
|
||||
I.forceMove(src)
|
||||
I.embedded()
|
||||
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
|
||||
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
@@ -104,7 +105,8 @@
|
||||
var/basebloodychance = affecting.brute_dam + totitemdamage
|
||||
if(prob(basebloodychance))
|
||||
I.add_mob_blood(src)
|
||||
bleed(totitemdamage)
|
||||
var/turf/location = get_turf(src)
|
||||
add_splatter_floor(location)
|
||||
if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(src)
|
||||
|
||||
@@ -262,11 +264,11 @@
|
||||
jitteriness += 1000 //High numbers for violent convulsions
|
||||
do_jitter_animation(jitteriness)
|
||||
stuttering += 2
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
|
||||
Stun(40)
|
||||
spawn(20)
|
||||
jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && (flags & SHOCK_NOSTUN))
|
||||
if((!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN))
|
||||
DefaultCombatKnockdown(60)
|
||||
return shock_damage
|
||||
|
||||
|
||||
@@ -45,31 +45,11 @@
|
||||
if(spec_return)
|
||||
return spec_return
|
||||
|
||||
if(mind)
|
||||
if (mind.martial_art && mind.martial_art.dodge_chance)
|
||||
if(!lying && dna && !dna.check_mutation(HULK))
|
||||
if(prob(mind.martial_art.dodge_chance))
|
||||
var/static/dodgemessages = list("dodges under",0,-4,"dodges to the right of",-4,0,"dodges to the left of",4,0,"jumps over",0,4)
|
||||
var/pick = pick(1,4,7,10)
|
||||
var/oldx = pixel_x
|
||||
var/oldy = pixel_y
|
||||
animate(src,pixel_x = pixel_x + dodgemessages[pick+1],pixel_y = pixel_y + dodgemessages[pick+2],time=3)
|
||||
animate(src,pixel_x = oldx,pixel_y = oldy,time=2)
|
||||
visible_message("<span class='danger'>[src] [dodgemessages[pick]] the projectile!</span>", "<span class='userdanger'>You dodge the projectile!</span>")
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
|
||||
if(prob(mind.martial_art.deflection_chance))
|
||||
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
|
||||
if(mind.martial_art.deflection_chance >= 100) //if they can NEVER be hit, lets clue sec in ;)
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] deflects the projectile!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
|
||||
if(mind.martial_art.reroute_deflection)
|
||||
P.firer = src
|
||||
P.setAngle(rand(0, 360))//SHING
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
|
||||
if(mind) //martial art stuff
|
||||
if(mind.martial_art && mind.martial_art.can_use(src)) //Some martial arts users can deflect projectiles!
|
||||
var/martial_art_result = mind.martial_art.on_projectile_hit(src, P, def_zone)
|
||||
if(!(martial_art_result == BULLET_ACT_HIT))
|
||||
return martial_art_result
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/check_reflect(def_zone)
|
||||
|
||||
@@ -316,6 +316,7 @@
|
||||
BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier)
|
||||
BP.embedded_objects -= I
|
||||
I.forceMove(drop_location())
|
||||
I.unembedded()
|
||||
visible_message("<span class='danger'>[I] falls out of [name]'s [BP.name]!</span>","<span class='userdanger'>[I] falls out of your [BP.name]!</span>")
|
||||
if(!has_embedded_objects())
|
||||
clear_alert("embeddedobject")
|
||||
|
||||
@@ -69,6 +69,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/siemens_coeff = 1 //base electrocution coefficient
|
||||
var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded?
|
||||
var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
|
||||
var/inert_mutation = DWARFISM
|
||||
var/list/special_step_sounds //Sounds to override barefeet walkng
|
||||
var/grab_sound //Special sound for grabbing
|
||||
var/datum/outfit/outfit_important_for_life // A path to an outfit that is important for species life e.g. plasmaman outfit
|
||||
@@ -356,6 +357,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
else
|
||||
C.type_of_meat = initial(meat)
|
||||
|
||||
//If their inert mutation is not the same, swap it out
|
||||
if((inert_mutation != new_species.inert_mutation) && LAZYLEN(C.dna.mutation_index) && (inert_mutation in C.dna.mutation_index))
|
||||
C.dna.remove_mutation(inert_mutation)
|
||||
//keep it at the right spot, so we can't have people taking shortcuts
|
||||
var/location = C.dna.mutation_index.Find(inert_mutation)
|
||||
C.dna.mutation_index[location] = new_species.inert_mutation
|
||||
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
|
||||
|
||||
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
|
||||
|
||||
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
|
||||
@@ -1394,7 +1403,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(radiation > RAD_MOB_MUTATE)
|
||||
if(prob(1))
|
||||
to_chat(H, "<span class='danger'>You mutate!</span>")
|
||||
H.randmutb()
|
||||
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
|
||||
H.emote("gasp")
|
||||
H.domutcheck()
|
||||
|
||||
@@ -1710,7 +1719,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
bloody = 1
|
||||
var/turf/location = H.loc
|
||||
if(istype(location))
|
||||
H.bleed(totitemdamage)
|
||||
H.add_splatter_floor(location)
|
||||
if(get_dist(user, H) <= 1) //people with TK won't get smeared with blood
|
||||
user.add_mob_blood(H)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
exotic_bloodtype = "L"
|
||||
disliked_food = GRAIN | DAIRY
|
||||
liked_food = GROSS | MEAT
|
||||
inert_mutation = FIREBREATH
|
||||
|
||||
/datum/species/lizard/after_equip_job(datum/job/J, mob/living/carbon/human/H)
|
||||
H.grant_language(/datum/language/draconic)
|
||||
|
||||
@@ -61,9 +61,9 @@
|
||||
H.DefaultCombatKnockdown(100)
|
||||
H.visible_message("<span class='warning'>[H] writhes in pain as [H.p_their()] vacuoles boil.</span>", "<span class='userdanger'>You writhe in pain as your vacuoles boil!</span>", "<span class='italics'>You hear the crunching of leaves.</span>")
|
||||
if(prob(80))
|
||||
H.randmutb()
|
||||
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
|
||||
else
|
||||
H.randmutg()
|
||||
H.easy_randmut(POSITIVE)
|
||||
H.domutcheck()
|
||||
else
|
||||
H.adjustFireLoss(rand(5,15))
|
||||
|
||||
@@ -122,9 +122,9 @@
|
||||
update_inv_wear_mask()
|
||||
|
||||
/mob/living/carbon/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
|
||||
if(C.tint || initial(C.tint))
|
||||
if(isclothing(C) && (C.tint || initial(C.tint)))
|
||||
update_tint()
|
||||
update_inv_wear_mask()
|
||||
return ..()
|
||||
|
||||
//handle stuff to update when a mob equips/unequips a headgear.
|
||||
/mob/living/carbon/proc/head_update(obj/item/I, forced)
|
||||
|
||||
@@ -427,7 +427,6 @@
|
||||
|
||||
/mob/living/carbon/handle_mutations_and_radiation()
|
||||
if(dna && dna.temporary_mutations.len)
|
||||
var/datum/mutation/human/HM
|
||||
for(var/mut in dna.temporary_mutations)
|
||||
if(dna.temporary_mutations[mut] < world.time)
|
||||
if(mut == UI_CHANGED)
|
||||
@@ -450,9 +449,9 @@
|
||||
dna.previous.Remove("blood_type")
|
||||
dna.temporary_mutations.Remove(mut)
|
||||
continue
|
||||
HM = GLOB.mutations_list[mut]
|
||||
HM.force_lose(src)
|
||||
dna.temporary_mutations.Remove(mut)
|
||||
for(var/datum/mutation/human/HM in dna.mutations)
|
||||
if(HM && HM.timed)
|
||||
dna.remove_mutation(HM.type)
|
||||
|
||||
radiation -= min(radiation, RAD_LOSS_PER_TICK)
|
||||
if(radiation > RAD_MOB_SAFE)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
if(radiation > RAD_MOB_MUTATE)
|
||||
if(prob(1))
|
||||
to_chat(src, "<span class='danger'>You mutate!</span>")
|
||||
randmutb()
|
||||
easy_randmut(NEGATIVE+MINOR_NEGATIVE)
|
||||
emote("gasp")
|
||||
domutcheck()
|
||||
if(radiation > RAD_MOB_VOMIT && prob(RAD_MOB_VOMIT_PROB))
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
/mob/living/carbon/monkey/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/mob_holder, "monkey", null, null, null, ITEM_SLOT_HEAD)
|
||||
AddElement(/datum/element/mob_holder, worn_state = "monkey", inv_slots = ITEM_SLOT_HEAD)
|
||||
|
||||
|
||||
/mob/living/carbon/monkey/Destroy()
|
||||
|
||||
@@ -97,8 +97,7 @@
|
||||
resist_a_rest(FALSE, TRUE)
|
||||
update_icon()
|
||||
if(possible_chassis[old_chassis])
|
||||
var/datum/element/mob_holder/M = SSdcs.GetElement(/datum/element/mob_holder, old_chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
M.Detach(src)
|
||||
RemoveElement(/datum/element/mob_holder, old_chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
if(possible_chassis[chassis])
|
||||
AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
|
||||
to_chat(src, "<span class='boldnotice'>You switch your holochassis projection composite to [chassis]</span>")
|
||||
|
||||
@@ -363,10 +363,8 @@
|
||||
icon_dead = "old_corgi_dead"
|
||||
desc = "At a ripe old age of [record_age] Ian's not as spry as he used to be, but he'll always be the HoP's beloved corgi." //RIP
|
||||
turns_per_move = 20
|
||||
var/datum/element/mob_holder/ele = SSdcs.GetElement(/datum/element/mob_holder, held_icon)
|
||||
if(ele)
|
||||
ele.Detach(src)
|
||||
AddElement(/datum/element/mob_holder, "old_corgi")
|
||||
RemoveElement(/datum/element/mob_holder, held_icon)
|
||||
AddElement(/datum/element/mob_holder, "old_corgi")
|
||||
|
||||
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
|
||||
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/lizard/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/mob_holder, "lizard", null, null, null, ITEM_SLOT_HEAD) //you can hold lizards now.
|
||||
AddElement(/datum/element/mob_holder, worn_state = "lizard", inv_slots = ITEM_SLOT_HEAD) //you can hold lizards now.
|
||||
|
||||
/mob/living/simple_animal/hostile/lizard/CanAttack(atom/the_target)//Can we actually attack a possible target?
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/mouse/handle_automated_action()
|
||||
if(isbelly(loc))
|
||||
if(!isturf(loc))
|
||||
return
|
||||
|
||||
if(prob(chew_probability))
|
||||
@@ -76,7 +76,7 @@
|
||||
visible_message("<span class='warning'>[src] chews through the [C]. It's toast!</span>")
|
||||
playsound(src, 'sound/effects/sparks2.ogg', 100, 1)
|
||||
C.deconstruct()
|
||||
death(toast=1)
|
||||
death(toast=TRUE)
|
||||
else
|
||||
C.deconstruct()
|
||||
visible_message("<span class='warning'>[src] chews through the [C].</span>")
|
||||
|
||||
@@ -17,7 +17,7 @@ From these blood pools Bubblegum may summon slaughterlings - weak, low-damage mi
|
||||
When Bubblegum dies, it leaves behind a H.E.C.K. suit+helmet as well as a chest that can contain three things:
|
||||
1. A spellblade that can slice off limbs at range
|
||||
2. A bottle that, when activated, drives everyone nearby into a frenzy
|
||||
3. A contract that marks for death the chosen target
|
||||
3. A super double-barrel shotgun that shoots both shells at the same time.
|
||||
|
||||
Difficulty: Hard
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ Difficulty: Very Hard
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.mind)
|
||||
if(H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
|
||||
if(istype(H.mind.martial_art, /datum/martial_art/the_sleeping_carp) & istype(H.mind.martial_art, /datum/martial_art/the_rising_bass))
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
|
||||
|
||||
@@ -84,10 +84,12 @@
|
||||
pass_flags = PASSTABLE | PASSMOB //they shouldn't get stuck behind hivelords.
|
||||
density = FALSE
|
||||
del_on_death = 1
|
||||
var/swarming = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/swarming) //oh god not the bees
|
||||
if(swarming)
|
||||
AddComponent(/datum/component/swarming) //oh god not the bees
|
||||
addtimer(CALLBACK(src, .proc/death), 100)
|
||||
|
||||
//Legion
|
||||
@@ -184,6 +186,7 @@
|
||||
del_on_death = TRUE
|
||||
stat_attack = UNCONSCIOUS
|
||||
robust_searching = 1
|
||||
swarming = TRUE
|
||||
var/can_infest_dead = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life()
|
||||
|
||||
@@ -19,9 +19,15 @@
|
||||
/mob/proc/set_dizziness(amount)
|
||||
dizziness = max(amount, 0)
|
||||
|
||||
///Blind a mobs eyes by amount
|
||||
/**
|
||||
* Sets a mob's blindness to an amount if it was not above it already, similar to how status effects work
|
||||
*/
|
||||
/mob/proc/blind_eyes(amount)
|
||||
adjust_blindness(amount)
|
||||
var/old_blind = eye_blind || HAS_TRAIT(src, TRAIT_BLIND)
|
||||
eye_blind = max(eye_blind, amount)
|
||||
var/new_blind = eye_blind || HAS_TRAIT(src, TRAIT_BLIND)
|
||||
if(old_blind != new_blind)
|
||||
update_blindness()
|
||||
|
||||
/**
|
||||
* Adjust a mobs blindness by an amount
|
||||
|
||||
@@ -49,9 +49,8 @@
|
||||
O.updateappearance(icon_update=0)
|
||||
|
||||
if(tr_flags & TR_KEEPSE)
|
||||
O.dna.struc_enzymes = dna.struc_enzymes
|
||||
var/datum/mutation/human/race/R = GLOB.mutations_list[RACEMUT]
|
||||
O.dna.struc_enzymes = R.set_se(O.dna.struc_enzymes, on=1)//we don't want to keep the race block inactive
|
||||
O.dna.mutation_index = dna.mutation_index
|
||||
O.dna.set_se(1, GET_INITIALIZED_MUTATION(RACEMUT))
|
||||
|
||||
if(suiciding)
|
||||
O.suiciding = suiciding
|
||||
@@ -208,9 +207,8 @@
|
||||
O.name = O.real_name
|
||||
|
||||
if(tr_flags & TR_KEEPSE)
|
||||
O.dna.struc_enzymes = dna.struc_enzymes
|
||||
var/datum/mutation/human/race/R = GLOB.mutations_list[RACEMUT]
|
||||
O.dna.struc_enzymes = R.set_se(O.dna.struc_enzymes, on=0)//we don't want to keep the race block active
|
||||
O.dna.mutation_index = dna.mutation_index
|
||||
O.dna.set_se(0, GET_INITIALIZED_MUTATION(RACEMUT))
|
||||
O.domutcheck()
|
||||
|
||||
if(suiciding)
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
/obj/item/modular_computer/tablet/syndicate_contract_uplink
|
||||
name = "contractor tablet"
|
||||
icon = 'icons/obj/contractor_tablet.dmi'
|
||||
icon_state = "tablet-red"
|
||||
icon_state = "tablet"
|
||||
icon_state_unpowered = "tablet"
|
||||
icon_state_powered = "tablet"
|
||||
icon_state_menu = "assign"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
|
||||
comp_light_luminosity = 6.3
|
||||
has_variants = FALSE
|
||||
has_variants = FALSE
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
name = "double-barrel shotgun internal magazine"
|
||||
max_ammo = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/dual/heck
|
||||
name = "heckgun internal magazine"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/improvised
|
||||
name = "improvised shotgun internal magazine"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/improvised
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
magazine = AM
|
||||
if(oldmag)
|
||||
to_chat(user, "<span class='notice'>You perform a tactical reload on \the [src], replacing the magazine.</span>")
|
||||
oldmag.dropped()
|
||||
oldmag.forceMove(get_turf(src.loc))
|
||||
oldmag.update_icon()
|
||||
else
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
pump()
|
||||
gun_type = type
|
||||
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/dropped()
|
||||
/obj/item/gun/ballistic/shotgun/boltaction/enchanted/dropped(mob/user)
|
||||
..()
|
||||
guns_left = 0
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/kinetic/premium)
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/premiumka/dropped()
|
||||
/obj/item/gun/energy/kinetic_accelerator/premiumka/dropped(mob/user)
|
||||
. = ..()
|
||||
if(!QDELING(src) && !holds_charge)
|
||||
// Put it on a delay because moving item from slot to hand
|
||||
@@ -137,7 +137,7 @@
|
||||
if(!can_shoot())
|
||||
attempt_reload()
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/dropped()
|
||||
/obj/item/gun/energy/kinetic_accelerator/dropped(mob/user)
|
||||
. = ..()
|
||||
if(!QDELING(src) && !holds_charge)
|
||||
// Put it on a delay because moving item from slot to hand
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
var/mob/current_user = null
|
||||
var/list/obj/effect/projectile/tracer/current_tracers
|
||||
|
||||
var/structure_piercing = 1
|
||||
var/structure_piercing = 0
|
||||
var/structure_bleed_coeff = 0.7
|
||||
var/wall_pierce_amount = 0
|
||||
var/wall_devastate = 0
|
||||
@@ -60,7 +60,7 @@
|
||||
var/impact_structure_damage = 75
|
||||
var/projectile_damage = 40
|
||||
var/projectile_stun = 0
|
||||
var/projectile_setting_pierce = TRUE
|
||||
var/projectile_setting_pierce = FALSE
|
||||
var/delay = 30
|
||||
var/lastfire = 0
|
||||
|
||||
@@ -160,6 +160,9 @@
|
||||
add_overlay(drained_overlay)
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/attack_self(mob/user)
|
||||
if(!structure_piercing)
|
||||
projectile_setting_pierce = FALSE
|
||||
return
|
||||
projectile_setting_pierce = !projectile_setting_pierce
|
||||
to_chat(user, "<span class='boldnotice'>You set \the [src] to [projectile_setting_pierce? "pierce":"impact"] mode.</span>")
|
||||
aiming_beam()
|
||||
@@ -402,7 +405,7 @@
|
||||
/obj/item/ammo_casing/energy/beam_rifle/hitscan
|
||||
projectile_type = /obj/item/projectile/beam/beam_rifle/hitscan
|
||||
select_name = "beam"
|
||||
e_cost = 5000
|
||||
e_cost = 10000
|
||||
fire_sound = 'sound/weapons/beam_sniper.ogg'
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle
|
||||
@@ -557,9 +560,4 @@
|
||||
hitscan_light_color_override = "#99ff99"
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
|
||||
qdel(src)
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
C.IgniteMob()
|
||||
if(C.dna && C.dna.check_mutation(HULK))
|
||||
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
|
||||
else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
|
||||
else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE) && !HAS_TRAIT(C, TRAIT_TASED_RESISTANCE))
|
||||
C.apply_status_effect(strong_tase? STATUS_EFFECT_TASED : STATUS_EFFECT_TASED_WEAK, tase_duration)
|
||||
addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
|
||||
|
||||
|
||||
@@ -16,3 +16,8 @@
|
||||
/obj/item/projectile/temp/hot
|
||||
name = "heat beam"
|
||||
temperature = 400
|
||||
|
||||
/obj/item/projectile/temp/cryo
|
||||
name = "cryo beam"
|
||||
range = 3
|
||||
temperature = -240 // Single slow shot reduces temp greatly
|
||||
@@ -171,9 +171,11 @@
|
||||
/datum/reagent/drug/methamphetamine/on_mob_metabolize(mob/living/L)
|
||||
..()
|
||||
L.ignore_slowdown(type)
|
||||
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
|
||||
|
||||
/datum/reagent/drug/methamphetamine/on_mob_end_metabolize(mob/living/L)
|
||||
L.unignore_slowdown(type)
|
||||
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
|
||||
..()
|
||||
|
||||
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M)
|
||||
|
||||
@@ -218,7 +218,8 @@
|
||||
. = ..()
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/patient = M
|
||||
if(reac_volume >= 5 && HAS_TRAIT_FROM(patient, TRAIT_HUSK, "burn") && patient.getFireLoss() < THRESHOLD_UNHUSK) //One carp yields 12u rezadone.
|
||||
var/vol = reac_volume + M.reagents.get_reagent_amount(/datum/reagent/medicine/rezadone)
|
||||
if(vol >= 5 && HAS_TRAIT_FROM(patient, TRAIT_HUSK, "burn") && patient.getFireLoss() < THRESHOLD_UNHUSK) //One carp yields 12u rezadone.
|
||||
patient.cure_husk("burn")
|
||||
patient.visible_message("<span class='nicegreen'>[patient]'s body rapidly absorbs moisture from the enviroment, taking on a more healthy appearance.")
|
||||
|
||||
@@ -425,7 +426,7 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
|
||||
overdose_threshold = 40
|
||||
value = 6
|
||||
|
||||
/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1)
|
||||
/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
|
||||
if(iscarbon(M))
|
||||
if (M.stat == DEAD)
|
||||
show_message = 0
|
||||
@@ -442,8 +443,9 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
|
||||
if(show_message)
|
||||
to_chat(M, "<span class='danger'>You feel your burns and bruises healing! It stings like hell!</span>")
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
|
||||
var/vol = reac_volume + M.reagents.get_reagent_amount(/datum/reagent/medicine/synthflesh)
|
||||
//Has to be at less than THRESHOLD_UNHUSK burn damage and have 100 synthflesh before unhusking. Corpses dont metabolize.
|
||||
if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && M.reagents.has_reagent(/datum/reagent/medicine/synthflesh, 100))
|
||||
if(HAS_TRAIT_FROM(M, TRAIT_HUSK, "burn") && M.getFireLoss() < THRESHOLD_UNHUSK && (vol > 100))
|
||||
M.cure_husk("burn")
|
||||
M.visible_message("<span class='nicegreen'>Most of [M]'s burnt off or charred flesh has been restored.")
|
||||
..()
|
||||
@@ -957,7 +959,7 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
|
||||
/datum/reagent/medicine/mutadone/on_mob_life(mob/living/carbon/M)
|
||||
M.jitteriness = 0
|
||||
if(M.has_dna())
|
||||
M.dna.remove_all_mutations()
|
||||
M.dna.remove_all_mutations(mutadone = TRUE)
|
||||
if(!QDELETED(M)) //We were a monkey, now a human
|
||||
..()
|
||||
|
||||
@@ -992,9 +994,11 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
|
||||
/datum/reagent/medicine/stimulants/on_mob_metabolize(mob/living/L)
|
||||
..()
|
||||
L.add_movespeed_modifier(type, update=TRUE, priority=100, multiplicative_slowdown=-0.5, blacklisted_movetypes=(FLYING|FLOATING))
|
||||
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
|
||||
|
||||
/datum/reagent/medicine/stimulants/on_mob_end_metabolize(mob/living/L)
|
||||
L.remove_movespeed_modifier(type)
|
||||
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
|
||||
..()
|
||||
|
||||
/datum/reagent/medicine/stimulants/on_mob_life(mob/living/carbon/M)
|
||||
@@ -1299,6 +1303,14 @@ datum/reagent/medicine/styptic_powder/overdose_start(mob/living/M)
|
||||
color = "#918e53"
|
||||
overdose_threshold = 30
|
||||
|
||||
/datum/reagent/medicine/changelingadrenaline/on_mob_metabolize(mob/living/L)
|
||||
..()
|
||||
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
|
||||
|
||||
/datum/reagent/medicine/changelingadrenaline/on_mob_end_metabolize(mob/living/L)
|
||||
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
|
||||
..()
|
||||
|
||||
/datum/reagent/medicine/changelingadrenaline/on_mob_life(mob/living/carbon/M as mob)
|
||||
M.AdjustUnconscious(-20, 0)
|
||||
M.AdjustAllImmobility(-20, 0)
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
if((method==VAPOR && prob(min(33, reac_volume))) || method==INGEST || method==PATCH || method==INJECT)
|
||||
M.randmuti()
|
||||
if(prob(98))
|
||||
M.randmutb()
|
||||
M.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
|
||||
else
|
||||
M.randmutg()
|
||||
M.easy_randmut(POSITIVE)
|
||||
M.updateappearance()
|
||||
M.domutcheck()
|
||||
..()
|
||||
|
||||
@@ -75,6 +75,28 @@
|
||||
for(var/i = 1, i <= multiplier, i++)
|
||||
new /obj/item/stack/sheet/mineral/gold(location)
|
||||
|
||||
/datum/chemical_reaction/uraniumsolidification
|
||||
name = "Solid Uranium"
|
||||
id = "soliduranium"
|
||||
required_reagents = list(/datum/reagent/consumable/frostoil = 5, /datum/reagent/uranium = 20, /datum/reagent/bromine = 1)
|
||||
mob_react = FALSE
|
||||
|
||||
/datum/chemical_reaction/uraniumsolidification/on_reaction(datum/reagents/holder, multiplier)
|
||||
var/location = get_turf(holder.my_atom)
|
||||
for(var/i = 1, i <= multiplier, i++)
|
||||
new /obj/item/stack/sheet/mineral/uranium(location)
|
||||
|
||||
/datum/chemical_reaction/bluespacecrystalifaction
|
||||
name = "Crystal Bluespace"
|
||||
id = "crystalbluespace"
|
||||
required_reagents = list(/datum/reagent/consumable/frostoil = 5, /datum/reagent/bluespace = 20, /datum/reagent/iron = 1)
|
||||
mob_react = FALSE
|
||||
|
||||
/datum/chemical_reaction/bluespacecrystalifaction/on_reaction(datum/reagents/holder, multiplier)
|
||||
var/location = get_turf(holder.my_atom)
|
||||
for(var/i = 1, i <= multiplier, i++)
|
||||
new /obj/item/stack/sheet/bluespace_crystal(location)
|
||||
|
||||
/datum/chemical_reaction/capsaicincondensation
|
||||
name = "Capsaicincondensation"
|
||||
id = /datum/reagent/consumable/condensedcapsaicin
|
||||
|
||||
@@ -28,7 +28,7 @@ Borg Hypospray
|
||||
|
||||
var/list/datum/reagents/reagent_list = list()
|
||||
var/list/reagent_ids = list(/datum/reagent/medicine/dexalin, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/antitoxin,
|
||||
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin)
|
||||
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
|
||||
var/accepts_reagent_upgrades = TRUE //If upgrades can increase number of reagents dispensed.
|
||||
var/list/modes = list() //Basically the inverse of reagent_ids. Instead of having numbers as "keys" and strings as values it has strings as keys and numbers as values.
|
||||
//Used as list for input() in shakers.
|
||||
@@ -164,7 +164,7 @@ Borg Hypospray
|
||||
icon_state = "borghypo_s"
|
||||
charge_cost = 20
|
||||
recharge_time = 2
|
||||
reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/potass_iodide, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
|
||||
reagent_ids = list(/datum/reagent/medicine/syndicate_nanites, /datum/reagent/medicine/prussian_blue, /datum/reagent/medicine/morphine, /datum/reagent/medicine/insulin)
|
||||
bypass_protection = 1
|
||||
accepts_reagent_upgrades = FALSE
|
||||
|
||||
@@ -261,5 +261,5 @@ Borg Shaker
|
||||
/obj/item/reagent_containers/borghypo/epi
|
||||
name = "Stabilizer injector"
|
||||
desc = "An advanced chemical synthesizer and injection system, designed to stabilize patients."
|
||||
reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin)
|
||||
reagent_ids = list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/insulin, /datum/reagent/medicine/potass_iodide)
|
||||
accepts_reagent_upgrades = FALSE
|
||||
|
||||
@@ -162,6 +162,16 @@
|
||||
category = list("Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/genescanner
|
||||
name = "Genetic Sequence Analyzer"
|
||||
desc = "A handy hand-held analyzers for quickly determining mutations and collecting the full sequence."
|
||||
id = "genescanner"
|
||||
build_path = /obj/item/sequence_scanner
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 1000, /datum/material/glass = 500)
|
||||
category = list("Medical Designs")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
|
||||
|
||||
/datum/design/healthanalyzer_advanced
|
||||
name = "Advanced Health Analyzer"
|
||||
desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
return
|
||||
|
||||
var/datum/nanite_cloud_backup/backup = new(src)
|
||||
var/datum/component/nanites/cloud_copy = new(backup)
|
||||
var/datum/component/nanites/cloud_copy = backup.AddComponent(/datum/component/nanites)
|
||||
backup.cloud_id = cloud_id
|
||||
backup.nanites = cloud_copy
|
||||
investigate_log("[key_name(user)] created a new nanite cloud backup with id #[cloud_id]", INVESTIGATE_NANITES)
|
||||
@@ -213,7 +213,7 @@
|
||||
var/datum/component/nanites/nanites = backup.nanites
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = rule_template.make_rule(P)
|
||||
|
||||
|
||||
investigate_log("[key_name(usr)] added rule [rule.display()] to program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
if("remove_rule")
|
||||
@@ -224,7 +224,7 @@
|
||||
var/datum/nanite_program/P = nanites.programs[text2num(params["program_id"])]
|
||||
var/datum/nanite_rule/rule = P.rules[text2num(params["rule_id"])]
|
||||
rule.remove()
|
||||
|
||||
|
||||
investigate_log("[key_name(usr)] removed rule [rule.display()] from program [P.name] in cloud #[current_view]", INVESTIGATE_NANITES)
|
||||
. = TRUE
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
/datum/nanite_program/fake_death/enable_passive_effect()
|
||||
. = ..()
|
||||
host_mob.emote("deathgasp")
|
||||
host_mob.fakedeath("nanites")
|
||||
host_mob.fakedeath("nanites", TRUE)
|
||||
|
||||
/datum/nanite_program/fake_death/disable_passive_effect()
|
||||
. = ..()
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
var/largest_bomb_value = 0
|
||||
var/organization = "Third-Party" //Organization name, used for display.
|
||||
var/list/last_bitcoins = list() //Current per-second production, used for display only.
|
||||
var/list/discovered_mutations = list() //Mutations discovered by genetics, this way they are shared and cant be destroyed by destroying a single console
|
||||
var/list/tiers = list() //Assoc list, id = number, 1 is available, 2 is all reqs are 1, so on
|
||||
|
||||
/datum/techweb/New()
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
display_name = "Biological Technology"
|
||||
description = "What makes us tick." //the MC, silly!
|
||||
prereq_ids = list("base")
|
||||
design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray")
|
||||
design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag", "bloodbankgen", "telescopiciv", "medspray","genescanner")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
/datum/techweb_node/adv_biotech
|
||||
|
||||
@@ -80,11 +80,11 @@
|
||||
school = "conjuration"
|
||||
charge_max = 150
|
||||
cooldown_min = 10
|
||||
var/delete_old = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/conjure_item/cast(list/targets, mob/user = usr)
|
||||
if (item && !QDELETED(item))
|
||||
qdel(item)
|
||||
item = null
|
||||
if (delete_old && item && !QDELETED(item))
|
||||
QDEL_NULL(item)
|
||||
else
|
||||
for(var/mob/living/carbon/C in targets)
|
||||
if(C.dropItemToGround(C.get_active_held_item()))
|
||||
|
||||
@@ -128,6 +128,49 @@
|
||||
invocation_type ="none"
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/touch/mimerope
|
||||
name = "Invisible Rope"
|
||||
desc = "Form an invisible rope to tie people or trip people with."
|
||||
school = "mime"
|
||||
panel = "Mime"
|
||||
invocation_type = "emote"
|
||||
invocation_emote_self = "<span class='notice'>You start fabricate an invisible rope.</span>"
|
||||
charge_max = 700
|
||||
sound = null
|
||||
clothes_req = 0
|
||||
range = -1
|
||||
include_user = 1
|
||||
action_icon_state = "mime"
|
||||
action_background_icon_state = "bg_mime"
|
||||
hand_path = /obj/item/melee/touch_attack/mimerope
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/touch/mimerope/Click()
|
||||
if(usr && usr.mind)
|
||||
if(!usr.mind.miming)
|
||||
to_chat(usr, "<span class='notice'>You must dedicate yourself to silence first.</span>")
|
||||
return
|
||||
if (usr.get_active_held_item())
|
||||
to_chat(usr, "<span class='notice'>Your hands must be free to create the invisible rope.</span>")
|
||||
return
|
||||
invocation = "<B>[usr.real_name]</B> is twirling an invisible rope in [usr.p_their()] hands."
|
||||
else
|
||||
invocation_type ="none"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/touch/mimerope/cast(list/targets,mob/user = usr)
|
||||
|
||||
usr.put_in_hands()
|
||||
|
||||
/obj/item/melee/touch_attack/mimerope
|
||||
item_state = ""
|
||||
icon_state = ""
|
||||
name = "mime rope"
|
||||
desc = "An invisible rope."
|
||||
|
||||
/obj/item/restraints/handcuffs/cable/mime
|
||||
name = "mime restraints"
|
||||
desc = "An invisible rope."
|
||||
item_state = ""
|
||||
icon_state = ""
|
||||
|
||||
/obj/item/book/granter/spell/mimery_blockade
|
||||
spell = /obj/effect/proc_holder/spell/targeted/forcewall/mime
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/obj/effect/proc_holder/spell/targeted/touch
|
||||
var/hand_path = /obj/item/melee/touch_attack
|
||||
var/obj/item/melee/touch_attack/attached_hand = null
|
||||
var/drawmessage = "You channel the power of the spell to your hand."
|
||||
var/dropmessage = "You draw the power out of your hand."
|
||||
invocation_type = "none" //you scream on connecting, not summoning
|
||||
include_user = 1
|
||||
range = -1
|
||||
@@ -21,7 +23,7 @@
|
||||
/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets,mob/user = usr)
|
||||
if(!QDELETED(attached_hand))
|
||||
remove_hand(TRUE)
|
||||
to_chat(user, "<span class='notice'>You draw the power out of your hand.</span>")
|
||||
to_chat(user, "<span class='notice'>[dropmessage]</span>")
|
||||
return
|
||||
|
||||
for(var/mob/living/carbon/C in targets)
|
||||
@@ -43,7 +45,7 @@
|
||||
remove_hand(TRUE)
|
||||
to_chat(user, "<span class='warning'>Your hands are full!</span>")
|
||||
return FALSE
|
||||
to_chat(user, "<span class='notice'>You channel the power of the spell to your hand.</span>")
|
||||
to_chat(user, "<span class='notice'>[drawmessage]</span>")
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
for(var/obj/item/I in embedded_objects)
|
||||
embedded_objects -= I
|
||||
I.forceMove(src)
|
||||
I.unembedded()
|
||||
if(!C.has_embedded_objects())
|
||||
C.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
@@ -112,7 +113,7 @@
|
||||
for(var/X in C.dna.mutations) //some mutations require having specific limbs to be kept.
|
||||
var/datum/mutation/human/MT = X
|
||||
if(MT.limb_req && MT.limb_req == body_zone)
|
||||
MT.force_lose(C)
|
||||
C.dna.force_lose(MT)
|
||||
|
||||
for(var/X in C.internal_organs) //internal organs inside the dismembered limb are dropped.
|
||||
var/obj/item/organ/O = X
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
for(var/obj/item/I in L.embedded_objects)
|
||||
L.embedded_objects -= I
|
||||
I.forceMove(T)
|
||||
I.unembedded()
|
||||
|
||||
clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
objects++
|
||||
I.forceMove(get_turf(H))
|
||||
L.embedded_objects -= I
|
||||
I.unembedded()
|
||||
if(!H.has_embedded_objects())
|
||||
H.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE)
|
||||
/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE, other_filter = list())
|
||||
var/list/filtered_uplink_items = GLOB.uplink_categories.Copy() // list of uplink categories without associated values.
|
||||
var/list/sale_items = list()
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
continue
|
||||
if (I.restricted && !allow_restricted)
|
||||
continue
|
||||
|
||||
if (I.type in other_filter)
|
||||
continue
|
||||
LAZYSET(filtered_uplink_items[I.category], I.name, I)
|
||||
|
||||
if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 1)
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
/datum/uplink_item/stealthy_weapons/martialarts
|
||||
name = "Sleeping Carp Scroll"
|
||||
desc = "This scroll contains the secrets of an ancient martial arts technique. You will master unarmed combat, \
|
||||
deflecting all ranged weapon fire, but you also refuse to use dishonorable ranged weaponry."
|
||||
gain skin as hard as steel and swat bullets from the air, but you also refuse to use dishonorable ranged weaponry."
|
||||
item = /obj/item/book/granter/martial/carp
|
||||
cost = 17
|
||||
surplus = 0
|
||||
|
||||
Reference in New Issue
Block a user