Merge branch 'master' into debug_outfit_updates

This commit is contained in:
Arturlang
2020-02-09 22:05:26 +02:00
committed by GitHub
243 changed files with 7595 additions and 7002 deletions
+3 -3
View File
@@ -138,15 +138,15 @@ GLOBAL_PROTECT(protected_ranks)
if(!line || findtextEx_char(line,"#",1,2))
continue
var/next = findtext(line, "=")
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, line[next])))
var/datum/admin_rank/R = new(ckeyEx(copytext(line, 1, next)))
if(!R)
continue
GLOB.admin_ranks += R
GLOB.protected_ranks += R
var/prev = findchar(line, "+-*", next, 0)
while(prev)
next = findchar(line, "+-*", prev + 1, 0)
R.process_keyword(copytext_char(line, prev, next), previous_rights)
next = findchar(line, "+-*", prev + length(line[prev]), 0)
R.process_keyword(copytext(line, prev, next), previous_rights)
prev = next
previous_rights = R.rights
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
+1 -1
View File
@@ -214,4 +214,4 @@ GLOBAL_VAR(antag_prototypes)
var/datum/browser/panel = new(usr, "traitorpanel", "", 600, 600)
panel.set_content(out)
panel.open()
return
return
+1 -1
View File
@@ -75,7 +75,7 @@
message_admins("[key_name_admin(src)] decided not to answer [key_name_admin(H)]'s [sender] request.")
return
log_directed_talk(src, H, input, LOG_ADMIN, "reply")
log_directed_talk(mob, H, input, LOG_ADMIN, "reply")
message_admins("[key_name_admin(src)] replied to [key_name_admin(H)]'s [sender] message with: \"[input]\"")
to_chat(H, "You hear something crackle in your ears for a moment before a voice speaks. \"Please stand by for a message from [sender == "Syndicate" ? "your benefactor" : "Central Command"]. Message as follows[sender == "Syndicate" ? ", agent." : ":"] <span class='bold'>[input].</span> Message ends.\"")
@@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
/datum/antagonist/New()
GLOB.antagonists += src
@@ -70,6 +71,7 @@ GLOBAL_LIST_EMPTY(antagonists)
greet()
apply_innate_effects()
give_antag_moodies()
remove_blacklisted_quirks()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
@@ -117,6 +119,18 @@ GLOBAL_LIST_EMPTY(antagonists)
return
SEND_SIGNAL(owner.current, COMSIG_CLEAR_MOOD_EVENT, "antag_moodlet")
/datum/antagonist/proc/remove_blacklisted_quirks()
var/mob/living/L = owner.current
if(istype(L))
var/list/my_quirks = L.client?.prefs.all_quirks.Copy()
SSquirks.filter_quirks(my_quirks,blacklisted_quirks)
for(var/q in L.roundstart_quirks)
var/datum/quirk/Q = q
if(!(SSquirks.quirk_name_by_path(Q.type) in my_quirks))
if(initial(Q.antag_removal_text))
to_chat(L, "<span class='boldannounce'>[initial(Q.antag_removal_text)]</span>")
L.remove_quirk(Q.type)
//Returns the team antagonist belongs to if any.
/datum/antagonist/proc/get_team()
return
@@ -134,7 +148,7 @@ GLOBAL_LIST_EMPTY(antagonists)
if(objectives.len)
report += printobjectives(objectives)
for(var/datum/objective/objective in objectives)
if(!objective.check_completion())
if(objective.completable && !objective.check_completion())
objectives_complete = FALSE
break
+10 -4
View File
@@ -36,11 +36,17 @@
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
else
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text]"
objective_count++
if(win)
report += "<span class='greentext'>The [name] was successful!</span>"
@@ -31,12 +31,11 @@
if(was_running)
user.toggle_move_intent()
ADD_TRAIT(user, TRAIT_NORUNNING, "cloak of darkness")
while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN)
while(bloodsuckerdatum && ContinueActive(user))
// Pay Blood Toll (if awake)
owner.alpha = max(20, owner.alpha - min(75, 10 + 5 * level_current))
bloodsuckerdatum.AddBloodVolume(-0.2)
sleep(5) // Check every few ticks that we haven't disabled this power
// Return to Running (if you were before)
/datum/action/bloodsucker/cloak/ContinueActive(mob/living/user, mob/living/target)
if (!..())
+10 -4
View File
@@ -108,11 +108,17 @@
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
else
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text]"
objective_count++
if(win)
parts += "<span class='greentext'>The blood brothers were successful!</span>"
@@ -54,8 +54,10 @@
var/honorific
if(owner.current.gender == FEMALE)
honorific = "Ms."
else
else if(owner.current.gender == MALE)
honorific = "Mr."
else
honorific = "Mx."
if(GLOB.possible_changeling_IDs.len)
changelingID = pick(GLOB.possible_changeling_IDs)
GLOB.possible_changeling_IDs -= changelingID
@@ -552,11 +554,17 @@
if(objectives.len)
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</b></span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
changelingwin = FALSE
else
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
changelingwin = 0
parts += "<B>Objective #[count]</B>: [objective.explanation_text]"
count++
if(changelingwin)
@@ -0,0 +1,19 @@
/datum/antagonist/collector
name = "Contraband Collector"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = FALSE
blacklisted_quirks = list() // no blacklist, these guys are harmless
/datum/antagonist/collector/proc/forge_objectives()
var/datum/objective/hoard/collector/O = new
O.owner = owner
O.find_target()
objectives += O
/datum/antagonist/collector/on_gain()
forge_objectives()
. = ..()
/datum/antagonist/collector/greet()
to_chat(owner, "<B>You are a contraband collector!</B>")
owner.announce_objectives()
+10 -4
View File
@@ -300,7 +300,7 @@
if(ishuman(cultist))
var/mob/living/carbon/human/H = cultist
H.eye_color = "f00"
H.dna.update_ui_block(DNA_EYE_COLOR_BLOCK)
H.dna?.update_ui_block(DNA_EYE_COLOR_BLOCK)
ADD_TRAIT(H, TRAIT_CULT_EYES, "valid_cultist")
H.update_body()
@@ -425,10 +425,16 @@
parts += "<b>The cultists' objectives were:</b>"
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
else
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
parts += "<B>Objective #[count]</B>: [objective.explanation_text]"
count++
if(members.len)
+1 -1
View File
@@ -885,7 +885,7 @@ structure_check() searches for nearby cultist structures required for the invoca
if(new_human)
new_human.visible_message("<span class='warning'>[new_human] suddenly dissolves into bones and ashes.</span>", \
"<span class='cultlarge'>Your link to the world fades. Your form breaks apart.</span>")
for(var/obj/I in new_human)
for(var/obj/item/I in new_human)
new_human.dropItemToGround(I, TRUE)
new_human.dust()
else if(choice == "Ascend as a Dark Spirit")
@@ -44,11 +44,17 @@
var/objectives_text = ""
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
result += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
result += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
else
result += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
result += "<B>Objective #[count]</B>: [objective.explanation_text]"
count++
result += objectives_text
+9 -16
View File
@@ -63,10 +63,10 @@
possible_targets.Cut(index,index+1)
if(is_bad_guy ^ helping_station) //kill (good-ninja + bad-guy or bad-ninja + good-guy)
var/datum/objective/assassinate/O = new /datum/objective/assassinate()
var/datum/objective/assassinate/once/O = new /datum/objective/assassinate()
O.owner = owner
O.target = M
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]. You may let [M.p_they()] live, if they come back from death."
objectives += O
else //protect
var/datum/objective/protect/O = new /datum/objective/protect()
@@ -74,23 +74,16 @@
O.target = M
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
objectives += O
if(4) //debrain/capture
if(!possible_targets.len) continue
var/selected = rand(1,possible_targets.len)
var/datum/mind/M = possible_targets[selected]
var/is_bad_guy = possible_targets[M]
possible_targets.Cut(selected,selected+1)
if(is_bad_guy ^ helping_station) //debrain (good-ninja + bad-guy or bad-ninja + good-guy)
var/datum/objective/debrain/O = new /datum/objective/debrain()
if(4) //flavor
if(helping_station)
var/datum/objective/flavor/ninja_helping/O = new /datum/objective/flavor/ninja_helping
O.owner = owner
O.target = M
O.explanation_text = "Steal the brain of [M.current.real_name]."
O.forge_objective()
objectives += O
else //capture
var/datum/objective/capture/O = new /datum/objective/capture()
else
var/datum/objective/flavor/ninja_syndie/O = new /datum/objective/flavor/ninja_helping
O.owner = owner
O.gen_amount_goal()
O.forge_objective()
objectives += O
else
break
+2 -2
View File
@@ -7,10 +7,10 @@
/datum/antagonist/nukeop/clownop/on_gain()
. = ..()
ADD_TRAIT(owner, TRAIT_CLOWN_MENTALITY, NUKEOP_ANTAGONIST)
ADD_TRAIT(owner, TRAIT_CLOWN_MENTALITY, CLOWNOP_TRAIT)
/datum/antagonist/nukeop/clownop/on_removal()
REMOVE_TRAIT(owner, TRAIT_CLOWN_MENTALITY, NUKEOP_ANTAGONIST)
REMOVE_TRAIT(owner, TRAIT_CLOWN_MENTALITY, CLOWNOP_TRAIT)
return ..()
/datum/antagonist/nukeop/leader/clownop
@@ -2,6 +2,7 @@
name = "Survivalist"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
blacklisted_quirks = list(/datum/quirk/nonviolent) // mutes are allowed
var/greet_message = ""
/datum/antagonist/survivalist/proc/forge_objectives()
@@ -19,20 +20,8 @@
owner.announce_objectives()
/datum/antagonist/survivalist/guns
greet_message = "Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way."
/datum/antagonist/survivalist/guns/forge_objectives()
var/datum/objective/steal_five_of_type/summon_guns/guns = new
guns.owner = owner
objectives += guns
..()
greet_message = "Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, and don't let anyone take them!"
/datum/antagonist/survivalist/magic
name = "Amateur Magician"
greet_message = "Grow your newfound talent! Grab as many magical artefacts as possible, by any means necessary. Kill anyone who gets in your way."
/datum/antagonist/survivalist/magic/forge_objectives()
var/datum/objective/steal_five_of_type/summon_magic/magic = new
magic.owner = owner
objectives += magic
..()
greet_message = "This magic stuff is... so powerful. You want more. More! They want your power. They can't have it! Don't let them have it!"
@@ -77,19 +77,23 @@
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.storyteller.flags & NO_ASSASSIN)
is_hijacker = FALSE
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(10) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement))
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(10) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop]))
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(20)
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)
@@ -170,7 +174,7 @@
if(istype(SSticker.mode,/datum/game_mode/dynamic))
mode = SSticker.mode
is_dynamic = TRUE
assassin_prob = mode.threat_level*(2/3)
assassin_prob = max(0,mode.threat_level-20)
if(prob(assassin_prob))
if(is_dynamic)
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
@@ -187,22 +191,37 @@
maroon_objective.owner = owner
maroon_objective.find_target()
add_objective(maroon_objective)
else
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
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
@@ -369,11 +388,17 @@
if(objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
traitorwin = FALSE
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
traitorwin = FALSE
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text]"
count++
if(uplink_true)
@@ -35,7 +35,7 @@
var/objectives_complete = TRUE
if(objectives.len)
for(var/datum/objective/objective in objectives)
if(!objective.check_completion())
if(objective.completable && !objective.check_completion())
objectives_complete = FALSE
break
+13 -6
View File
@@ -61,9 +61,9 @@
owner.current.forceMove(pick(GLOB.wizardstart))
/datum/antagonist/wizard/proc/create_objectives()
var/datum/objective/new_objective = new("Cause as much creative mayhem as you can aboard the station! The more outlandish your methods of achieving this, the better! Make sure there's a decent amount of crew alive to tell of your tale.")
new_objective.completed = TRUE //So they can greentext without admin intervention.
var/datum/objective/flavor/wizard/new_objective = new
new_objective.owner = owner
new_objective.forge_objective()
objectives += new_objective
if (!(locate(/datum/objective/escape) in objectives))
@@ -94,6 +94,7 @@
to_chat(owner, "<span class='boldannounce'>You are the Space Wizard!</span>")
to_chat(owner, "<B>The Space Wizards Federation has given you the following tasks:</B>")
owner.announce_objectives()
to_chat(owner, "<B>These are merely guidelines! The federation are your masters, but you forge your own path!</B>")
to_chat(owner, "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.")
to_chat(owner, "The spellbook is bound to you, and others cannot use it.")
to_chat(owner, "In your pockets you will find a teleport scroll. Use it as needed.")
@@ -265,11 +266,17 @@
var/count = 1
var/wizardwin = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else if(completion <= 0)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
wizardwin = FALSE
else
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='yellowtext'>[completion*100]%</span>"
else
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
wizardwin = 0
parts += "<B>Objective #[count]</B>: [objective.explanation_text]"
count++
if(wizardwin)
@@ -337,8 +337,9 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list())
if(!length(cached_gases))
return
var/list/reactions = list()
for(var/I in cached_gases)
reactions += SSair.gas_reactions[I]
for(var/datum/gas_reaction/G in SSair.gas_reactions)
if(cached_gases[G.major_gas])
reactions += G
if(!length(reactions))
return
reaction_results = new
@@ -2,8 +2,6 @@
/proc/init_gas_reactions()
. = list()
for(var/type in subtypesof(/datum/gas))
.[type] = list()
for(var/r in subtypesof(/datum/gas_reaction))
var/datum/gas_reaction/reaction = r
@@ -16,27 +14,19 @@
var/datum/gas/req_gas = req
if (!reaction_key || initial(reaction_key.rarity) > initial(req_gas.rarity))
reaction_key = req_gas
.[reaction_key] += list(reaction)
sortTim(., /proc/cmp_gas_reactions, TRUE)
reaction.major_gas = reaction_key
. += reaction
sortTim(., /proc/cmp_gas_reaction)
/proc/cmp_gas_reactions(list/datum/gas_reaction/a, list/datum/gas_reaction/b) // compares lists of reactions by the maximum priority contained within the list
if (!length(a) || !length(b))
return length(b) - length(a)
var/maxa
var/maxb
for (var/datum/gas_reaction/R in a)
if (R.priority > maxa)
maxa = R.priority
for (var/datum/gas_reaction/R in b)
if (R.priority > maxb)
maxb = R.priority
return maxb - maxa
/proc/cmp_gas_reaction(datum/gas_reaction/a, datum/gas_reaction/b) // compares lists of reactions by the maximum priority contained within the list
return b.priority - a.priority
/datum/gas_reaction
//regarding the requirements lists: the minimum or maximum requirements must be non-zero.
//when in doubt, use MINIMUM_MOLE_COUNT.
var/list/min_requirements
var/list/max_requirements
var/major_gas //the highest rarity gas used in the reaction.
var/exclude = FALSE //do it this way to allow for addition/removal of reactions midmatch in the future
var/priority = 100 //lower numbers are checked/react later than higher numbers. if two reactions have the same priority they may happen in either order
var/name = "reaction"
+7 -7
View File
@@ -81,8 +81,8 @@
desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!"
contraband = TRUE
cost = 5750 // Its basicly sec suits, good boots/gloves
contains = list(/obj/item/clothing/suit/security/officer/russian,
/obj/item/clothing/suit/security/officer/russian,
contains = list(/obj/item/clothing/suit/armor/navyblue/russian,
/obj/item/clothing/suit/armor/navyblue/russian,
/obj/item/clothing/shoes/combat,
/obj/item/clothing/shoes/combat,
/obj/item/clothing/head/ushanka,
@@ -104,7 +104,7 @@
contraband = TRUE
access = FALSE
cost = 5500 //
contains = list(/obj/item/clothing/suit/security/officer/russian,
contains = list(/obj/item/clothing/suit/armor/navyblue/russian,
/obj/item/clothing/shoes/combat,
/obj/item/clothing/head/ushanka,
/obj/item/clothing/suit/armor/bulletproof,
@@ -141,15 +141,15 @@
cost = 3250
contains = list(/obj/item/clothing/under/rank/security/navyblue,
/obj/item/clothing/under/rank/security/navyblue,
/obj/item/clothing/suit/security/officer,
/obj/item/clothing/suit/security/officer,
/obj/item/clothing/suit/armor/navyblue,
/obj/item/clothing/suit/armor/navyblue,
/obj/item/clothing/head/beret/sec/navyofficer,
/obj/item/clothing/head/beret/sec/navyofficer,
/obj/item/clothing/under/rank/warden/navyblue,
/obj/item/clothing/suit/security/warden,
/obj/item/clothing/suit/armor/vest/warden/navyblue,
/obj/item/clothing/head/beret/sec/navywarden,
/obj/item/clothing/under/rank/head_of_security/navyblue,
/obj/item/clothing/suit/security/hos,
/obj/item/clothing/suit/armor/hos/navyblue,
/obj/item/clothing/head/beret/sec/navyhos)
crate_name = "security clothing crate"
+44
View File
@@ -22,6 +22,14 @@
/obj/item/book/granter/action/drink_fling)
crate_name = "bartending supply crate"
/datum/supply_pack/vending/hydro
name = "Cartridge Supply Crate"
desc = "Restock you cartridges for PDAs. Contains a PTech vending machine refill."
cost = 5000
contains = list(/obj/item/vending_refill/cart)
crate_name = "hydroponics supply crate"
crate_type = /obj/structure/closet/crate
/datum/supply_pack/vending/cigarette
name = "Cigarette Supply Crate"
desc = "Don't believe the reports - smoke today! Contains a cigarette vending machine refill."
@@ -30,6 +38,25 @@
crate_name = "cigarette supply crate"
crate_type = /obj/structure/closet/crate
/datum/supply_pack/vending/dinner
name = "Dinnerware Supply Crate"
desc = "Use a plate and have some utensils! Contains a dinnerware and sustenance vending machine refill."
cost = 2500
contains = list(/obj/item/vending_refill/sustenance,
/obj/item/vending_refill/dinnerware)
crate_name = "dinnerware supply crate"
crate_type = /obj/structure/closet/crate
/datum/supply_pack/vending/dinner
name = "Engineering Supply Crate"
desc = "Packs of tools waiting to be used for repairing. Contains a tool and engineering vending machine refill. Requires CE access."
cost = 5500 //Powerfull
access = ACCESS_CE
contains = list(/obj/item/vending_refill/tool,
/obj/item/vending_refill/engivend)
crate_name = "engineering supply crate"
crate_type = /obj/structure/closet/crate/secure/engineering
/datum/supply_pack/vending/games
name = "Games Supply Crate"
desc = "Get your game on with this game vending machine refill."
@@ -38,8 +65,18 @@
crate_name = "games supply crate"
crate_type = /obj/structure/closet/crate
/datum/supply_pack/vending/hydro
name = "Hydroponics Supply Crate"
desc = "Arnt you glad you dont have to do it the natural way? Contains a megaseed and nutrimax vending machine refill."
cost = 5000
contains = list(/obj/item/vending_refill/hydroseeds,
/obj/item/vending_refill/hydronutrients)
crate_name = "hydroponics supply crate"
crate_type = /obj/structure/closet/crate
/datum/supply_pack/vending/kinkmate
name = "Kinkmate Supply and Construction Kit"
desc = "A fun way to spend the shift. Contains unmentionable desires."
cost = 2000
contraband = TRUE
contains = list(/obj/item/vending_refill/kink, /obj/item/circuitboard/machine/kinkmate)
@@ -77,6 +114,13 @@
contains = list(/obj/item/vending_refill/cola)
crate_name = "soft drinks supply crate"
/datum/supply_pack/vending/vendomat
name = "Vendomat Supply Crate"
desc = "Contains a Vendomat restock unit!"
cost = 1200
contains = list(/obj/item/vending_refill/assist)
crate_name = "vendomat supply crate"
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Wardrobe Vendors ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-3
View File
@@ -137,7 +137,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"balls_cum_rate" = CUM_RATE,
"balls_cum_mult" = CUM_RATE_MULT,
"balls_efficiency" = CUM_EFFICIENCY,
"balls_fluid" = "semen",
"has_ovi" = FALSE,
"ovi_shape" = "knotted",
"ovi_length" = 6,
@@ -152,7 +151,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"breasts_color" = "fff",
"breasts_size" = "C",
"breasts_shape" = "Pair",
"breasts_fluid" = "milk",
"breasts_producing" = FALSE,
"has_vag" = FALSE,
"vag_shape" = "Human",
@@ -163,7 +161,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"womb_cum_rate" = CUM_RATE,
"womb_cum_mult" = CUM_RATE_MULT,
"womb_efficiency" = CUM_EFFICIENCY,
"womb_fluid" = "femcum",
"ipc_screen" = "Sunburst",
"ipc_antenna" = "None",
"flavor_text" = "",
@@ -423,13 +423,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_balls_size"] >> features["balls_size"]
S["feature_balls_shape"] >> features["balls_shape"]
S["feature_balls_sack_size"] >> features["balls_sack_size"]
S["feature_balls_fluid"] >> features["balls_fluid"]
//breasts features
S["feature_has_breasts"] >> features["has_breasts"]
S["feature_breasts_size"] >> features["breasts_size"]
S["feature_breasts_shape"] >> features["breasts_shape"]
S["feature_breasts_color"] >> features["breasts_color"]
S["feature_breasts_fluid"] >> features["breasts_fluid"]
S["feature_breasts_producing"] >> features["breasts_producing"]
//vagina features
S["feature_has_vag"] >> features["has_vag"]
+2
View File
@@ -11,6 +11,8 @@
var/transfer_blood = 0
strip_delay = 20
equip_delay_other = 40
var/strip_mod = 1 //how much they alter stripping items time by, higher is quicker
var/strip_silence = FALSE //if it shows a warning when stripping
/obj/item/clothing/gloves/ComponentInitialize()
. = ..()
+1
View File
@@ -5,6 +5,7 @@
item_state = "boxing"
equip_delay_other = 60
species_exception = list(/datum/species/golem) // now you too can be a golem boxing champion
strip_mod = 0.5
/obj/item/clothing/gloves/boxing/green
icon_state = "boxinggreen"
+2
View File
@@ -41,6 +41,7 @@
permeability_coefficient = 1
resistance_flags = NONE
transfer_prints = TRUE
strip_mod = 0.8
/obj/item/clothing/gloves/cut/family
desc = "The old gloves your great grandfather stole from Engineering, many moons ago. They've seen some tough times recently."
@@ -76,6 +77,7 @@
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
var/can_be_cut = 1
strip_mod = 1.2
/obj/item/clothing/gloves/color/black/hos
item_color = "hosred" //Exists for washing machines. Is not different from black gloves in any way.
@@ -10,6 +10,7 @@
equip_delay_other = 20
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
strip_mod = 0.9
/obj/item/clothing/gloves/botanic_leather
name = "botanist's leather gloves"
@@ -23,6 +24,7 @@
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 30)
strip_mod = 0.9
/obj/item/clothing/gloves/combat
name = "combat gloves"
@@ -38,6 +40,7 @@
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 50)
strip_mod = 1.5
/obj/item/clothing/gloves/bracer
@@ -103,3 +106,15 @@
/obj/item/clothing/gloves/rapid/hug/attack_self(mob/user)
return FALSE
/obj/item/clothing/gloves/thief
name = "black gloves"
desc = "Gloves made with completely frictionless, insulated cloth, easier to steal from people with."
icon_state = "thief"
item_state = "blackgloves"
siemens_coefficient = 0
permeability_coefficient = 0.05
strip_delay = 80
transfer_prints = FALSE
strip_mod = 5
strip_silence = TRUE
+24 -1
View File
@@ -15,6 +15,13 @@
if(!allowed)
allowed = GLOB.security_vest_allowed
/obj/item/clothing/suit/armor/navyblue
name = "security officer's jacket"
desc = "This jacket is for those special occasions when a security officer isn't required to wear their armor."
icon_state = "officerbluejacket"
item_state = "officerbluejacket"
body_parts_covered = CHEST|ARMS
/obj/item/clothing/suit/armor/vest
name = "armor vest"
desc = "A slim Type I armored vest that provides decent protection against most types of damage."
@@ -52,8 +59,17 @@
heat_protection = CHEST|GROIN|LEGS|ARMS
strip_delay = 80
/obj/item/clothing/suit/armor/hos/navyblue
name = "head of security's jacket"
desc = "This piece of clothing was specifically designed for asserting superior authority."
icon_state = "hosbluejacket"
item_state = "hosbluejacket"
body_parts_covered = CHEST|ARMS
cold_protection = CHEST|ARMS
heat_protection = CHEST|ARMS
/obj/item/clothing/suit/armor/hos/trenchcoat
name = "armored trenchoat"
name = "armored trenchcoat"
desc = "A trenchcoat enhanced with a special lightweight kevlar. The epitome of tactical plainclothes."
icon_state = "hostrench"
item_state = "hostrench"
@@ -78,6 +94,13 @@
desc = "A red jacket with silver rank pips and body armor strapped on top."
icon_state = "warden_jacket"
/obj/item/clothing/suit/armor/vest/warden/navyblue
name = "warden's jacket"
desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig."
icon_state = "wardenbluejacket"
item_state = "wardenbluejacket"
body_parts_covered = CHEST|ARMS
/obj/item/clothing/suit/armor/vest/leather
name = "security overcoat"
desc = "Lightly armored leather overcoat meant as casual wear for high-ranking officers. Bears the crest of Nanotrasen Security."
-22
View File
@@ -155,28 +155,6 @@
blood_overlay_type = "armor" //it's the less thing that I can put here
body_parts_covered = NONE
//Security
/obj/item/clothing/suit/security/officer
name = "security officer's jacket"
desc = "This jacket is for those special occasions when a security officer isn't required to wear their armor."
icon_state = "officerbluejacket"
item_state = "officerbluejacket"
body_parts_covered = CHEST|ARMS
/obj/item/clothing/suit/security/warden
name = "warden's jacket"
desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig."
icon_state = "wardenbluejacket"
item_state = "wardenbluejacket"
body_parts_covered = CHEST|ARMS
/obj/item/clothing/suit/security/hos
name = "head of security's jacket"
desc = "This piece of clothing was specifically designed for asserting superior authority."
icon_state = "hosbluejacket"
item_state = "hosbluejacket"
body_parts_covered = CHEST|ARMS
//Surgeon
/obj/item/clothing/suit/apron/surgical
name = "surgical apron"
+1 -1
View File
@@ -317,7 +317,7 @@
flags_cover = HEADCOVERSEYES
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
/obj/item/clothing/suit/security/officer/russian
/obj/item/clothing/suit/armor/navyblue/russian
name = "\improper Russian officer's jacket"
desc = "This jacket is for those special occasions when a russian officer isn't required to wear their armor."
icon_state = "officertanjacket"
+1 -1
View File
@@ -22,7 +22,7 @@
/datum/round_event/meteor_wave/setup()
announceWhen = 1
startWhen = rand(60, 90) //Yeah for SOME REASON this is measured in seconds and not deciseconds???
startWhen = rand(90, 180) // Apparently it is by 2 seconds, so 90 is actually 180 seconds, and 180 is 360 seconds. So this is 3-6 minutes
if(GLOB.singularity_counter)
startWhen *= 1 - min(GLOB.singularity_counter * SINGULO_BEACON_DISTURBANCE, SINGULO_BEACON_MAX_DISTURBANCE)
endWhen = startWhen + 60
+4 -3
View File
@@ -71,9 +71,10 @@
reagents_add = list(/datum/reagent/consumable/nutriment = 0.05)
rarity = 30
/obj/item/seeds/poppy/lily/trumpet/Initialize()
..()
unset_mutability(/datum/plant_gene/reagent/polypyr, PLANT_GENE_EXTRACTABLE)
/obj/item/seeds/poppy/lily/trumpet/Initialize(mapload, nogenes = FALSE)
. = ..()
if(!nogenes)
unset_mutability(/datum/plant_gene/reagent/polypyr, PLANT_GENE_EXTRACTABLE)
/obj/item/reagent_containers/food/snacks/grown/trumpet
seed = /obj/item/seeds/poppy/lily/trumpet
+4 -3
View File
@@ -82,9 +82,10 @@
mutatelist = list()
reagents_add = list(/datum/reagent/consumable/nutriment = 0.05, /datum/reagent/medicine/silibinin = 0.1)
/obj/item/seeds/galaxythistle/Initialize()
..()
unset_mutability(/datum/plant_gene/trait/invasive, PLANT_GENE_REMOVABLE)
/obj/item/seeds/galaxythistle/Initialize(mapload, nogenes = FALSE)
. = ..()
if(!nogenes)
unset_mutability(/datum/plant_gene/trait/invasive, PLANT_GENE_REMOVABLE)
/obj/item/reagent_containers/food/snacks/grown/galaxythistle
seed = /obj/item/seeds/galaxythistle
+5 -4
View File
@@ -217,10 +217,11 @@
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
reagents_add = list(/datum/reagent/consumable/nutriment = 0.1)
/obj/item/seeds/chanterelle/jupitercup/Initialize()
..()
unset_mutability(/datum/plant_gene/reagent/liquidelectricity, PLANT_GENE_EXTRACTABLE)
unset_mutability(/datum/plant_gene/trait/plant_type/carnivory, PLANT_GENE_REMOVABLE)
/obj/item/seeds/chanterelle/jupitercup/Initialize(mapload, nogenes = FALSE)
. = ..()
if(!nogenes)
unset_mutability(/datum/plant_gene/reagent/liquidelectricity, PLANT_GENE_EXTRACTABLE)
unset_mutability(/datum/plant_gene/trait/plant_type/carnivory, PLANT_GENE_REMOVABLE)
/obj/item/reagent_containers/food/snacks/grown/mushroom/jupitercup
seed = /obj/item/seeds/chanterelle/jupitercup
+3 -1
View File
@@ -18,7 +18,9 @@
return !istype(S, /obj/item/seeds/sample) // Samples can't accept new genes
/datum/plant_gene/proc/Copy()
return new type
var/datum/plant_gene/G = new type
G.mutability_flags = mutability_flags
return G
/datum/plant_gene/proc/apply_vars(obj/item/seeds/S) // currently used for fire resist, can prob. be further refactored
return
+1 -1
View File
@@ -37,7 +37,7 @@
var/weed_rate = 1 //If the chance below passes, then this many weeds sprout during growth
var/weed_chance = 5 //Percentage chance per tray update to grow weeds
/obj/item/seeds/Initialize(loc, nogenes = 0)
/obj/item/seeds/Initialize(mapload, nogenes = 0)
. = ..()
pixel_x = rand(-8, 8)
pixel_y = rand(-8, 8)
+1
View File
@@ -17,6 +17,7 @@
display_order = JOB_DISPLAY_ORDER_MIME
/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
. = ..()
H.apply_pref_name("mime", M.client)
/datum/outfit/job/mime
+14 -2
View File
@@ -129,6 +129,14 @@
choice.forceMove(drop_location())
update_icon()
/obj/structure/bookcase/attack_ghost(mob/dead/observer/user as mob)
if(contents.len && in_range(user, src))
var/obj/item/book/choice = input("Which book would you like to read?") as null|obj in contents
if(choice)
if(!istype(choice)) //spellbook, cult tome, or the one weird bible storage
to_chat(user,"A mysterious force is keeping you from reading that.")
return
choice.attack_self(user)
/obj/structure/bookcase/deconstruct(disassembled = TRUE)
new /obj/item/stack/sheet/mineral/wood(loc, 4)
@@ -204,8 +212,9 @@
return
if(dat)
user << browse("<TT><I>Penned by [author].</I></TT> <BR>" + "[dat]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "book_nerd", /datum/mood_event/book_nerd)
if(istype(user, /mob/living))
user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "book_nerd", /datum/mood_event/book_nerd)
onclose(user, "book")
else
to_chat(user, "<span class='notice'>This book is completely blank!</span>")
@@ -311,6 +320,9 @@
else
..()
/obj/item/book/attack_ghost(mob/user)
attack_self(user)
/*
* Barcode Scanner
+1 -1
View File
@@ -796,7 +796,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
update_icon()
/mob/dead/observer/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
return IsAdminGhost(usr)
return IsAdminGhost(usr) || (M.ghost_flags & INTERACT_GHOST_READ)
/mob/dead/observer/is_literate()
return 1
+2 -2
View File
@@ -559,7 +559,7 @@
health = round(maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute, DAMAGE_PRECISION)
staminaloss = round(total_stamina, DAMAGE_PRECISION)
update_stat()
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD*2) && stat == DEAD )
become_husk("burn")
med_hud_set_health()
if(stat == SOFT_CRIT)
@@ -986,4 +986,4 @@
if(H.clothing_flags & SCAN_REAGENTS)
return TRUE
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
return TRUE
return TRUE
@@ -274,7 +274,7 @@
return
if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
var/friendly_check = FALSE
if(lying)
if(buckled)
to_chat(M, "<span class='warning'>You need to unbuckle [src] first to do that!")
@@ -289,39 +289,35 @@
playsound(src, 'sound/items/Nose_boop.ogg', 50, 0)
else if(check_zone(M.zone_selected) == "head")
var/mob/living/carbon/human/H = src
var/datum/species/pref_species = H.dna.species
var/datum/species/S
if(ishuman(src))
S = dna.species
M.visible_message("<span class='notice'>[M] gives [H] a pat on the head to make [p_them()] feel better!</span>", \
"<span class='notice'>You give [H] a pat on the head to make [p_them()] feel better!</span>")
M.visible_message("<span class='notice'>[M] gives [src] a pat on the head to make [p_them()] feel better!</span>", \
"<span class='notice'>You give [src] a pat on the head to make [p_them()] feel better!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
if (mood.sanity >= SANITY_GREAT)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
else if (mood.sanity >= SANITY_DISTURBED)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
if(H.dna.species.can_wag_tail(H))
if("tail_human" in pref_species.default_features)
if(H.dna.features["tail_human"] == "None")
friendly_check = TRUE
if(S?.can_wag_tail(src))
if("tail_human" in S.default_features)
if(dna.features["tail_human"] == "None")
return
else
if(!H.dna.species.is_wagging_tail())
H.emote("wag")
if(!dna.species.is_wagging_tail())
emote("wag")
if("tail_lizard" in pref_species.default_features)
if(H.dna.features["tail_lizard"] == "None")
if("tail_lizard" in S.default_features)
if(dna.features["tail_lizard"] == "None")
return
else
if(!H.dna.species.is_wagging_tail())
H.emote("wag")
if(!dna.species.is_wagging_tail())
emote("wag")
if("mam_tail" in pref_species.default_features)
if(H.dna.features["mam_tail"] == "None")
if("mam_tail" in S.default_features)
if(dna.features["mam_tail"] == "None")
return
else
if(!H.dna.species.is_wagging_tail())
H.emote("wag")
if(!dna.species.is_wagging_tail())
emote("wag")
else
return
@@ -335,8 +331,11 @@
M.visible_message("<span class='notice'>[M] hugs [src] to make [p_them()] feel better!</span>", \
"<span class='notice'>You hug [src] to make [p_them()] feel better!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
if(HAS_TRAIT(M, TRAIT_FRIENDLY))
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
friendly_check = TRUE
if(friendly_check && HAS_TRAIT(M, TRAIT_FRIENDLY))
var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
if(mood)
if (mood.sanity >= SANITY_GREAT)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
else if (mood.sanity >= SANITY_DISTURBED)
+1 -4
View File
@@ -16,10 +16,6 @@
. += "[t_He] [t_is] wearing [wear_mask.get_examine_string(user)] on [t_his] face."
if (wear_neck)
. += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck.\n"
if(can_be_held)
. += "[t_He] looks small enough to be picked up with <b>Alt+Click</b>!\n"
for(var/obj/item/I in held_items)
if(!(I.item_flags & ABSTRACT))
@@ -116,4 +112,5 @@
. += "[t_He] look[p_s()] very happy."
if(MOOD_LEVEL_HAPPY4 to INFINITY)
. += "[t_He] look[p_s()] ecstatic."
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
. += "*---------*</span>"
@@ -7,13 +7,14 @@
/mob/living/carbon/human/spawn_gibs(with_bodyparts, atom/loc_override)
var/location = loc_override ? loc_override.drop_location() : drop_location()
if(dna?.species?.gib_types)
var/blood_dna = get_blood_dna_list()
var/datum/species/S = dna.species
var/length = length(S.gib_types)
if(length)
var/path = (with_bodyparts && length > 1) ? S.gib_types[2] : S.gib_types[1]
new path(location, src, get_static_viruses())
else
new S.gib_types(location, src, get_static_viruses())
new S.gib_types(location, src, get_static_viruses(), blood_dna)
else
if(with_bodyparts)
new /obj/effect/gibspawner/human(location, src, get_static_viruses())
@@ -67,4 +68,4 @@
/mob/living/carbon/proc/makeUncloneable()
ADD_TRAIT(src, TRAIT_NOCLONE, MADE_UNCLONEABLE)
blood_volume = 0
return TRUE
return TRUE
@@ -396,6 +396,7 @@
var/temp_flavor = print_flavor_text_2()
if(temp_flavor)
. += temp_flavor
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
. += "*---------*</span>"
/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
@@ -1,45 +0,0 @@
/mob/living/carbon/human/proc/examine_nutrition()
var/message = ""
var/nutrition_examine = round(nutrition)
var/t_He = "It" //capitalised for use at the start of each line.
var/t_His = "Its"
var/t_his = "its"
var/t_is = "is"
var/t_has = "has"
switch(gender)
if(MALE)
t_He = "He"
t_his = "his"
t_His = "His"
if(FEMALE)
t_He = "She"
t_his = "her"
t_His = "Her"
if(PLURAL)
t_He = "They"
t_his = "their"
t_His = "Their"
t_is = "are"
t_has = "have"
if(NEUTER)
t_He = "It"
t_his = "its"
t_His = "Its"
switch(nutrition_examine)
if(0 to 49)
message = "<span class='warning'>[t_He] [t_is] starving! You can hear [t_his] stomach snarling from across the room!</span>\n"
if(50 to 99)
message = "<span class='warning'>[t_He] [t_is] extremely hungry. A deep growl occasionally rumbles from [t_his] empty stomach.</span>\n"
if(100 to 499)
return message //Well that's pretty normal, really.
if(500 to 864) // Fat.
message = "[t_He] [t_has] a stuffed belly, bloated fat and round from eating too much.\n"
if(1200 to 1934) // One person fully digested.
message = "<span class='warning'>[t_He] [t_is] sporting a large, round, sagging stomach. It's contains at least their body weight worth of glorping slush.</span>\n"
if(1935 to 3004) // Two people.
message = "<span class='warning'>[t_He] [t_is] engorged with a huge stomach that sags and wobbles as they move. [t_He] must have consumed at least twice their body weight. It looks incredibly soft.</span>\n"
if(3005 to 4074) // Three people.
message = "<span class='warning'>[t_His] stomach is firmly packed with digesting slop. [t_He] must have eaten at least a few times worth their body weight! It looks hard for them to stand, and [t_his] gut jiggles when they move.</span>\n"
if(4075 to 10000) // Four or more people.
message = "<span class='warning'>[t_He] [t_is] so absolutely stuffed that you aren't sure how it's possible to move. [t_He] can't seem to swell any bigger. The surface of [t_his] belly looks sorely strained!</span>\n"
return message
+1 -1
View File
@@ -91,7 +91,7 @@
var/say_starter = "Say \"" //"
if(findtextEx(temp, say_starter, 1, length(say_starter) + 1) && length(temp) > length(say_starter)) //case sensitive means
temp = trim_left(copytext(temp, length(say_starter + 1)))
temp = trim_left(copytext(temp, length(say_starter) + 1))
temp = replacetext(temp, ";", "", 1, 2) //general radio
while(trim_left(temp)[1] == ":") //dept radio again (necessary)
temp = copytext_char(trim_left(temp), 3)
@@ -132,14 +132,14 @@
return INITIALIZE_HINT_QDEL
owner = new_owner
START_PROCESSING(SSobj, src)
RegisterSignal(owner, COMSIG_MOB_EXAMINATE, .proc/examinate_check)
RegisterSignal(owner, COMSIG_CLICK_SHIFT, .proc/examinate_check)
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
RegisterSignal(owner, COMSIG_LIVING_FULLY_HEAL, .proc/retrieve_head)
/obj/item/dullahan_relay/proc/examinate_check(mob/source, atom/A)
if(source.client.eye == src && ((A in view(source.client.view, src)) || (isturf(A) && source.sight & SEE_TURFS) || (ismob(A) && source.sight & SEE_MOBS) || (isobj(A) && source.sight & SEE_OBJS)))
return COMPONENT_ALLOW_EXAMINE
/obj/item/dullahan_relay/proc/examinate_check(atom/source, mob/user)
if(user.client.eye == src)
return COMPONENT_ALLOW_EXAMINATE
/obj/item/dullahan_relay/proc/include_owner(datum/source, list/processing_list, list/hearers)
if(!QDELETED(owner))
@@ -182,10 +182,10 @@ There are several things that need to be remembered:
if(!gloves && bloody_hands)
var/mutable_appearance/bloody_overlay = mutable_appearance('icons/effects/blood.dmi', "bloodyhands", -GLOVES_LAYER, color = blood_DNA_to_color())
if(get_num_arms() < 2)
if(has_left_hand())
if(get_num_arms(FALSE) < 2)
if(has_left_hand(FALSE))
bloody_overlay.icon_state = "bloodyhands_left"
else if(has_right_hand())
else if(has_right_hand(FALSE))
bloody_overlay.icon_state = "bloodyhands_right"
overlays_standing[GLOVES_LAYER] = bloody_overlay
@@ -265,7 +265,7 @@ There are several things that need to be remembered:
/mob/living/carbon/human/update_inv_shoes()
remove_overlay(SHOES_LAYER)
if(get_num_legs() <2)
if(get_num_legs(FALSE) <2)
return
if(client && hud_used)
@@ -15,7 +15,6 @@
bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
/obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
hud_type = /datum/hud/monkey
can_be_held = "monkey"
/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
verbs += /mob/living/proc/mob_sleep
@@ -42,14 +41,15 @@
create_dna(src)
dna.initialize_dna(random_blood_type())
/mob/living/carbon/monkey/ComponentInitialize()
. = ..()
AddElement(/datum/element/mob_holder, "monkey", null, null, null, SLOT_HEAD)
/mob/living/carbon/monkey/Destroy()
SSmobs.cubemonkeys -= src
return ..()
/mob/living/carbon/monkey/generate_mob_holder()
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "monkey", 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi', TRUE)
return holder
/mob/living/carbon/monkey/create_internal_organs()
internal_organs += new /obj/item/organ/appendix
internal_organs += new /obj/item/organ/lungs
-130
View File
@@ -1,130 +0,0 @@
//Generic system for picking up mobs.
//Currently works for head and hands.
/obj/item/clothing/head/mob_holder
name = "bugged mob"
desc = "Yell at coderbrush."
icon = null
icon_state = ""
var/mob/living/held_mob
var/can_head = FALSE
w_class = WEIGHT_CLASS_BULKY
/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/M, _worn_state, alt_worn, lh_icon, rh_icon, _can_head_override = FALSE)
. = ..()
if(M)
M.setDir(SOUTH)
held_mob = M
M.forceMove(src)
appearance = M.appearance
name = M.name
desc = M.desc
if(_can_head_override)
can_head = _can_head_override
if(alt_worn)
alternate_worn_icon = alt_worn
if(_worn_state)
item_state = _worn_state
icon_state = _worn_state
if(lh_icon)
lefthand_file = lh_icon
if(rh_icon)
righthand_file = rh_icon
if(!can_head)
slot_flags = NONE
/obj/item/clothing/head/mob_holder/Destroy()
if(held_mob)
release()
return ..()
/obj/item/clothing/head/mob_holder/dropped()
..()
if(isturf(loc))//don't release on soft-drops
release()
/obj/item/clothing/head/mob_holder/proc/release()
if(isliving(loc))
var/mob/living/L = loc
L.dropItemToGround(src)
if(held_mob)
var/mob/living/m = held_mob
m.forceMove(get_turf(m))
m.reset_perspective()
m.setDir(SOUTH)
held_mob = null
qdel(src)
/obj/item/clothing/head/mob_holder/relaymove(mob/user)
return
/obj/item/clothing/head/mob_holder/container_resist()
if(isliving(loc))
var/mob/living/L = loc
visible_message("<span class='warning'>[src] escapes [L]!</span>")
release()
/mob/living/proc/mob_pickup(mob/living/L)
var/obj/item/clothing/head/mob_holder/holder = generate_mob_holder()
if(!holder)
return
drop_all_held_items()
L.put_in_hands(holder)
return
/mob/living/proc/mob_try_pickup(mob/living/user)
if(!ishuman(user) || !src.Adjacent(user) || user.incapacitated() || !can_be_held)
return FALSE
if(user.get_active_held_item())
to_chat(user, "<span class='warning'>Your hands are full!</span>")
return FALSE
if(buckled)
to_chat(user, "<span class='warning'>[src] is buckled to something!</span>")
return FALSE
if(src == user)
to_chat(user, "<span class='warning'>You can't pick yourself up.</span>")
return FALSE
visible_message("<span class='warning'>[user] starts picking up [src].</span>", \
"<span class='userdanger'>[user] starts picking you up!</span>")
if(!do_after(user, 20, target = src))
return FALSE
if(user.get_active_held_item()||buckled)
return FALSE
visible_message("<span class='warning'>[user] picks up [src]!</span>", \
"<span class='userdanger'>[user] picks you up!</span>")
to_chat(user, "<span class='notice'>You pick [src] up.</span>")
mob_pickup(user)
return TRUE
/mob/living/AltClick(mob/user)
. = ..()
if(mob_try_pickup(user))
return TRUE
// I didn't define these for mobs, because you shouldn't be able to breathe out of mobs and using their loc isn't always the logical thing to do.
/obj/item/clothing/head/mob_holder/assume_air(datum/gas_mixture/env)
var/atom/location = loc
if(!loc)
return //null
var/turf/T = get_turf(loc)
while(location != T)
location = location.loc
if(ismob(location))
return location.loc.assume_air(env)
return loc.assume_air(env)
/obj/item/clothing/head/mob_holder/remove_air(amount)
var/atom/location = loc
if(!loc)
return //null
var/turf/T = get_turf(loc)
while(location != T)
location = location.loc
if(ismob(location))
return location.loc.remove_air(amount)
return loc.remove_air(amount)
+19 -10
View File
@@ -40,11 +40,6 @@
QDEL_LIST(diseases)
return ..()
/mob/living/proc/generate_mob_holder()
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, (istext(can_be_held) ? can_be_held : ""), 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi')
return holder
/mob/living/onZImpact(turf/T, levels)
if(!isgroundlessturf(T))
ZImpactDamage(T, levels)
@@ -763,10 +758,22 @@
if(HAS_TRAIT(what, TRAIT_NODROP))
to_chat(src, "<span class='warning'>You can't remove \the [what.name], it appears to be stuck!</span>")
return
who.visible_message("<span class='danger'>[src] tries to remove [who]'s [what.name].</span>", \
var/strip_mod = 1
var/strip_silence = FALSE
if (ishuman(src)) //carbon doesn't actually wear gloves
var/mob/living/carbon/C = src
var/obj/item/clothing/gloves/g = C.gloves
if (istype(g))
strip_mod = g.strip_mod
strip_silence = g.strip_silence
if (!strip_silence)
who.visible_message("<span class='danger'>[src] tries to remove [who]'s [what.name].</span>", \
"<span class='userdanger'>[src] tries to remove [who]'s [what.name].</span>")
what.add_fingerprint(src)
if(do_mob(src, who, what.strip_delay, ignorehelditem = TRUE))
what.add_fingerprint(src)
else
to_chat(src,"<span class='notice'>You try to remove [who]'s [what.name].</span>")
what.add_fingerprint(src)
if(do_mob(src, who, round(what.strip_delay / strip_mod), ignorehelditem = TRUE))
if(what && Adjacent(who))
if(islist(where))
var/list/L = where
@@ -1087,6 +1094,10 @@
fall(forced = 1)
canmove = !(ko || recoveringstam || pinned || IsStun() || IsFrozen() || chokehold || buckled || (!has_legs && !ignore_legs && !has_arms)) //Cit change - makes it plausible to move while resting, adds pinning and stamina crit
density = !lying
if(resting)
ENABLE_BITFIELD(movement_type, CRAWLING)
else
DISABLE_BITFIELD(movement_type, CRAWLING)
if(lying)
if(layer == initial(layer)) //to avoid special cases like hiding larvas.
layer = LYING_MOB_LAYER //so mob lying always appear behind standing mobs
@@ -1172,8 +1183,6 @@
return
if(!over.Adjacent(src) || (user != src) || !canUseTopic(over))
return
if(can_be_held)
mob_try_pickup(over)
/mob/living/proc/get_static_viruses() //used when creating blood and other infective objects
if(!LAZYLEN(diseases))
@@ -101,8 +101,6 @@
var/list/obj/effect/proc_holder/abilities = list()
var/can_be_held = FALSE //whether this can be picked up and held.
var/radiation = 0 //If the mob is irradiated.
var/ventcrawl_layer = PIPING_LAYER_DEFAULT
var/losebreath = 0
+2 -1
View File
@@ -103,7 +103,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
else if(message_mode || saymode)
message = copytext_char(message, 3)
message = trim_left(message)
if(!message)
return
if(message_mode == MODE_ADMIN)
if(client)
client.cmd_admin_say(message)
+1 -4
View File
@@ -11,7 +11,7 @@
health = 500
maxHealth = 500
layer = BELOW_MOB_LAYER
can_be_held = TRUE
var/datum/element/mob_holder/current_mob_holder //because only a few of their chassis can be actually held.
var/network = "ss13"
var/obj/machinery/camera/current = null
@@ -64,9 +64,6 @@
var/list/possible_chassis //initialized in initialize.
var/list/dynamic_chassis_icons //ditto.
var/list/chassis_pixel_offsets_x //stupid dogborgs
var/static/item_head_icon = 'icons/mob/pai_item_head.dmi'
var/static/item_lh_icon = 'icons/mob/pai_item_lh.dmi'
var/static/item_rh_icon = 'icons/mob/pai_item_rh.dmi'
var/emitterhealth = 20
var/emittermaxhealth = 20
@@ -96,6 +96,12 @@
dynamic_chassis = choice
resist_a_rest(FALSE, TRUE)
update_icon()
if(possible_chassis[chassis])
current_mob_holder = AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', SLOT_HEAD)
else
current_mob_holder?.Detach(src)
current_mob_holder = null
return
to_chat(src, "<span class='boldnotice'>You switch your holochassis projection composite to [chassis]</span>")
/mob/living/silicon/pai/lay_down()
@@ -117,19 +123,6 @@
set_light(0)
to_chat(src, "<span class='notice'>You disable your integrated light.</span>")
/mob/living/silicon/pai/mob_pickup(mob/living/L)
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, chassis, item_head_icon, item_lh_icon, item_rh_icon)
if(!L.put_in_hands(holder))
qdel(holder)
else
L.visible_message("<span class='warning'>[L] scoops up [src]!</span>")
/mob/living/silicon/pai/mob_try_pickup(mob/living/user)
if(!possible_chassis[chassis])
to_chat(user, "<span class='warning'>[src]'s current form isn't able to be carried!</span>")
return FALSE
return ..()
/mob/living/silicon/pai/verb/toggle_chassis_sit()
set name = "Toggle Chassis Sit"
set category = "IC"
@@ -191,7 +191,7 @@
else if(istype(I, /obj/item/gun/energy))
var/obj/item/gun/energy/EG = I
if(EG.cell?.charge < EG.cell.maxcharge)
var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.select]
var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.current_firemode_index]
EG.cell.give(S.e_cost * coeff)
if(!EG.chambered)
EG.recharge_newshot(TRUE)
@@ -182,8 +182,9 @@
return TRUE
/mob/living/simple_animal/bot/death(gibbed)
explode()
..()
. = ..()
if(!gibbed)
explode()
/mob/living/simple_animal/bot/proc/explode()
qdel(src)
@@ -143,7 +143,7 @@
/datum/outfit/russiancorpse/officer
name = "Russian Officer Corpse"
uniform = /obj/item/clothing/under/rank/security/navyblue/russian
suit = /obj/item/clothing/suit/security/officer/russian
suit = /obj/item/clothing/suit/armor/navyblue/russian
shoes = /obj/item/clothing/shoes/combat
ears = /obj/item/radio/headset
head = /obj/item/clothing/head/ushanka
@@ -207,7 +207,7 @@
/obj/effect/mob_spawn/human/corpse/bee_terrorist
name = "BLF Operative"
outfit = /datum/outfit/bee_terrorist
/datum/outfit/bee_terrorist
name = "BLF Operative"
uniform = /obj/item/clothing/under/color/yellow
@@ -31,7 +31,7 @@
var/mob/living/simple_animal/mouse/movement_target
gold_core_spawnable = FRIENDLY_SPAWN
collar_type = "cat"
can_be_held = "cat2"
var/held_icon = "cat2"
do_footstep = TRUE
/mob/living/simple_animal/pet/cat/Initialize()
@@ -41,6 +41,7 @@
/mob/living/simple_animal/pet/cat/ComponentInitialize()
. = ..()
AddElement(/datum/element/wuv, "purrs!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "hisses!", EMOTE_AUDIBLE)
AddElement(/datum/element/mob_holder, held_icon)
/mob/living/simple_animal/pet/cat/update_canmove()
..()
@@ -60,6 +61,7 @@
icon_state = "spacecat"
icon_living = "spacecat"
icon_dead = "spacecat_dead"
held_icon = "spacecat"
unsuitable_atmos_damage = 0
minbodytemp = TCMB
maxbodytemp = T0C + 40
@@ -71,6 +73,7 @@
icon_state = "original"
icon_living = "original"
icon_dead = "original_dead"
held_icon = "original"
collar_type = null
unique_pet = TRUE
@@ -84,7 +87,7 @@
pass_flags = PASSMOB
mob_size = MOB_SIZE_SMALL
collar_type = "kitten"
can_be_held = "cat"
held_icon = "cat"
//RUNTIME IS ALIVE! SQUEEEEEEEE~
/mob/living/simple_animal/pet/cat/Runtime
@@ -249,7 +252,7 @@
attacked_sound = 'sound/items/eatfood.ogg'
deathmessage = "loses its false life and collapses!"
death_sound = "bodyfall"
can_be_held = "cak"
held_icon = "cak"
/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
..()
@@ -13,13 +13,14 @@
see_in_dark = 5
speak_chance = 1
turns_per_move = 10
var/held_icon = "corgi"
do_footstep = TRUE
can_be_held = TRUE
/mob/living/simple_animal/pet/dog/ComponentInitialize()
. = ..()
AddElement(/datum/element/wuv, "yaps_happily!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "growls!", EMOTE_AUDIBLE)
AddElement(/datum/element/mob_holder, held_icon)
//Corgis and pugs are now under one dog subtype
@@ -34,13 +35,11 @@
childtype = list(/mob/living/simple_animal/pet/dog/corgi/puppy = 95, /mob/living/simple_animal/pet/dog/corgi/puppy/void = 5)
animal_species = /mob/living/simple_animal/pet/dog
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = TRUE
collar_type = "corgi"
var/obj/item/inventory_head
var/obj/item/inventory_back
var/shaved = FALSE
var/nofur = FALSE //Corgis that have risen past the material plane of existence.
can_be_held = "corgi"
/mob/living/simple_animal/pet/dog/corgi/Destroy()
QDEL_NULL(inventory_head)
@@ -69,7 +68,7 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/pug = 3)
gold_core_spawnable = FRIENDLY_SPAWN
collar_type = "pug"
can_be_held = "pug"
held_icon = "pug"
/mob/living/simple_animal/pet/dog/corgi/exoticcorgi
name = "Exotic Corgi"
@@ -156,13 +155,6 @@
..()
update_corgi_fluff()
/mob/living/simple_animal/pet/dog/corgi/mob_pickup(mob/living/L)
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "corgi", null, 'icons/mob/pets_held_lh.dmi', 'icons/mob/pets_held_rh.dmi', FALSE)
if(!L.put_in_hands(holder))
qdel(holder)
else
L.visible_message("<span class='warning'>[L] scoops up [src]!</span>")
/mob/living/simple_animal/pet/dog/corgi/Topic(href, href_list)
if(!(iscarbon(usr) || iscyborg(usr)) || !usr.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
usr << browse(null, "window=mob[REF(src)]")
@@ -371,7 +363,10 @@
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
can_be_held = "old_corgi"
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")
/mob/living/simple_animal/pet/dog/corgi/Ian/Life()
if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
@@ -594,7 +589,7 @@
unsuitable_atmos_damage = 0
minbodytemp = TCMB
maxbodytemp = T0C + 40
can_be_held = "void_puppy"
held_icon = "void_puppy"
/mob/living/simple_animal/pet/dog/corgi/puppy/void/Process_Spacemove(movement_dir = 0)
return 1 //Void puppies can navigate space.
@@ -616,7 +611,7 @@
response_harm = "kicks"
var/turns_since_scan = 0
var/puppies = 0
can_be_held = "lisa"
held_icon = "lisa"
//Lisa already has a cute bow!
/mob/living/simple_animal/pet/dog/corgi/Lisa/Topic(href, href_list)
@@ -51,7 +51,7 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
see_in_dark = 7
blood_volume = 0
can_be_held = TRUE
var/can_be_held = TRUE //mob holder element.
held_items = list(null, null)
var/staticChoice = "static"
var/list/staticChoices = list("static", "blank", "letter", "animal")
@@ -101,6 +101,11 @@
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
/mob/living/simple_animal/drone/ComponentInitialize()
. = ..()
if(can_be_held)
//icon/item state is defined in mob_holder/drone_worn_icon()
AddElement(/datum/element/mob_holder, null, 'icons/mob/head.dmi', 'icons/mob/inhands/clothing_righthand.dmi', 'icons/mob/inhands/clothing_lefthand.dmi', TRUE, /datum/element/mob_holder.proc/drone_worn_icon)
/mob/living/simple_animal/drone/med_hud_set_health()
var/image/holder = hud_list[DIAG_HUD]
@@ -283,7 +288,3 @@
var/obj/item/clothing/H = head
if(H.clothing_flags & SCAN_REAGENTS)
return TRUE
/mob/living/simple_animal/drone/generate_mob_holder()
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "[visualAppearence]_hat", null, null, null, TRUE)
return holder
@@ -29,12 +29,6 @@
if("Nothing")
return
//picky up the drone c:
/mob/living/simple_animal/drone/attack_hand(mob/user)
if(user.a_intent != INTENT_HELP)
return ..() // TODO: convert picking up mobs into an element or component.
mob_try_pickup(user)
/mob/living/simple_animal/drone/proc/try_reactivate(mob/living/user)
var/mob/dead/observer/G = get_ghost()
if(!client && (!G || !G.client))
@@ -18,9 +18,12 @@
response_disarm = "gently pushes aside"
response_harm = "kicks"
gold_core_spawnable = FRIENDLY_SPAWN
can_be_held = "fox"
do_footstep = TRUE
/mob/living/simple_animal/pet/fox/ComponentInitialize()
. = ..()
AddElement(/datum/element/mob_holder, "fox")
//Captain fox
/mob/living/simple_animal/pet/fox/Renault
name = "Renault"
@@ -23,7 +23,10 @@
obj_damage = 0
environment_smash = ENVIRONMENT_SMASH_NONE
var/static/list/edibles = typecacheof(list(/mob/living/simple_animal/butterfly, /mob/living/simple_animal/cockroach)) //list of atoms, however turfs won't affect AI, but will affect consumption.
can_be_held = "lizard" //you can hold lizards now.
/mob/living/simple_animal/hostile/lizard/ComponentInitialize()
. = ..()
AddElement(/datum/element/mob_holder, "lizard", null, null, null, 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
@@ -40,7 +43,3 @@
return TRUE
else
return ..()
/mob/living/simple_animal/hostile/lizard/generate_mob_holder()
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, "lizard", 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi', TRUE)
return holder
@@ -26,17 +26,16 @@
var/body_color //brown, gray and white, leave blank for random
gold_core_spawnable = FRIENDLY_SPAWN
var/chew_probability = 1
can_be_held = TRUE
/mob/living/simple_animal/mouse/Initialize()
. = ..()
AddComponent(/datum/component/squeak, list('sound/effects/mousesqueek.ogg'=1), 100)
if(!body_color)
body_color = pick( list("brown","gray","white") )
body_color = pick(list("brown","gray","white"))
AddElement(/datum/element/mob_holder, "mouse_[body_color]")
icon_state = "mouse_[body_color]"
icon_living = "mouse_[body_color]"
icon_dead = "mouse_[body_color]_dead"
can_be_held = "mouse_[body_color]"
/mob/living/simple_animal/mouse/proc/splat()
src.health = 0
@@ -89,17 +88,14 @@
/mob/living/simple_animal/mouse/white
body_color = "white"
icon_state = "mouse_white"
can_be_held = "mouse_white"
/mob/living/simple_animal/mouse/gray
body_color = "gray"
icon_state = "mouse_gray"
can_be_held = "mouse_gray"
/mob/living/simple_animal/mouse/brown
body_color = "brown"
icon_state = "mouse_brown"
can_be_held = "mouse_brown"
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_animal/mouse/brown/Tom
@@ -124,7 +120,3 @@
/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
reagents.clear_reagents()
/mob/living/simple_animal/mouse/generate_mob_holder()
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(src), src, (istext(can_be_held) ? can_be_held : ""), 'icons/mob/animals_held.dmi', 'icons/mob/animals_held_lh.dmi', 'icons/mob/animals_held_rh.dmi')
holder.w_class = WEIGHT_CLASS_TINY
return holder
@@ -22,9 +22,11 @@
maxHealth = 50
speed = 10
glide_size = 2
can_be_held = "sloth" //finally oranges can be held
do_footstep = TRUE
/mob/living/simple_animal/pet/fox/ComponentInitialize()
. = ..()
AddElement(/datum/element/mob_holder, "sloth") //finally oranges can be held
//Cargo Sloth
/mob/living/simple_animal/sloth/paperwork
@@ -432,6 +432,7 @@ Difficulty: Very Hard
H.dropItemToGround(W)
var/datum/job/clown/C = new /datum/job/clown()
C.equip(H)
C.after_spawn(H, H, TRUE)
qdel(C)
affected_targets.Add(H)
@@ -197,8 +197,6 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
return 0
return ..()
/mob/living/simple_animal/hostile/mimic/copy/ranged
var/obj/item/gun/TrueGun = null
var/obj/item/gun/magic/Zapstick
@@ -229,14 +227,13 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
casingtype = initial(M.ammo_type)
if(istype(G, /obj/item/gun/energy))
Zapgun = G
var/selectfiresetting = Zapgun.select
var/obj/item/ammo_casing/energy/E = Zapgun.ammo_type[selectfiresetting]
var/obj/item/ammo_casing/energy/E = Zapgun.ammo_type[Zapgun.current_firemode_index]
projectiletype = initial(E.projectile_type)
/mob/living/simple_animal/hostile/mimic/copy/ranged/OpenFire(the_target)
if(Zapgun)
if(Zapgun.cell)
var/obj/item/ammo_casing/energy/shot = Zapgun.ammo_type[Zapgun.select]
var/obj/item/ammo_casing/energy/shot = Zapgun.ammo_type[Zapgun.current_firemode_index]
if(Zapgun.cell.charge >= shot.e_cost)
Zapgun.cell.use(shot.e_cost)
Zapgun.update_icon()
@@ -131,7 +131,7 @@
/obj/item/projectile/temp/basilisk/magmawing/on_hit(atom/target, blocked = FALSE)
. = ..()
if(.)
if(. && isliving(target))
var/mob/living/L = target
if (istype(L))
L.adjust_fire_stacks(0.1)
@@ -144,7 +144,7 @@
/obj/item/projectile/temp/basilisk/icewing/on_hit(atom/target, blocked = FALSE)
. = ..()
if(.)
if(. && isliving(target))
var/mob/living/L = target
L.apply_status_effect(/datum/status_effect/freon/watcher)
@@ -62,8 +62,9 @@
/mob/living/simple_animal/hostile/asteroid/elite/herald/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
. = ..()
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
if(.)
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 20, TRUE)
/datum/action/innate/elite_attack/herald_trishot
name = "Triple Shot"
button_icon_state = "herald_trishot"
+4 -6
View File
@@ -321,20 +321,18 @@ mob/visible_message(message, self_message, blind_message, vision_distance = DEFA
set name = "Examine"
set category = "IC"
if(!client)
return
if(!(SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A) & COMPONENT_ALLOW_EXAMINE) && ((client.eye != src && client.eye != loc) || (isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src)))))
//cameras & co don't allow users to examine far away things, also shift-click catcher may issue examinate() calls for out-of-sight turfs
if(isturf(A) && !(sight & SEE_TURFS) && !(A in view(client ? client.view : world.view, src)))
// shift-click catcher may issue examinate() calls for out-of-sight turfs
return
if(is_blind(src))
to_chat(src, "<span class='notice'>Something is there but you can't see it.</span>")
to_chat(src, "<span class='warning'>Something is there but you can't see it!</span>")
return
face_atom(A)
var/list/result = A.examine(src)
to_chat(src, result.Join("\n"))
SEND_SIGNAL(src, COMSIG_MOB_EXAMINATE, A)
//same as above
//note: ghosts can point, this is intended
+12
View File
@@ -402,6 +402,18 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return
return TRUE
/proc/canGhostWrite(var/mob/A, var/obj/target, var/desc="", var/allow_all=FALSE)
if(allow_all & TRUE)
if(!target.GetComponent(/datum/component/anti_magic))
return 1
if(IsAdminGhost(A))
if (desc != "")
log_admin("GHOST: [key_name(A)] [desc] ([target.name] at [loc_name(target)])")
else
log_admin("GHOST: [key_name(A)] fucked with the [target.name] at [loc_name(target)]")
return 1
return 0
/proc/offer_control(mob/M)
to_chat(M, "Control of your mob has been offered to dead players.")
if(usr)
@@ -12,4 +12,4 @@
/obj/item/ammo_casing/energy/plasma/weak
projectile_type = /obj/item/projectile/plasma/weak
e_cost = 100
e_cost = 100
@@ -5,6 +5,10 @@
e_cost = 200
harmful = FALSE
/obj/item/ammo_casing/energy/electrode/security
projectile_type = /obj/item/projectile/energy/electrode/security
e_cost = 100
/obj/item/ammo_casing/energy/electrode/spec
e_cost = 100
@@ -13,6 +17,7 @@
e_cost = 100
/obj/item/ammo_casing/energy/electrode/hos
projectile_type = /obj/item/projectile/energy/electrode/security/hos
e_cost = 200
/obj/item/ammo_casing/energy/electrode/old
@@ -27,4 +32,4 @@
click_cooldown_override = 3.5
/obj/item/ammo_casing/energy/disabler/secborg
e_cost = 50
e_cost = 50
@@ -13,7 +13,7 @@
name = "magpistol magazine (non-lethal disabler)"
icon_state = "smallmagmag"
ammo_type = /obj/item/ammo_casing/caseless/magnetic/weak/disabler
max_ammo = 15
max_ammo = 16
/obj/item/ammo_box/magazine/mmag/small/lethal
name = "magpistol magazine (lethal)"
+85 -70
View File
@@ -28,10 +28,19 @@
trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers
var/sawn_desc = null //description change if weapon is sawn-off
var/sawn_off = FALSE
var/burst_size = 1 //how large a burst is
var/fire_delay = 0 //rate of fire for burst firing and semi auto
var/firing_burst = 0 //Prevent the weapon from firing again while already firing
var/semicd = 0 //cooldown handler
/// Weapon is burst fire if this is above 1
var/burst_size = 1
/// The time between shots in burst.
var/burst_shot_delay = 3
/// The time between firing actions, this means between bursts if this is burst weapon. The reason this is 0 is because you are still, by default, limited by clickdelay.
var/fire_delay = 0
/// Last world.time this was fired
var/last_fire = 0
/// Currently firing, whether or not it's a burst or not.
var/firing = FALSE
/// Used in gun-in-mouth execution/suicide and similar, while TRUE nothing should work on this like firing or modification and so on and so forth.
var/busy_action = FALSE
var/weapon_weight = WEAPON_LIGHT //currently only used for inaccuracy
var/spread = 0 //Spread induced by the gun itself.
var/burst_spread = 0 //Spread induced by the gun itself during burst fire per iteration. Only checked if spread is 0.
@@ -77,10 +86,14 @@
azoom = new (src)
/obj/item/gun/Destroy()
QDEL_NULL(pin)
QDEL_NULL(gun_light)
QDEL_NULL(bayonet)
QDEL_NULL(chambered)
if(pin)
QDEL_NULL(pin)
if(gun_light)
QDEL_NULL(gun_light)
if(bayonet)
QDEL_NULL(bayonet)
if(chambered)
QDEL_NULL(chambered)
return ..()
/obj/item/gun/CheckParts(list/parts_list)
@@ -117,13 +130,12 @@
to_chat(user, "<span class='danger'>*click*</span>")
playsound(src, "gun_dry_fire", 30, 1)
/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
if(recoil)
shake_camera(user, recoil + 1, recoil)
if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
user.adjustStaminaLossBuffered(getstamcost(user)*(firing_burst && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
if(suppressed)
playsound(user, fire_sound, 10, 1)
@@ -143,9 +155,12 @@
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
process_afterattack(target, user, flag, params)
/obj/item/gun/proc/process_afterattack(atom/target, mob/living/user, flag, params)
if(!target)
return
if(firing_burst)
if(firing)
return
if(flag) //It's adjacent, is the user, or is on the user's person
if(target in user.contents) //can't shoot stuff inside us.
@@ -169,7 +184,6 @@
handle_suicide(user, target, params)
return
//Exclude lasertag guns from the TRAIT_CLUMSY check.
if(clumsy_check)
if(istype(user))
@@ -201,8 +215,6 @@
process_fire(target, user, TRUE, params, null, bonus_spread)
/obj/item/gun/can_trigger_gun(mob/living/user)
. = ..()
if(!.)
@@ -227,54 +239,29 @@
/obj/item/gun/proc/recharge_newshot()
return
/obj/item/gun/proc/process_burst(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!user || !firing_burst)
firing_burst = FALSE
return FALSE
if(!issilicon(user))
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
firing_burst = FALSE
return FALSE
if(chambered && chambered.BB)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
if(chambered.harmful) // Is the bullet chambered harmful?
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
return
if(randomspread)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread), 1)
else //Smart spread
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
before_firing(target,user)
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
shoot_with_empty_chamber(user)
firing_burst = FALSE
return FALSE
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
shoot_live_shot(user, 1, target, message)
else
shoot_live_shot(user, 0, target, message)
if (iteration >= burst_size)
firing_burst = FALSE
else
shoot_with_empty_chamber(user)
firing_burst = FALSE
return FALSE
process_chamber()
update_icon()
return TRUE
/obj/item/gun/proc/on_cooldown()
return busy_action || firing || ((last_fire + fire_delay) > world.time)
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
add_fingerprint(user)
if(semicd)
if(on_cooldown())
return
firing = TRUE
. = do_fire(target, user, message, params, zone_override, bonus_spread)
firing = FALSE
last_fire = world.time
if(user)
user.update_inv_hands()
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
var/sprd = 0
var/randomized_gun_spread = 0
var/rand_spr = rand()
if(spread)
randomized_gun_spread = rand(0, spread)
randomized_gun_spread = rand(0, spread)
else if(burst_size > 1 && burst_spread)
randomized_gun_spread = rand(0, burst_spread)
if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex
@@ -282,9 +269,12 @@
var/randomized_bonus_spread = rand(0, bonus_spread)
if(burst_size > 1)
firing_burst = TRUE
for(var/i = 1 to burst_size)
addtimer(CALLBACK(src, .proc/process_burst, user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i), fire_delay * (i - 1))
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, 1)
for(var/i in 2 to burst_size)
sleep(burst_shot_delay)
if(QDELETED(src))
break
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i)
else
if(chambered)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
@@ -302,21 +292,46 @@
return
process_chamber()
update_icon()
semicd = TRUE
addtimer(CALLBACK(src, .proc/reset_semicd), fire_delay)
if(user)
user.update_inv_hands()
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
return TRUE
/obj/item/gun/update_icon()
..()
/obj/item/gun/proc/reset_semicd()
semicd = FALSE
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!user || !firing)
firing = FALSE
return FALSE
if(!issilicon(user))
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
firing = FALSE
return FALSE
if(chambered && chambered.BB)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
if(chambered.harmful) // Is the bullet chambered harmful?
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
return
if(randomspread)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread), 1)
else //Smart spread
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
before_firing(target,user)
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
shoot_with_empty_chamber(user)
firing = FALSE
return FALSE
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
shoot_live_shot(user, 1, target, message)
else
shoot_live_shot(user, 0, target, message)
if (iteration >= burst_size)
firing = FALSE
else
shoot_with_empty_chamber(user)
firing = FALSE
return FALSE
process_chamber()
update_icon()
return TRUE
/obj/item/gun/attack(mob/M as mob, mob/user)
if(user.a_intent == INTENT_HARM) //Flogging
@@ -437,7 +452,7 @@
if(!ishuman(user) || !ishuman(target))
return
if(semicd)
if(on_cooldown())
return
if(user == target)
@@ -447,7 +462,7 @@
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
semicd = TRUE
busy_action = TRUE
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
if(user)
@@ -455,10 +470,10 @@
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
else if(target && target.Adjacent(user))
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
semicd = FALSE
busy_action = FALSE
return
semicd = FALSE
busy_action = FALSE
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
@@ -5,7 +5,7 @@
var/automatic_burst_overlay = TRUE
can_suppress = TRUE
burst_size = 3
fire_delay = 2
burst_shot_delay = 2
actions_types = list(/datum/action/item_action/toggle_firemode)
/obj/item/gun/ballistic/automatic/proto
@@ -77,11 +77,9 @@
/obj/item/gun/ballistic/automatic/proc/enable_burst()
burst_size = initial(burst_size)
fire_delay = initial(fire_delay)
/obj/item/gun/ballistic/automatic/proc/disable_burst()
burst_size = 1
fire_delay = 0
/obj/item/gun/ballistic/automatic/can_shoot()
return get_ammo()
@@ -100,7 +98,7 @@
item_state = "c20r"
mag_type = /obj/item/ammo_box/magazine/smgm45
fire_sound = 'sound/weapons/gunshot_smg.ogg'
fire_delay = 2
burst_shot_delay = 2
burst_size = 2
pin = /obj/item/firing_pin/implant/pindicate
can_bayonet = TRUE
@@ -130,7 +128,7 @@
mag_type = /obj/item/ammo_box/magazine/wt550m9
can_suppress = FALSE
burst_size = 2
fire_delay = 1
burst_shot_delay = 1
can_bayonet = TRUE
knife_x_offset = 25
knife_y_offset = 12
@@ -165,7 +163,7 @@
can_suppress = FALSE
var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel
burst_size = 3
fire_delay = 2
burst_shot_delay = 2
pin = /obj/item/firing_pin/implant/pindicate
/obj/item/gun/ballistic/automatic/m90/Initialize()
@@ -212,7 +210,6 @@
if(0)
select = 1
burst_size = initial(burst_size)
fire_delay = initial(fire_delay)
to_chat(user, "<span class='notice'>You switch to [burst_size]-rnd burst.</span>")
if(1)
select = 2
@@ -220,7 +217,6 @@
if(2)
select = 0
burst_size = 1
fire_delay = 0
to_chat(user, "<span class='notice'>You switch to semi-auto.</span>")
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
update_icon()
@@ -237,7 +233,7 @@
fire_sound = 'sound/weapons/gunshot_smg.ogg'
can_suppress = FALSE
burst_size = 4
fire_delay = 1
burst_shot_delay = 1
/obj/item/gun/ballistic/automatic/ar
name = "\improper NT-ARG 'Boarder'"
@@ -249,7 +245,7 @@
fire_sound = 'sound/weapons/gunshot_smg.ogg'
can_suppress = FALSE
burst_size = 3
fire_delay = 1
burst_shot_delay = 1
// Bulldog shotgun //
@@ -264,7 +260,6 @@
fire_sound = 'sound/weapons/gunshot.ogg'
can_suppress = FALSE
burst_size = 1
fire_delay = 0
pin = /obj/item/firing_pin/implant/pindicate
actions_types = list()
@@ -301,7 +296,7 @@
var/cover_open = FALSE
can_suppress = FALSE
burst_size = 3
fire_delay = 1
burst_shot_delay = 1
spread = 7
pin = /obj/item/firing_pin/implant/pindicate
@@ -421,7 +416,7 @@
mag_type = /obj/item/ammo_box/magazine/recharge
fire_delay = 2
can_suppress = FALSE
burst_size = 0
burst_size = 1
actions_types = list()
fire_sound = 'sound/weapons/laser.ogg'
casing_ejector = FALSE
+138 -40
View File
@@ -1,3 +1,16 @@
/*
* Energy guns that draw from a cell to fire.
*
* This is a bit weird but this is how it currently works:
* When switching shots, it clears the chamber, and loads the correct energy ammo casing if there is enough energy to fire it.
* If there's no projectile in the casing, it creates it now.
* Otherwise the chamber stays null.
* After firing, it actually deducts the energy and then clears the chamber and does the above again.
* It detects if a successful fire is done by checking if the chambered energy ammo casing still has its projectile intact.
*
* It might be good in the future to move away from ammo casinsgs and instead use a datum-firemode system, but that would make handling firing,
* which the casing does as of now, a little interesting to implement.
*/
/obj/item/gun/energy
icon_state = "energy"
name = "energy gun"
@@ -7,8 +20,10 @@
var/obj/item/stock_parts/cell/cell //What type of power cell this uses
var/cell_type = /obj/item/stock_parts/cell
var/modifystate = 0
var/list/ammo_type = list(/obj/item/ammo_casing/energy)
var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next.
/// = TRUE/FALSE decides if the user can switch to it of their own accord
var/list/ammo_type = list(/obj/item/ammo_casing/energy = TRUE)
/// The index of the ammo_types/firemodes which we're using right now
var/current_firemode_index = 1
var/can_charge = 1 //Can it be charged in a recharger?
var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_icon()?
var/charge_sections = 4
@@ -21,6 +36,9 @@
var/use_cyborg_cell = FALSE //whether the gun drains the cyborg user's cell instead, not to be confused with EGUN_SELFCHARGE_BORG
var/dead_cell = FALSE //set to true so the gun is given an empty cell
/// SET THIS TO TRUE IF YOU OVERRIDE altafterattack() or ANY right click action! If this is FALSE, the gun will show in examine its default right click behavior, which is to switch modes.
var/right_click_overridden = FALSE
/obj/item/gun/energy/emp_act(severity)
. = ..()
if(!(. & EMP_PROTECT_CONTENTS))
@@ -46,22 +64,18 @@
START_PROCESSING(SSobj, src)
update_icon()
/obj/item/gun/energy/proc/update_ammo_types()
var/obj/item/ammo_casing/energy/shot
for (var/i = 1, i <= ammo_type.len, i++)
var/shottype = ammo_type[i]
shot = new shottype(src)
ammo_type[i] = shot
shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
/obj/item/gun/energy/Destroy()
QDEL_NULL(cell)
QDEL_LIST(ammo_type)
STOP_PROCESSING(SSobj, src)
if(flags_1 & INITIALIZED_1)
QDEL_NULL(cell)
QDEL_LIST(ammo_type)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/gun/energy/examine(mob/user)
. = ..()
if(!right_click_overridden)
. += "<span class='notice'>Right click in combat mode to switch modes.</span>"
/obj/item/gun/energy/process()
if(selfcharge && cell?.charge < cell.maxcharge)
charge_tick++
@@ -82,13 +96,14 @@
recharge_newshot(TRUE)
update_icon()
/obj/item/gun/energy/attack_self(mob/living/user as mob)
if(ammo_type.len > 1)
// ATTACK SELF IGNORING PARENT RETURN VALUE
/obj/item/gun/energy/attack_self(mob/living/user)
. = ..()
if(can_select_fire(user))
select_fire(user)
update_icon()
/obj/item/gun/energy/can_shoot()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
return !QDELETED(cell) ? (cell.charge >= shot.e_cost) : FALSE
/obj/item/gun/energy/recharge_newshot(no_cyborg_drain)
@@ -98,11 +113,11 @@
if(iscyborg(loc))
var/mob/living/silicon/robot/R = loc
if(R.cell)
var/obj/item/ammo_casing/energy/shot = ammo_type[select] //Necessary to find cost of shot
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] //Necessary to find cost of shot
if(R.cell.use(shot.e_cost)) //Take power from the borg...
cell.give(shot.e_cost) //... to recharge the shot
if(!chambered)
var/obj/item/ammo_casing/energy/AC = ammo_type[select]
var/obj/item/ammo_casing/energy/AC = ammo_type[current_firemode_index]
if(cell.charge >= AC.e_cost) //if there's enough power in the cell cell...
chambered = AC //...prepare a new shot based on the current ammo type selected
if(!chambered.BB)
@@ -115,29 +130,104 @@
chambered = null //either way, released the prepared shot
recharge_newshot() //try to charge a new shot
/obj/item/gun/energy/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
/obj/item/gun/energy/do_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
if(!chambered && can_shoot())
process_chamber() // If the gun was drained and then recharged, load a new shot.
return ..()
/obj/item/gun/energy/process_burst(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!chambered && can_shoot())
process_chamber() // Ditto.
return ..()
/obj/item/gun/energy/proc/select_fire(mob/living/user)
select++
if (select > ammo_type.len)
select = 1
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
if (shot.select_name)
to_chat(user, "<span class='notice'>[src] is now set to [shot.select_name].</span>")
chambered = null
recharge_newshot(TRUE)
// Firemodes/Ammotypes
/obj/item/gun/energy/proc/update_ammo_types()
var/obj/item/ammo_casing/energy/C
for(var/i in 1 to length(ammo_type))
var/v = ammo_type[i]
var/user_can_select = ammo_type[v]
if(istype(v, /obj/item/ammo_casing/energy)) //already set
ammo_type[v] = isnull(user_can_select)? TRUE : user_can_select
else
C = new v //if you put non energycasing/type stuff in here you deserve the runtime
ammo_type[i] = C
ammo_type[C] = isnull(user_can_select)? TRUE : user_can_select
set_firemode_index(initial(current_firemode_index))
/obj/item/gun/energy/proc/set_firemode_index(index, mob/user_for_feedback)
chambered = null //unchamber whatever we have chambered
if(index > length(ammo_type))
index = 1
else if(index < 1)
index = length(ammo_type)
var/obj/item/ammo_casing/energy/C = ammo_type[index] //energy weapons should not have no casings, if it does you deserve the runtime.
current_firemode_index = index
fire_sound = C.fire_sound
fire_delay = C.delay
if(user_for_feedback)
to_chat(user_for_feedback, "<span class='notice'>[src] is now set to [C.select_name || C].</span>")
post_set_firemode()
update_icon(TRUE)
return
/obj/item/gun/energy/proc/post_set_firemode(recharge_newshot = TRUE)
if(recharge_newshot)
recharge_newshot(TRUE)
/obj/item/gun/energy/proc/set_firemode_to_next(mob/user_for_feedback)
return set_firemode_index(++current_firemode_index, user_for_feedback)
/obj/item/gun/energy/proc/set_firemode_to_prev(mob/user_for_feedback)
return set_firemode_index(--current_firemode_index, user_for_feedback)
/obj/item/gun/energy/proc/get_firemode_index(casing_type)
var/obj/item/ammo_casing/energy/E = locate(casing_type) in ammo_type
if(E)
return ammo_type.Find(E)
/obj/item/gun/energy/proc/set_firemode_to_type(casing_type)
var/index = get_firemode_index(casing_type)
if(index)
set_firemode_index(index)
/// This is the proc used in general for when a user switches firemodes. Just goes to next firemode by default.
/obj/item/gun/energy/proc/select_fire(mob/living/user)
return user_set_firemode_to_next(user)
/obj/item/gun/energy/proc/can_select_fire(mob/living/user)
return TRUE
#define INCREMENT_OR_WRAP(i) i = (i >= length(ammo_type))? 1 : (i + 1)
#define DECREMENT_OR_WRAP(i) i = (i <= 1)? length(ammo_type) : (i - 1)
#define IS_VALID_INDEX(i) (ammo_type[ammo_type[i]])
/obj/item/gun/energy/proc/user_set_firemode_to_next(mob/user_for_feedback)
var/current_index = current_firemode_index
var/new_index = current_index
INCREMENT_OR_WRAP(new_index)
if(!IS_VALID_INDEX(new_index))
var/initial_index = new_index
while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
new_index = INCREMENT_OR_WRAP(new_index)
if(initial_index == new_index) //cycled through without finding another
new_index = current_index
set_firemode_index(new_index, user_for_feedback)
/obj/item/gun/energy/proc/user_set_firemode_to_prev(mob/user_for_feedback)
var/current_index = current_firemode_index
var/new_index = current_index
DECREMENT_OR_WRAP(new_index)
if(!IS_VALID_INDEX(new_index))
var/initial_index = new_index
while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
new_index = DECREMENT_OR_WRAP(new_index)
if(initial_index == new_index) //cycled through without finding another
new_index = current_index
set_firemode_index(new_index, user_for_feedback)
#undef INCREMENT_OR_WRAP
#undef DECREMENT_OR_WRAP
#undef IS_VALID_INDEX
/obj/item/gun/energy/update_icon(force_update)
if(QDELETED(src))
@@ -157,7 +247,7 @@
if(!initial(item_state))
itemState = icon_state
if (modifystate)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
add_overlay("[icon_state]_[shot.select_name]")
iconState += "_[shot.select_name]"
if(itemState)
@@ -176,6 +266,9 @@
if(itemState)
itemState += "[ratio]"
item_state = itemState
if(ismob(loc)) //forces inhands to update
var/mob/M = loc
M.update_inv_hands()
/obj/item/gun/energy/suicide_act(mob/living/user)
if (istype(user) && can_shoot() && can_trigger_gun(user) && user.get_bodypart(BODY_ZONE_HEAD))
@@ -185,7 +278,7 @@
user.visible_message("<span class='suicide'>[user] melts [user.p_their()] face off with [src]!</span>")
playsound(loc, fire_sound, 50, 1, -1)
playsound(src, 'sound/weapons/dink.ogg', 30, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
cell.use(shot.e_cost)
update_icon()
return(FIRELOSS)
@@ -207,13 +300,12 @@
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/gun/energy/ignition_effect(atom/A, mob/living/user)
if(!can_shoot() || !ammo_type[select])
if(!can_shoot() || !ammo_type[current_firemode_index])
shoot_with_empty_chamber()
. = ""
else
var/obj/item/ammo_casing/energy/E = ammo_type[select]
var/obj/item/ammo_casing/energy/E = ammo_type[current_firemode_index]
var/obj/item/projectile/energy/BB = E.BB
if(!BB)
. = ""
@@ -235,3 +327,9 @@
playsound(user, BB.hitsound, 50, 1)
cell.use(E.e_cost)
. = "<span class='danger'>[user] casually lights their [A.name] with [src]. Damn.</span>"
/obj/item/gun/energy/altafterattack(atom/target, mob/user, proximity_flags, params)
if(!right_click_overridden)
select_fire(user)
return TRUE
return ..()
@@ -97,7 +97,7 @@
pin = null
can_charge = 0
ammo_x_offset = 1
ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser)
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser)
selfcharge = EGUN_SELFCHARGE
var/fail_tick = 0
var/fail_chance = 0
@@ -113,18 +113,21 @@
..()
/obj/item/gun/energy/e_gun/nuclear/proc/failcheck()
if(prob(fail_chance) && isliving(loc))
var/mob/living/M = loc
if(prob(fail_chance))
switch(fail_tick)
if(0 to 200)
fail_tick += (2*(fail_chance))
M.rad_act(400)
to_chat(M, "<span class='userdanger'>Your [name] feels warmer.</span>")
radiation_pulse(src, 50)
var/mob/M = (ismob(loc) && loc) || (ismob(loc.loc) && loc.loc) //thank you short circuiting. if you powergame and nest these guns deeply you get to suffer no-warning radiation death.
if(M)
to_chat(M, "<span class='userdanger'>Your [name] feels warmer.</span>")
if(201 to INFINITY)
SSobj.processing.Remove(src)
M.rad_act(800)
crit_fail = 1
to_chat(M, "<span class='userdanger'>Your [name]'s reactor overloads!</span>")
radiation_pulse(src, 200)
crit_fail = TRUE
var/mob/M = (ismob(loc) && loc) || (ismob(loc.loc) && loc.loc)
if(M)
to_chat(M, "<span class='userdanger'>Your [name]'s reactor overloads!</span>")
/obj/item/gun/energy/e_gun/nuclear/emp_act(severity)
. = ..()
@@ -202,7 +202,7 @@
if(!ishuman(user) || !ishuman(target))
return
if(semicd)
if(on_cooldown())
return
if(user == target)
@@ -212,7 +212,7 @@
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
semicd = TRUE
busy_action = TRUE
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
if(user)
@@ -220,10 +220,10 @@
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
else if(target && target.Adjacent(user))
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
semicd = FALSE
busy_action = FALSE
return
semicd = FALSE
busy_action = FALSE
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
@@ -36,7 +36,7 @@
/obj/item/gun/energy/decloner/update_icon()
..()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(!QDELETED(cell) && (cell.charge > shot.e_cost))
add_overlay("decloner_spin")
@@ -185,7 +185,7 @@
var/atmos_link = FALSE
/obj/item/gun/energy/wormhole_projector/update_icon()
icon_state = "[initial(icon_state)][select]"
icon_state = "[initial(icon_state)][current_firemode_index]"
item_state = icon_state
/obj/item/gun/energy/wormhole_projector/update_ammo_types()
@@ -320,7 +320,7 @@
/obj/item/gun/energy/emitter/update_icon()
..()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(!QDELETED(cell) && (cell.charge > shot.e_cost))
add_overlay("emitter_carbine_empty")
else
+15 -2
View File
@@ -18,10 +18,23 @@
/obj/item/gun/energy/e_gun/advtaser
name = "hybrid taser"
desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams."
desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams. <span class='boldnotice'>Right click in combat mode to fire a taser shot with a cooldown.</span>"
icon_state = "advtaser"
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode)
ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode/security = FALSE)
ammo_x_offset = 2
// Not enough guns have altfire systems like this yet for this to be a universal framework.
var/last_altfire = 0
var/altfire_delay = 15
/obj/item/gun/energy/e_gun/advtaser/altafterattack(atom/target, mob/user, proximity_flag, params)
. = TRUE
if(last_altfire + altfire_delay > world.time)
return
var/current_index = current_firemode_index
set_firemode_to_type(/obj/item/ammo_casing/energy/electrode)
process_afterattack(target, user, proximity_flag, params)
set_firemode_index(current_index)
last_altfire = world.time
/obj/item/gun/energy/e_gun/advtaser/cyborg
name = "cyborg taser"
@@ -43,6 +43,7 @@
var/lastangle = 0
var/aiming_lastangle = 0
var/last_aimbeam = 0
var/mob/current_user = null
var/list/obj/effect/projectile/tracer/current_tracers
@@ -186,8 +187,9 @@
/obj/item/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE)
var/diff = abs(aiming_lastangle - lastangle)
check_user()
if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update)
if(!check_user())
return
if(((diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD) || ((last_aimbeam + 1) > world.time)) && !force_update)
return
aiming_lastangle = lastangle
var/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/P = new
@@ -208,6 +210,7 @@
targloc = get_turf_in_angle(lastangle, curloc, 10)
P.preparePixelProjectile(targloc, current_user, current_user.client.mouseParams, 0)
P.fire(lastangle)
last_aimbeam = world.time
/obj/item/gun/energy/beam_rifle/process()
if(!aiming)
@@ -296,27 +299,17 @@
if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher))
return
process_aim()
if(aiming_time_left <= aiming_time_fire_threshold && check_user())
if(aiming_time_left <= aiming_time_fire_threshold && check_user() && ((lastfire + delay) <= world.time))
sync_ammo()
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
do_fire(M.client.mouseObject, M, FALSE, M.client.mouseParams, M.zone_selected)
stop_aiming()
QDEL_LIST(current_tracers)
return ..()
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
if(flag) //It's adjacent, is the user, or is on the user's person
if(target in user.contents) //can't shoot stuff inside us.
return
if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack
return
if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected)
return
if(!passthrough && (aiming_time > aiming_time_fire_threshold))
return
if(lastfire > world.time + delay)
return
lastfire = world.time
/obj/item/gun/energy/beam_rifle/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
. = ..()
if(.)
lastfire = world.time
stop_aiming()
/obj/item/gun/energy/beam_rifle/proc/sync_ammo()
@@ -2,11 +2,11 @@
name = "electrode"
icon_state = "spark"
color = "#FFFF00"
nodamage = 1
nodamage = TRUE
knockdown = 60
knockdown_stamoverride = 36
knockdown_stam_max = 50
stutter = 5
stutter = 10
jitter = 20
hitsound = 'sound/weapons/taserhit.ogg'
range = 7
@@ -14,6 +14,7 @@
muzzle_type = /obj/effect/projectile/muzzle/stun
impact_type = /obj/effect/projectile/impact/stun
var/tase_duration = 50
var/strong_tase = TRUE
/obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -26,10 +27,24 @@
C.IgniteMob()
if(C.dna && C.dna.check_mutation(HULK))
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
else if((C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
C.apply_status_effect(STATUS_EFFECT_TASED, tase_duration)
else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
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)
/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet
do_sparks(1, TRUE, src)
..()
/obj/item/projectile/energy/electrode/security
tase_duration = 30
knockdown = 0
stamina = 10
knockdown_stamoverride = 0
knockdown_stam_max = 0
strong_tase = FALSE
range = 12
/obj/item/projectile/energy/electrode/security/hos
knockdown = 100
knockdown_stamoverride = 30
knockdown_stam_max = null
@@ -216,6 +216,14 @@
..()
. = 1
/datum/reagent/medicine/rezadone/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
. = ..()
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.
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.")
/datum/reagent/medicine/spaceacillin
name = "Spaceacillin"
description = "Spaceacillin will prevent a patient from conventionally spreading any diseases they are currently infected with."
@@ -436,6 +444,10 @@ 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)
//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))
M.cure_husk("burn")
M.visible_message("<span class='nicegreen'>Most of [M]'s burnt off or charred flesh has been restored.")
..()
/datum/reagent/medicine/synthflesh/overdose_start(mob/living/M)
@@ -423,18 +423,21 @@
else
unload_hypo(vial,user)
/obj/item/hypospray/mkii/verb/modes()
set name = "Toggle Application Mode"
set category = "Object"
set src in usr
var/mob/M = usr
switch(mode)
if(HYPO_SPRAY)
mode = HYPO_INJECT
to_chat(M, "[src] is now set to inject contents on application.")
if(HYPO_INJECT)
mode = HYPO_SPRAY
to_chat(M, "[src] is now set to spray contents on application.")
/obj/item/hypospray/mkii/AltClick(mob/living/user)
. = ..()
if(user.canUseTopic(src, FALSE))
switch(mode)
if(HYPO_SPRAY)
mode = HYPO_INJECT
to_chat(user, "[src] is now set to inject contents on application.")
if(HYPO_INJECT)
mode = HYPO_SPRAY
to_chat(user, "[src] is now set to spray contents on application.")
return TRUE
/obj/item/hypospray/mkii/examine(mob/user)
. = ..()
. += "<span class='notice'><b>Alt-Click</b> it to toggle its mode from spraying to injecting and vice versa.</span>"
#undef HYPO_SPRAY
#undef HYPO_INJECT
@@ -1,11 +1,11 @@
///////////////////////////////////
//////////Autolathe Designs ///////
//////////Autolathe Designs////////
///////////////////////////////////
////////////////
///Construction//
////////////////
//////////////////
///Construction///
//////////////////
/datum/design/rods
name = "Metal Rod"
@@ -1,8 +1,8 @@
///////////////////////////////////
//////////Autolathe Designs ///////
/////////Autolathe Designs/////////
///////////////////////////////////
///////////
///Tools //
///Tools///
///////////
/datum/design/bucket
name = "Bucket"
@@ -52,7 +52,8 @@
build_type = AUTOLATHE
materials = list(MAT_METAL = 50, MAT_GLASS = 20)
build_path = /obj/item/multitool
category = list("initial","Tools")
category = list("initial","Tools","Tool Designs")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/analyzer
name = "Analyzer"
@@ -250,10 +250,10 @@
name = "Plant Data Disk"
desc = "A disk for storing plant genetic data."
id = "diskplantgene"
build_type = PROTOLATHE
build_type = PROTOLATHE | AUTOLATHE
materials = list(MAT_METAL=200, MAT_GLASS=100)
build_path = /obj/item/disk/plantgene
category = list("Electronics")
category = list("Electronics","Imported")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
/datum/design/roastingstick
@@ -405,7 +405,7 @@
/datum/design/holosigncombifan
name = "ATMOS Holo-Combifan Projector"
desc = "A holographic projector that creates holographic barriesr that prevent changes in atmospheric and temperature conditions."
desc = "A holographic projector that creates holographic barriers that prevent changes in atmospheric and temperature conditions."
id = "holosigncombifan"
build_type = PROTOLATHE
materials = list(MAT_METAL = 7500, MAT_GLASS = 2500, MAT_SILVER = 2500, MAT_GOLD = 2500, MAT_TITANIUM = 1750)
@@ -2,7 +2,7 @@
name = "technology fabricator"
desc = "Makes researched and prototype items with materials and energy."
layer = BELOW_OBJ_LAYER
var/consoleless_interface = FALSE //Whether it can be used without a console.
var/consoleless_interface = TRUE //Whether it can be used without a console.
var/efficiency_coeff = 1 //Materials needed / coeff = actual.
var/list/categories = list()
var/datum/component/remote_materials/materials
@@ -4,10 +4,9 @@
icon_state = "circuit_imprinter"
circuit = /obj/item/circuitboard/machine/circuit_imprinter/department
requires_console = FALSE
consoleless_interface = TRUE
/obj/machinery/rnd/production/circuit_imprinter/department/science
name = "department circuit imprinter (Science)"
circuit = /obj/item/circuitboard/machine/circuit_imprinter/department/science
allowed_department_flags = DEPARTMENTAL_FLAG_ALL|DEPARTMENTAL_FLAG_SCIENCE
department_tag = "Science"
department_tag = "Science"
@@ -4,7 +4,6 @@
icon_state = "protolathe"
circuit = /obj/item/circuitboard/machine/protolathe/department
requires_console = FALSE
consoleless_interface = TRUE
/obj/machinery/rnd/production/protolathe/department/engineering
name = "department protolathe (Engineering)"
@@ -40,4 +39,4 @@
name = "department protolathe (Security)"
allowed_department_flags = DEPARTMENTAL_FLAG_ALL|DEPARTMENTAL_FLAG_SECURITY
department_tag = "Security"
circuit = /obj/item/circuitboard/machine/protolathe/department/security
circuit = /obj/item/circuitboard/machine/protolathe/department/security
@@ -31,5 +31,4 @@
console_link = FALSE
production_animation = "protolathe_n"
requires_console = FALSE
consoleless_interface = TRUE
allowed_buildtypes = PROTOLATHE | IMPRINTER
+1 -1
View File
@@ -191,7 +191,7 @@
prereq_ids = list("base")
design_ids = list("solarcontrol", "recharger", "powermonitor", "rped", "pacman", "adv_capacitor", "adv_scanning", "emitter", "high_cell", "adv_matter_bin",
"atmosalerts", "atmos_control", "recycler", "autolathe", "high_micro_laser", "nano_mani", "mesons", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod",
"apc_control", "cell_charger", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine")
"apc_control", "cell_charger", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine", "rcd_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 6000)
export_price = 5000
@@ -102,6 +102,12 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE)
var/gun_type = pick(GLOB.summoned_guns)
var/obj/item/gun/G = new gun_type(get_turf(H))
G.unlock()
var/datum/antagonist/survivalist/guns/our_antag_datum = H.mind.has_antag_datum(/datum/antagonist/survivalist/guns)
if(our_antag_datum)
var/datum/objective/hoard/O = new()
O.owner = H
O.set_target(G)
our_antag_datum.objectives += O
playsound(get_turf(H),'sound/magic/summon_guns.ogg', 50, 1)
var/in_hand = H.put_in_hands(G) // not always successful
@@ -128,6 +134,13 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE)
var/obj/item/M = new magic_type(get_turf(H))
playsound(get_turf(H),'sound/magic/summon_magic.ogg', 50, 1)
var/datum/antagonist/survivalist/magic/our_antag_datum = H.mind.has_antag_datum(/datum/antagonist/survivalist/magic)
if(istype(our_antag_datum))
var/datum/objective/hoard/O = new()
O.owner = H
O.set_target(M)
our_antag_datum.objectives += O
var/in_hand = H.put_in_hands(M)
to_chat(H, "<span class='warning'>\A [M] appears [in_hand ? "in your hand" : "at your feet"]!</span>")
+1 -1
View File
@@ -51,7 +51,7 @@
clear_eye_trauma()
. = ..()
var/mob/living/carbon/C = .
if(C)
if(!QDELETED(C))
if(ishuman(C) && eye_color)
var/mob/living/carbon/human/H = C
H.eye_color = old_eye_color
@@ -78,3 +78,9 @@
cost = 30
include_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
exclude_modes = list()
/datum/uplink_item/suits/thiefgloves
name = "Thieving Gloves"
desc = "A pair of gloves that are insulated and frictionless, allowing you to steal easily from anyone you see."
item = /obj/item/clothing/gloves/thief
cost = 4
+4
View File
@@ -17,4 +17,8 @@
/obj/item/beacon = 2)
product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!"
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/assist
resistance_flags = FIRE_PROOF
/obj/item/vending_refill/assist
icon_state = "refill_engi"
+4
View File
@@ -14,4 +14,8 @@
/obj/item/cartridge/captain = 3,
/obj/item/cartridge/quartermaster = 10)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
refill_canister = /obj/item/vending_refill/cart
resistance_flags = FIRE_PROOF
/obj/item/vending_refill/cart
icon_state = "refill_pda"

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