Merge remote-tracking branch 'citadel/master' into mobility_flags
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
//It is called from your coffin on close (by you only)
|
||||
if(poweron_masquerade == TRUE || owner.current.AmStaked())
|
||||
return FALSE
|
||||
owner.current.adjustStaminaLoss(-2 + (regenRate * -8) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
|
||||
owner.current.adjustStaminaLoss(-1.5 + (regenRate * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
|
||||
owner.current.adjustCloneLoss(-0.1 * (regenRate * 2) * mult, 0)
|
||||
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (regenRate * 4) * mult) //adjustBrainLoss(-1 * (regenRate * 4) * mult, 0)
|
||||
// No Bleeding
|
||||
@@ -125,7 +125,7 @@
|
||||
C.adjustFireLoss(-fireheal * mult, forced = TRUE)
|
||||
C.adjustToxLoss(-toxinheal * mult * 2, forced = TRUE) //Toxin healing because vamps arent immune
|
||||
//C.heal_overall_damage(bruteheal * mult, fireheal * mult) // REMOVED: We need to FORCE this, because otherwise, vamps won't heal EVER. Swapped to above.
|
||||
AddBloodVolume((bruteheal * -0.5 + fireheal * -1) / mult * costMult) // Costs blood to heal
|
||||
AddBloodVolume((bruteheal * -0.5 + fireheal * -1 + toxinheal * -0.2) / mult * costMult) // Costs blood to heal
|
||||
return TRUE // Healed! Done for this tick.
|
||||
if(amInCoffinWhileTorpor) // Limbs? (And I have no other healing)
|
||||
var/list/missing = owner.current.get_missing_limbs() // Heal Missing
|
||||
@@ -189,7 +189,7 @@
|
||||
/datum/antagonist/bloodsucker/proc/HandleDeath()
|
||||
// FINAL DEATH
|
||||
// Fire Damage? (above double health)
|
||||
if(owner.current.getFireLoss_nonProsthetic() >= owner.current.getMaxHealth() * 1.5)
|
||||
if(owner.current.getFireLoss_nonProsthetic() >= owner.current.maxHealth * 2.5)
|
||||
FinalDeath()
|
||||
return
|
||||
// Staked while "Temp Death" or Asleep
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
//var/not_bloodsucker = FALSE // This goes to Vassals or Hunters, but NOT bloodsuckers.
|
||||
|
||||
/datum/action/bloodsucker/New()
|
||||
if (bloodcost > 0)
|
||||
if(bloodcost > 0)
|
||||
desc += "<br><br><b>COST:</b> [bloodcost] Blood" // Modify description to add cost.
|
||||
if (warn_constant_cost)
|
||||
if(warn_constant_cost)
|
||||
desc += "<br><br><i>Your over-time blood consumption increases while [name] is active.</i>"
|
||||
if (amSingleUse)
|
||||
if(amSingleUse)
|
||||
desc += "<br><br><i>Useable once per night.</i>"
|
||||
..()
|
||||
|
||||
@@ -47,35 +47,35 @@
|
||||
|
||||
/datum/action/bloodsucker/Trigger()
|
||||
// Active? DEACTIVATE AND END!
|
||||
if (active && CheckCanDeactivate(TRUE))
|
||||
if(active && CheckCanDeactivate(TRUE))
|
||||
DeactivatePower()
|
||||
return
|
||||
if (!CheckCanPayCost(TRUE) || !CheckCanUse(TRUE))
|
||||
if(!CheckCanPayCost(TRUE) || !CheckCanUse(TRUE))
|
||||
return
|
||||
PayCost()
|
||||
if (amToggle)
|
||||
if(amToggle)
|
||||
active = !active
|
||||
UpdateButtonIcon()
|
||||
if (!amToggle || !active)
|
||||
if(!amToggle || !active)
|
||||
StartCooldown() // Must come AFTER UpdateButton(), otherwise icon will revert.
|
||||
ActivatePower() // NOTE: ActivatePower() freezes this power in place until it ends.
|
||||
if (active) // Did we not manually disable? Handle it here.
|
||||
if(active) // Did we not manually disable? Handle it here.
|
||||
DeactivatePower()
|
||||
if (amSingleUse)
|
||||
if(amSingleUse)
|
||||
RemoveAfterUse()
|
||||
|
||||
/datum/action/bloodsucker/proc/CheckCanPayCost(display_error)
|
||||
if(!owner || !owner.mind)
|
||||
return FALSE
|
||||
// Cooldown?
|
||||
if (cooldownUntil > world.time)
|
||||
if (display_error)
|
||||
if(cooldownUntil > world.time)
|
||||
if(display_error)
|
||||
to_chat(owner, "[src] is unavailable. Wait [(cooldownUntil - world.time) / 10] seconds.")
|
||||
return FALSE
|
||||
// Have enough blood?
|
||||
var/mob/living/L = owner
|
||||
if (L.blood_volume < bloodcost)
|
||||
if (display_error)
|
||||
if(L.blood_volume < bloodcost)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You need at least [bloodcost] blood to activate [name]</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define TIME_BLOODSUCKER_NIGHT 900 // 15 minutes
|
||||
#define TIME_BLOODSUCKER_DAY_WARN 90 // 1.5 minutes
|
||||
#define TIME_BLOODSUCKER_DAY_FINAL_WARN 25 // 25 sec
|
||||
#define TIME_BLOODSUCKER_DAY 60 // 1.5 minutes // 10 is a second, 600 is a minute.
|
||||
@@ -11,6 +10,7 @@
|
||||
var/cancel_me = FALSE
|
||||
var/amDay = FALSE
|
||||
var/time_til_cycle = 0
|
||||
var/nightime_duration = 900 //15 Minutes
|
||||
|
||||
/obj/effect/sunlight/Initialize()
|
||||
countdown()
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
while(!cancel_me)
|
||||
|
||||
time_til_cycle = TIME_BLOODSUCKER_NIGHT
|
||||
time_til_cycle = nightime_duration
|
||||
|
||||
// Part 1: Night (all is well)
|
||||
while(time_til_cycle > TIME_BLOODSUCKER_DAY_WARN)
|
||||
@@ -81,7 +81,9 @@
|
||||
"<span class = 'announce'>The solar flare has ended, and the daylight danger has passed...for now.</span>")
|
||||
amDay = FALSE
|
||||
day_end() // Remove VANISHING ACT power from all vamps who have it! Clear Warnings (sunlight, locker protection)
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [TIME_BLOODSUCKER_NIGHT / 60] minutes.)")
|
||||
nightime_duration += 100 //Each day makes the night a minute longer.
|
||||
message_admins("BLOODSUCKER NOTICE: Daylight Ended. Resetting to Night (Lasts for [nightime_duration / 60] minutes.)")
|
||||
|
||||
|
||||
|
||||
/obj/effect/sunlight/proc/hud_tick()
|
||||
@@ -97,7 +99,7 @@
|
||||
sleep(10)
|
||||
time_til_cycle --
|
||||
|
||||
/obj/effect/sunlight/proc/warn_daylight(danger_level=0, vampwarn = "", vassalwarn = "")
|
||||
/obj/effect/sunlight/proc/warn_daylight(danger_level =0, vampwarn = "", vassalwarn = "")
|
||||
for(var/datum/mind/M in SSticker.mode.bloodsuckers)
|
||||
if(!istype(M))
|
||||
continue
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
// STATS
|
||||
var/vamplevel = 0
|
||||
var/vamplevel_unspent = 1
|
||||
var/regenRate = 0.3 // How many points of Brute do I heal per tick?
|
||||
var/regenRate = 0.4 // How many points of Brute do I heal per tick?
|
||||
var/feedAmount = 15 // Amount of blood drawn from a target per tick.
|
||||
var/maxBloodVolume = 600 // Maximum blood a Vamp can hold via feeding. // BLOOD_VOLUME_NORMAL 550 // BLOOD_VOLUME_SAFE 475 //BLOOD_VOLUME_OKAY 336 //BLOOD_VOLUME_BAD 224 // BLOOD_VOLUME_SURVIVE 122
|
||||
// OBJECTIVES
|
||||
@@ -34,6 +34,7 @@
|
||||
var/warn_sun_locker = FALSE // So we only get the locker burn message once per day.
|
||||
var/warn_sun_burn = FALSE // So we only get the sun burn message once per day.
|
||||
var/had_toxlover = FALSE
|
||||
var/level_bloodcost
|
||||
// LISTS
|
||||
var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_NIGHT_VISION, \
|
||||
TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_VIRUSIMMUNE)
|
||||
@@ -98,7 +99,7 @@
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/SelectFirstName()
|
||||
// Names (EVERYONE gets one))
|
||||
if (owner.current.gender == MALE)
|
||||
if(owner.current.gender == MALE)
|
||||
vampname = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \
|
||||
"Sveyn","Aurel","Alexe","Iustin","Theodor","Dimitrie","Octav","Damien","Magnus","Caine","Abel", // Romanian/Ancient
|
||||
"Lucius","Gaius","Otho","Balbinus","Arcadius","Romanos","Alexios","Vitellius", // Latin
|
||||
@@ -119,7 +120,7 @@
|
||||
return
|
||||
// Titles [Master]
|
||||
if (!am_fledgling)
|
||||
if (owner.current.gender == MALE)
|
||||
if(owner.current.gender == MALE)
|
||||
vamptitle = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master")
|
||||
else
|
||||
vamptitle = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress")
|
||||
@@ -130,18 +131,18 @@
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/SelectReputation(am_fledgling = 0, forced=FALSE)
|
||||
// Already have Reputation
|
||||
if (!forced && vampreputation != null)
|
||||
if(!forced && vampreputation != null)
|
||||
return
|
||||
// Reputations [Master]
|
||||
if (!am_fledgling)
|
||||
if(!am_fledgling)
|
||||
vampreputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \
|
||||
"Inqisitor","Harvester","Reviled","Robust","Betrayer","Destructor","Damned","Accursed","Terrible","Vicious","Profane","Vile","Depraved","Foul","Slayer","Manslayer","Sovereign","Slaughterer", \
|
||||
"Forsaken","Mad","Dragon","Savage","Villainous","Nefarious","Inquisitor","Marauder","Horrible","Immortal","Undying","Overlord","Corrupt","Hellspawn","Tyrant","Sanguineous")
|
||||
if (owner.current.gender == MALE)
|
||||
if (prob(10)) // Gender override
|
||||
if(owner.current.gender == MALE)
|
||||
if(prob(10)) // Gender override
|
||||
vampreputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King")
|
||||
else
|
||||
if (prob(10)) // Gender override
|
||||
if(prob(10)) // Gender override
|
||||
vampreputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen")
|
||||
|
||||
to_chat(owner, "<span class='announce'>You have earned a reputation! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
|
||||
@@ -202,7 +203,7 @@
|
||||
// Make Changes
|
||||
H.physiology.brute_mod *= 0.8 // <-------------------- Start small, but burn mod increases based on rank!
|
||||
H.physiology.cold_mod = 0
|
||||
H.physiology.stun_mod *= 0.35
|
||||
H.physiology.stun_mod *= 0.5
|
||||
H.physiology.siemens_coeff *= 0.75 //base electrocution coefficient 1
|
||||
//S.heatmod += 0.5 // Heat shouldn't affect. Only Fire.
|
||||
//S.punchstunthreshold = 8 //damage at which punches from this race will stun 9
|
||||
@@ -261,7 +262,7 @@
|
||||
owner.hasSoul = TRUE
|
||||
//owner.current.hellbound = FALSE
|
||||
|
||||
datum/antagonist/bloodsucker/proc/RankUp()
|
||||
/datum/antagonist/bloodsucker/proc/RankUp()
|
||||
set waitfor = FALSE
|
||||
if(!owner || !owner.current)
|
||||
return
|
||||
@@ -272,21 +273,23 @@ datum/antagonist/bloodsucker/proc/RankUp()
|
||||
else
|
||||
to_chat(owner, "<EM><span class='notice'>You have grown more ancient! Sleep in a coffin that you have claimed to thicken your blood and become more powerful.</span></EM>")
|
||||
if(vamplevel_unspent >= 2)
|
||||
to_chat(owner, "<span class='announce'>Bloodsucker Tip: If you cannot find or steal a coffin to use, they can be built from wooden planks.</span><br>")
|
||||
to_chat(owner, "<span class='announce'>Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wooden planks.</span><br>")
|
||||
|
||||
datum/antagonist/bloodsucker/proc/LevelUpPowers()
|
||||
/datum/antagonist/bloodsucker/proc/LevelUpPowers()
|
||||
for(var/datum/action/bloodsucker/power in powers)
|
||||
power.level_current ++
|
||||
|
||||
datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
/datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
set waitfor = FALSE
|
||||
if (vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client)
|
||||
if(vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current))
|
||||
return
|
||||
/////////
|
||||
// Powers
|
||||
//TODO: Make this into a radial
|
||||
var/mob/living/L = owner.current
|
||||
level_bloodcost = maxBloodVolume * 0.2
|
||||
//If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker
|
||||
|
||||
//TODO: Make this into a radial, or perhaps a tgui next UI
|
||||
// Purchase Power Prompt
|
||||
var/list/options = list() // Taken from gasmask.dm, for Clown Masks.
|
||||
var/list/options = list()
|
||||
for(var/pickedpower in typesof(/datum/action/bloodsucker))
|
||||
var/datum/action/bloodsucker/power = pickedpower
|
||||
// If I don't own it, and I'm allowed to buy it.
|
||||
@@ -295,7 +298,7 @@ datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
options["\[ Not Now \]"] = null
|
||||
// Abort?
|
||||
if(options.len > 1)
|
||||
var/choice = input(owner.current, "You have the opportunity to grow more ancient. Select a power to advance your Rank.", "Your Blood Thickens...") in options
|
||||
var/choice = input(owner.current, "You have the opportunity to grow more ancient at the cost of [level_bloodcost] units of blood. Select a power to advance your Rank.", "Your Blood Thickens...") in options
|
||||
// Cheat-Safety: Can't keep opening/closing coffin to spam levels
|
||||
if(vamplevel_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal.
|
||||
return
|
||||
@@ -305,10 +308,14 @@ datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
if(!choice || !options[choice] || (locate(options[choice]) in powers)) // ADDED: Check to see if you already have this power, due to window stacking.
|
||||
to_chat(owner.current, "<span class='notice'>You prevent your blood from thickening just yet, but you may try again later.</span>")
|
||||
return
|
||||
if(L.blood_volume < level_bloodcost)
|
||||
to_chat(owner.current, "<span class='warning'>You dont have enough blood to thicken your blood, you need [level_bloodcost - L.blood_volume] units more!</span>")
|
||||
return
|
||||
// Buy New Powers
|
||||
var/datum/action/bloodsucker/P = options[choice]
|
||||
AddBloodVolume(-level_bloodcost)
|
||||
BuyPower(new P)
|
||||
to_chat(owner.current, "<span class='notice'>You have learned [initial(P.name)]!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>You have used [level_bloodcost] units of blood and learned [initial(P.name)]!</span>")
|
||||
else
|
||||
to_chat(owner.current, "<span class='notice'>You grow more ancient by the night!</span>")
|
||||
/////////
|
||||
@@ -326,7 +333,7 @@ datum/antagonist/bloodsucker/proc/SpendRank()
|
||||
// Vamp Stats
|
||||
regenRate += 0.05 // Points of brute healed (starts at 0.3)
|
||||
feedAmount += 2 // Increase how quickly I munch down vics (15)
|
||||
maxBloodVolume += 50 // Increase my max blood (600)
|
||||
maxBloodVolume += 100 // Increase my max blood (600)
|
||||
/////////
|
||||
vamplevel ++
|
||||
vamplevel_unspent --
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
return SSticker.mode.make_vassal(C,owner)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/FreeAllVassals()
|
||||
for (var/datum/antagonist/vassal/V in vassals)
|
||||
for(var/datum/antagonist/vassal/V in vassals)
|
||||
SSticker.mode.remove_vassal(V.owner)
|
||||
|
||||
/datum/antagonist/vassal
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/datum/antagonist/vassal/can_be_owned(datum/mind/new_owner)
|
||||
// If we weren't created by a bloodsucker, then we cannot be a vassal (assigned from antag panel)
|
||||
if (!master)
|
||||
if(!master)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
/datum/antagonist/vassal/on_removal()
|
||||
SSticker.mode.vassals -= owner // Add if not already in here (and you might be, if you were picked at round start)
|
||||
// Mindslave Remove
|
||||
if (master && master.owner)
|
||||
if(master && master.owner)
|
||||
master.vassals -= src
|
||||
if (owner.enslaved_to == master.owner.current)
|
||||
if(owner.enslaved_to == master.owner.current)
|
||||
owner.enslaved_to = null
|
||||
// Master Pinpointer
|
||||
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer/vassal_edition)
|
||||
|
||||
@@ -60,6 +60,8 @@
|
||||
breakout_time = 600
|
||||
pryLidTimer = 400
|
||||
resistance_flags = NONE
|
||||
integrity_failure = 70
|
||||
armor = list("melee" = 50, "bullet" = 20, "laser" = 30, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
|
||||
|
||||
/obj/structure/closet/crate/coffin/meatcoffin
|
||||
name = "meat coffin"
|
||||
@@ -75,7 +77,9 @@
|
||||
resistance_flags = NONE
|
||||
material_drop = /obj/item/reagent_containers/food/snacks/meat/slab
|
||||
material_drop_amount = 3
|
||||
|
||||
integrity_failure = 40
|
||||
armor = list("melee" = 70, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 70, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 100)
|
||||
|
||||
/obj/structure/closet/crate/coffin/metalcoffin
|
||||
name = "metal coffin"
|
||||
desc = "A big metal sardine can inside of another big metal sardine can, in space."
|
||||
@@ -90,6 +94,8 @@
|
||||
resistance_flags = NONE
|
||||
material_drop = /obj/item/stack/sheet/metal
|
||||
material_drop_amount = 5
|
||||
integrity_failure = 60
|
||||
armor = list("melee" = 40, "bullet" = 15, "laser" = 50, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
var/convert_progress = 3 // Resets on each new character to be added to the chair. Some effects should lower it...
|
||||
var/disloyalty_confirm = FALSE // Command & Antags need to CONFIRM they are willing to lose their role (and will only do it if the Vassal'ing succeeds)
|
||||
var/disloyalty_offered = FALSE // Has the popup been issued? Don't spam them.
|
||||
var/convert_cost = 100
|
||||
|
||||
|
||||
/obj/structure/bloodsucker/vassalrack/deconstruct(disassembled = TRUE)
|
||||
new /obj/item/stack/sheet/metal(src.loc, 4)
|
||||
@@ -116,10 +116,10 @@
|
||||
|
||||
/obj/structure/bloodsucker/vassalrack/examine(mob/user)
|
||||
. = ..()
|
||||
if((user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) || isobserver(user))
|
||||
if(isvamp(user) || isobserver(user))
|
||||
. += {"<span class='cult'>This is the vassal rack, which allows you to thrall crewmembers into loyal minions in your service.</span>"}
|
||||
. += {"<span class='cult'>You need to first secure the vassal rack by clicking on it while it is in your lair.</span>"}
|
||||
. += {"<span class='cult'>Simply click and hold on a victim, and then drag their sprite on the vassal rack.</span>"}
|
||||
. += {"<span class='cult'>Simply click and hold on a victim, and then drag their sprite on the vassal rack. Alt click on the vassal rack to unbuckle them.</span>"}
|
||||
. += {"<span class='cult'>Make sure that the victim is handcuffed, or else they can simply run away or resist, as the process is not instant.</span>"}
|
||||
. += {"<span class='cult'>To convert the victim, simply click on the vassal rack itself. Sharp weapons work faster than other tools.</span>"}
|
||||
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
|
||||
@@ -177,7 +177,7 @@
|
||||
M.pixel_y = -2 //M.get_standard_pixel_y_offset(120)//180)
|
||||
update_icon()
|
||||
// Torture Stuff
|
||||
convert_progress = 2 // Goes down unless you start over.
|
||||
convert_progress = 4 // Goes down unless you start over.
|
||||
disloyalty_confirm = FALSE // New guy gets the chance to say NO if he's special.
|
||||
disloyalty_offered = FALSE // Prevents spamming torture window.
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
else
|
||||
M.visible_message("<span class='danger'>[user] tries to pull [M] rack!</span>",\
|
||||
"<span class='danger'>[user] attempts to release you from the rack!</span>") // For sound if not seen --> "<span class='italics'>You hear a squishy wet noise.</span>")
|
||||
if(!do_mob(user, M, 100))
|
||||
if(!do_mob(user, M, 200))
|
||||
return
|
||||
// Did the time. Now try to do it.
|
||||
..()
|
||||
@@ -248,7 +248,7 @@
|
||||
// Bloodsucker Owner! Let the boy go.
|
||||
if(C.mind)
|
||||
var/datum/antagonist/vassal/vassaldatum = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
|
||||
if (istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD)
|
||||
if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD)
|
||||
unbuckle_mob(C)
|
||||
useLock = FALSE // Failsafe
|
||||
return
|
||||
@@ -256,7 +256,9 @@
|
||||
torture_victim(user, C)
|
||||
|
||||
/obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target)
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
// Check Bloodmob/living/M, force = FALSE, check_loc = TRUE
|
||||
var/convert_cost = 200 + 200 * bloodsuckerdatum.vassals
|
||||
if(user.blood_volume < convert_cost + 5)
|
||||
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target].</span>")
|
||||
return
|
||||
@@ -275,7 +277,7 @@
|
||||
// All done!
|
||||
if(convert_progress <= 0)
|
||||
// FAIL: Can't be Vassal
|
||||
if(!SSticker.mode.can_make_vassal(target, user, display_warning=FALSE) || HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
|
||||
if(!SSticker.mode.can_make_vassal(target, user, display_warning = FALSE) || HAS_TRAIT(target, TRAIT_MINDSHIELD)) // If I'm an unconvertable Antag ONLY
|
||||
to_chat(user, "<span class='danger'>[target] doesn't respond to your persuasion. It doesn't appear they can be converted to follow you, they either have a mindshield or their external loyalties are too difficult for you to break.<i>\[ALT+click to release\]</span>")
|
||||
convert_progress ++ // Pop it back up some. Avoids wasting Blood on a lost cause.
|
||||
// SUCCESS: All done!
|
||||
@@ -301,10 +303,9 @@
|
||||
return
|
||||
// Check: Blood
|
||||
if(user.blood_volume < convert_cost)
|
||||
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target].</span>")
|
||||
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [convert_cost - user.blood_volume] units more!</span>")
|
||||
useLock = FALSE
|
||||
return
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
bloodsuckerdatum.AddBloodVolume(-convert_cost)
|
||||
target.add_mob_blood(user)
|
||||
user.visible_message("<span class='notice'>[user] marks a bloody smear on [target]'s forehead and puts a wrist up to [target.p_their()] mouth!</span>", \
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
desc = "Snap restraints with ease, or deal terrible damage with your bare hands."
|
||||
button_icon_state = "power_strength"
|
||||
bloodcost = 10
|
||||
cooldown = 130
|
||||
cooldown = 90
|
||||
target_range = 1
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = ""//"Whom will you subvert to your will?"
|
||||
@@ -66,16 +66,13 @@
|
||||
// Target Type: Mob
|
||||
if(isliving(target))
|
||||
var/mob/living/carbon/user_C = user
|
||||
var/hitStrength = user_C.dna.species.punchdamagehigh * 1.3 + 5
|
||||
var/hitStrength = user_C.dna.species.punchdamagehigh * 1.4 + 15
|
||||
// Knockdown!
|
||||
var/powerlevel = min(5, 1 + level_current)
|
||||
if(rand(5 + powerlevel) >= 5)
|
||||
target.visible_message("<span class='danger'>[user] lands a vicious punch, sending [target] away!</span>", \
|
||||
"<span class='userdanger'>[user] has landed a horrifying punch on you, sending you flying!!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
target.DefaultCombatKnockdown(min(5, rand(10, 10 * powerlevel)) )
|
||||
// Chance of KO
|
||||
if(rand(6 + powerlevel) >= 6 && target.stat <= UNCONSCIOUS)
|
||||
target.Unconscious(40)
|
||||
target.DefaultCombatKnockdownKnockdown(min(5, rand(10, 10 * powerlevel)) )
|
||||
// Attack!
|
||||
playsound(get_turf(target), 'sound/weapons/punch4.ogg', 60, 1, -1)
|
||||
user.do_attack_animation(target, ATTACK_EFFECT_SMASH)
|
||||
|
||||
@@ -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 (!..())
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
return
|
||||
// Wearing mask
|
||||
var/mob/living/L = owner
|
||||
if (L.is_mouth_covered())
|
||||
if (display_error)
|
||||
if(L.is_mouth_covered())
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You cannot feed with your mouth covered! Remove your mask.</span>")
|
||||
return FALSE
|
||||
// Find my Target!
|
||||
if (!FindMyTarget(display_error)) // Sets feed_target within after Validating
|
||||
if(!FindMyTarget(display_error)) // Sets feed_target within after Validating
|
||||
return FALSE
|
||||
// Not in correct state
|
||||
// DONE!
|
||||
@@ -35,36 +35,36 @@
|
||||
|
||||
/datum/action/bloodsucker/feed/proc/ValidateTarget(mob/living/target, display_error) // Called twice: validating a subtle victim, or validating your grapple victim.
|
||||
// Bloodsuckers + Animals MUST be grabbed aggressively!
|
||||
if (!owner.pulling || target == owner.pulling && owner.grab_state < GRAB_AGGRESSIVE)
|
||||
if(!owner.pulling || target == owner.pulling && owner.grab_state < GRAB_AGGRESSIVE)
|
||||
// NOTE: It's OKAY that we are checking if(!target) below, AFTER animals here. We want passive check vs animal to warn you first, THEN the standard warning.
|
||||
// Animals:
|
||||
if (isliving(target) && !iscarbon(target))
|
||||
if (display_error)
|
||||
if(isliving(target) && !iscarbon(target))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Lesser beings require a tighter grip.</span>")
|
||||
return FALSE
|
||||
// Bloodsuckers:
|
||||
else if (iscarbon(target) && target.mind && target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if (display_error)
|
||||
else if(iscarbon(target) && target.mind && target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Other Bloodsuckers will not fall for your subtle approach.</span>")
|
||||
return FALSE
|
||||
// Must have Target
|
||||
if (!target) // || !ismob(target)
|
||||
if (display_error)
|
||||
if(!target) // || !ismob(target)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You must be next to or grabbing a victim to feed from them.</span>")
|
||||
return FALSE
|
||||
// Not even living!
|
||||
if (!isliving(target) || issilicon(target))
|
||||
if (display_error)
|
||||
if(!isliving(target) || issilicon(target))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You may only feed from living beings.</span>")
|
||||
return FALSE
|
||||
if (target.blood_volume <= 0)
|
||||
if (display_error)
|
||||
if(target.blood_volume <= 0)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Your victim has no blood to take.</span>")
|
||||
return FALSE
|
||||
if (ishuman(target))
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(NOBLOOD in H.dna.species.species_traits)// || owner.get_blood_id() != target.get_blood_id())
|
||||
if (display_error)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Your victim's blood is not suitable for you to take.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -75,9 +75,9 @@
|
||||
feed_target = null
|
||||
target_grappled = FALSE
|
||||
// If you are pulling a mob, that's your target. If you don't like it, then release them.
|
||||
if (owner.pulling && ismob(owner.pulling))
|
||||
if(owner.pulling && ismob(owner.pulling))
|
||||
// Check grapple target Valid
|
||||
if (!ValidateTarget(owner.pulling, display_error)) // Grabbed targets display error.
|
||||
if(!ValidateTarget(owner.pulling, display_error)) // Grabbed targets display error.
|
||||
return FALSE
|
||||
target_grappled = TRUE
|
||||
feed_target = owner.pulling
|
||||
@@ -86,11 +86,11 @@
|
||||
var/list/mob/living/seen_targets = view(1, owner)
|
||||
var/list/mob/living/seen_mobs = list()
|
||||
for(var/mob/living/M in seen_targets)
|
||||
if (isliving(M) && M != owner)
|
||||
if(isliving(M) && M != owner)
|
||||
seen_mobs += M
|
||||
// None Seen!
|
||||
if (seen_mobs.len == 0)
|
||||
if (display_error)
|
||||
if(seen_mobs.len == 0)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You must be next to or grabbing a victim to feed from them.</span>")
|
||||
return FALSE
|
||||
// Check Valids...
|
||||
@@ -98,19 +98,19 @@
|
||||
var/list/targets_dead = list()
|
||||
for(var/mob/living/M in seen_mobs)
|
||||
// Check adjecent Valid target
|
||||
if (M != owner && ValidateTarget(M, display_error = FALSE)) // Do NOT display errors. We'll be doing this again in CheckCanUse(), which will rule out grabbed targets.
|
||||
if(M != owner && ValidateTarget(M, display_error = FALSE)) // Do NOT display errors. We'll be doing this again in CheckCanUse(), which will rule out grabbed targets.
|
||||
// Prioritize living, but remember dead as backup
|
||||
if (M.stat < DEAD)
|
||||
if(M.stat < DEAD)
|
||||
targets_valid += M
|
||||
else
|
||||
targets_dead += M
|
||||
// No Living? Try dead.
|
||||
if (targets_valid.len == 0 && targets_dead.len > 0)
|
||||
if(targets_valid.len == 0 && targets_dead.len > 0)
|
||||
targets_valid = targets_dead
|
||||
// No Targets
|
||||
if (targets_valid.len == 0)
|
||||
if(targets_valid.len == 0)
|
||||
// Did I see targets? Then display at least one error
|
||||
if (seen_mobs.len > 1)
|
||||
if(seen_mobs.len > 1)
|
||||
if (display_error)
|
||||
to_chat(owner, "<span class='warning'>None of these are valid targets to feed from subtly.</span>")
|
||||
else
|
||||
@@ -136,28 +136,28 @@
|
||||
// Initial Wait
|
||||
var/feed_time = (amSilent ? 45 : 25) - (2.5 * level_current)
|
||||
feed_time = max(15, feed_time)
|
||||
if (amSilent)
|
||||
if(amSilent)
|
||||
to_chat(user, "<span class='notice'>You lean quietly toward [target] and secretly draw out your fangs...</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You pull [target] close to you and draw out your fangs...</span>")
|
||||
if (!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10)
|
||||
if(!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10)
|
||||
to_chat(user, "<span class='warning'>Your feeding was interrupted.</span>")
|
||||
//DeactivatePower(user,target)
|
||||
return
|
||||
// Put target to Sleep (Bloodsuckers are immune to their own bite's sleep effect)
|
||||
if (!amSilent)
|
||||
if(!amSilent)
|
||||
ApplyVictimEffects(target) // Sleep, paralysis, immobile, unconscious, and mute
|
||||
if(target.stat <= UNCONSCIOUS)
|
||||
sleep(1)
|
||||
// Wait, then Cancel if Invalid
|
||||
if (!ContinueActive(user,target)) // Cancel. They're gone.
|
||||
if(!ContinueActive(user,target)) // Cancel. They're gone.
|
||||
//DeactivatePower(user,target)
|
||||
return
|
||||
// Pull Target Close
|
||||
if (!target.density) // Pull target to you if they don't take up space.
|
||||
if(!target.density) // Pull target to you if they don't take up space.
|
||||
target.Move(user.loc)
|
||||
// Broadcast Message
|
||||
if (amSilent)
|
||||
if(amSilent)
|
||||
//if (!iscarbon(target))
|
||||
// user.visible_message("<span class='notice'>[user] shifts [target] closer to [user.p_their()] mouth.</span>", \
|
||||
// "<span class='notice'>You secretly slip your fangs into [target]'s flesh.</span>", \
|
||||
@@ -173,7 +173,7 @@
|
||||
if(M != owner && M != target && iscarbon(M) && M.mind && !M.has_unlimited_silicon_privilege && !M.eye_blind && !M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
was_unnoticed = FALSE
|
||||
break
|
||||
if (was_unnoticed)
|
||||
if(was_unnoticed)
|
||||
to_chat(user, "<span class='notice'>You think no one saw you...</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Someone may have noticed...</span>")
|
||||
@@ -197,16 +197,16 @@
|
||||
|
||||
// FEEEEEEEEED!!! //
|
||||
bloodsuckerdatum.poweron_feed = TRUE
|
||||
while (bloodsuckerdatum && target && active)
|
||||
while(bloodsuckerdatum && target && active)
|
||||
//user.mobility_flags &= ~MOBILITY_MOVE // user.canmove = 0 // Prevents spilling blood accidentally.
|
||||
|
||||
// Abort? A bloody mistake.
|
||||
if (!do_mob(user, target, 20, 0, 0, extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))
|
||||
if(!do_mob(user, target, 20, 0, 0, extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))
|
||||
// May have disabled Feed during do_mob
|
||||
if (!active || !ContinueActive(user, target))
|
||||
if(!active || !ContinueActive(user, target))
|
||||
break
|
||||
|
||||
if (amSilent)
|
||||
if(amSilent)
|
||||
to_chat(user, "<span class='warning'>Your feeding has been interrupted...but [target.p_they()] didn't seem to notice you.<span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Your feeding has been interrupted!</span>")
|
||||
@@ -214,11 +214,11 @@
|
||||
"<span class='userdanger'>Your teeth are ripped from [target]'s throat. [target.p_their(TRUE)] blood sprays everywhere!</span>")
|
||||
|
||||
// Deal Damage to Target (should have been more careful!)
|
||||
if (iscarbon(target))
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.bleed(15)
|
||||
playsound(get_turf(target), 'sound/effects/splat.ogg', 40, 1)
|
||||
if (ishuman(target))
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.bleed_rate += 5
|
||||
target.add_splatter_floor(get_turf(target))
|
||||
@@ -228,7 +228,7 @@
|
||||
target.emote("scream")
|
||||
|
||||
// Killed Target?
|
||||
if (was_alive)
|
||||
if(was_alive)
|
||||
CheckKilledTarget(user,target)
|
||||
|
||||
return
|
||||
@@ -237,40 +237,40 @@
|
||||
// Handle Feeding! User & Victim Effects (per tick)
|
||||
bloodsuckerdatum.HandleFeeding(target, blood_take_mult)
|
||||
amount_taken += amSilent ? 0.3 : 1
|
||||
if (!amSilent)
|
||||
if(!amSilent)
|
||||
ApplyVictimEffects(target) // Sleep, paralysis, immobile, unconscious, and mute
|
||||
if (amount_taken > 5 && target.stat < DEAD && ishuman(target))
|
||||
if(amount_taken > 5 && target.stat < DEAD && ishuman(target))
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankblood", /datum/mood_event/drankblood) // GOOD // in bloodsucker_life.dm
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Not Human?
|
||||
if (!ishuman(target))
|
||||
if(!ishuman(target))
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankblood", /datum/mood_event/drankblood_bad) // BAD // in bloodsucker_life.dm
|
||||
if (!warning_target_inhuman)
|
||||
if(!warning_target_inhuman)
|
||||
to_chat(user, "<span class='notice'>You recoil at the taste of a lesser lifeform.</span>")
|
||||
warning_target_inhuman = TRUE
|
||||
// Dead Blood?
|
||||
if (target.stat >= DEAD)
|
||||
if (ishuman(target))
|
||||
if(target.stat >= DEAD)
|
||||
if(ishuman(target))
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankblood", /datum/mood_event/drankblood_dead) // BAD // in bloodsucker_life.dm
|
||||
if (!warning_target_dead)
|
||||
if(!warning_target_dead)
|
||||
to_chat(user, "<span class='notice'>Your victim is dead. [target.p_their(TRUE)] blood barely nourishes you.</span>")
|
||||
warning_target_dead = TRUE
|
||||
// Full?
|
||||
if (!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume)
|
||||
if(!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume)
|
||||
to_chat(user, "<span class='notice'>You are full. Further blood will be wasted.</span>")
|
||||
warning_full = TRUE
|
||||
// Blood Remaining? (Carbons/Humans only)
|
||||
if (iscarbon(target) && !target.AmBloodsucker(1))
|
||||
if (target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD)
|
||||
if(iscarbon(target) && !target.AmBloodsucker(1))
|
||||
if(target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD)
|
||||
to_chat(user, "<span class='warning'>Your victim's blood volume is fatally low!</span>")
|
||||
else if (target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY)
|
||||
else if(target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY)
|
||||
to_chat(user, "<span class='warning'>Your victim's blood volume is dangerously low.</span>")
|
||||
else if (target.blood_volume <= BLOOD_VOLUME_SAFE && warning_target_bloodvol > BLOOD_VOLUME_SAFE)
|
||||
else if(target.blood_volume <= BLOOD_VOLUME_SAFE && warning_target_bloodvol > BLOOD_VOLUME_SAFE)
|
||||
to_chat(user, "<span class='notice'>Your victim's blood is at an unsafe level.</span>")
|
||||
warning_target_bloodvol = target.blood_volume // If we had a warning to give, it's been given by now.
|
||||
// Done?
|
||||
if (target.blood_volume <= 0)
|
||||
if(target.blood_volume <= 0)
|
||||
to_chat(user, "<span class='notice'>You have bled your victim dry.</span>")
|
||||
break
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
|
||||
// DONE!
|
||||
//DeactivatePower(user,target)
|
||||
if (amSilent)
|
||||
if(amSilent)
|
||||
to_chat(user, "<span class='notice'>You slowly release [target]'s wrist." + (target.stat == 0 ? " [target.p_their(TRUE)] face lacks expression, like you've already been forgotten.</span>" : ""))
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] unclenches their teeth from [target]'s neck.</span>", \
|
||||
@@ -289,13 +289,13 @@
|
||||
log_combat(owner, target, "fed on blood", addition="(and took [amount_taken] blood)")
|
||||
|
||||
// Killed Target?
|
||||
if (was_alive)
|
||||
if(was_alive)
|
||||
CheckKilledTarget(user,target)
|
||||
|
||||
|
||||
/datum/action/bloodsucker/feed/proc/CheckKilledTarget(mob/living/user, mob/living/target)
|
||||
// Bad Vampire. You shouldn't do that.
|
||||
if (target && target.stat >= DEAD && ishuman(target))
|
||||
if(target && target.stat >= DEAD && ishuman(target))
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankkilled", /datum/mood_event/drankkilled) // BAD // in bloodsucker_life.dm
|
||||
|
||||
/datum/action/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target)
|
||||
@@ -304,18 +304,18 @@
|
||||
|
||||
/datum/action/bloodsucker/feed/proc/ApplyVictimEffects(mob/living/target)
|
||||
// Bloodsuckers not affected by "the Kiss" of another vampire
|
||||
if (!target.mind || !target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
if(!target.mind || !target.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
target.Unconscious(50,0)
|
||||
target.DefaultCombatKnockdown(40 + 5 * level_current,1)
|
||||
// NOTE: THis is based on level of power!
|
||||
if (ishuman(target))
|
||||
if(ishuman(target))
|
||||
target.adjustStaminaLoss(5, forced = TRUE)// Base Stamina Damage
|
||||
|
||||
/datum/action/bloodsucker/feed/DeactivatePower(mob/living/user = owner, mob/living/target)
|
||||
..() // activate = FALSE
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
// No longer Feeding
|
||||
if (bloodsuckerdatum)
|
||||
if(bloodsuckerdatum)
|
||||
bloodsuckerdatum.poweron_feed = FALSE
|
||||
feed_target = null
|
||||
// My mouth is no longer full
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
name = "Fortitude"//"Cellular Emporium"
|
||||
desc = "Withstand egregious physical wounds and walk away from attacks that would stun, pierce, and dismember lesser beings. You cannot run while active."
|
||||
button_icon_state = "power_fortitude"
|
||||
bloodcost = 5
|
||||
bloodcost = 30
|
||||
cooldown = 80
|
||||
bloodsucker_can_buy = TRUE
|
||||
amToggle = TRUE
|
||||
@@ -23,7 +23,7 @@
|
||||
ADD_TRAIT(user, TRAIT_NODISMEMBER, "fortitude")
|
||||
ADD_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude")
|
||||
ADD_TRAIT(user, TRAIT_NORUNNING, "fortitude")
|
||||
if (ishuman(owner))
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
this_resist = max(0.3, 0.7 - level_current * 0.1)
|
||||
H.physiology.brute_mod *= this_resist//0.5
|
||||
@@ -34,7 +34,7 @@
|
||||
user.toggle_move_intent()
|
||||
while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN)
|
||||
// Pay Blood Toll (if awake)
|
||||
if (user.stat == CONSCIOUS)
|
||||
if(user.stat == CONSCIOUS)
|
||||
bloodsuckerdatum.AddBloodVolume(-0.5) // Used to be 0.3 blood per 2 seconds, but we're making it more expensive to keep on.
|
||||
sleep(20) // Check every few ticks that we haven't disabled this power
|
||||
// Return to Running (if you were before)
|
||||
@@ -48,7 +48,7 @@
|
||||
REMOVE_TRAIT(user, TRAIT_NODISMEMBER, "fortitude")
|
||||
REMOVE_TRAIT(user, TRAIT_STUNIMMUNE, "fortitude")
|
||||
REMOVE_TRAIT(user, TRAIT_NORUNNING, "fortitude")
|
||||
if (ishuman(owner))
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.physiology.brute_mod /= this_resist//0.5
|
||||
H.physiology.burn_mod /= this_resist//0.5
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
background_icon_state_on = "vamp_power_off_oneshot" // Even though this never goes off.
|
||||
background_icon_state_off = "vamp_power_off_oneshot"
|
||||
|
||||
bloodcost = 25
|
||||
bloodcost = 100
|
||||
cooldown = 99999 // It'll never come back.
|
||||
amToggle = FALSE
|
||||
amSingleUse = TRUE
|
||||
@@ -23,11 +23,16 @@
|
||||
return
|
||||
// Have No Lair (NOTE: You only got this power if you had a lair, so this means it's destroyed)
|
||||
var/datum/antagonist/bloodsucker/bloodsuckerdatum = owner.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
|
||||
if (!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin)
|
||||
if (display_error)
|
||||
if(!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin)
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Your coffin has been destroyed!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/gohome/proc/flicker_lights(var/flicker_range, var/beat_volume)
|
||||
for(var/obj/machinery/light/L in view(flicker_range, get_turf(owner)))
|
||||
playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', beat_volume, 1)
|
||||
|
||||
|
||||
/datum/action/bloodsucker/gohome/ActivatePower()
|
||||
var/mob/living/carbon/user = owner
|
||||
@@ -35,34 +40,31 @@
|
||||
// IMPORTANT: Check for lair at every step! It might get destroyed.
|
||||
to_chat(user, "<span class='notice'>You focus on separating your consciousness from your physical form...</span>")
|
||||
// STEP ONE: Flicker Lights
|
||||
for(var/obj/machinery/light/L in view(3, get_turf(owner))) // /obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
|
||||
L.flicker(5)
|
||||
playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 20, 1)
|
||||
flicker_lights(3, 20)
|
||||
sleep(50)
|
||||
for(var/obj/machinery/light/L in view(3, get_turf(owner))) // /obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
|
||||
L.flicker(5)
|
||||
playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1)
|
||||
flicker_lights(4, 40)
|
||||
sleep(50)
|
||||
for(var/obj/machinery/light/L in view(6, get_turf(owner))) // /obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
|
||||
flicker_lights(4, 60)
|
||||
for(var/obj/machinery/light/L in view(6, get_turf(owner)))
|
||||
L.flicker(5)
|
||||
playsound(get_turf(owner), 'sound/effects/singlebeat.ogg', 60, 1)
|
||||
// ( STEP TWO: Lights OFF? )
|
||||
// CHECK: Still have Coffin?
|
||||
if (!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin)
|
||||
if(!istype(bloodsuckerdatum) || !bloodsuckerdatum.coffin)
|
||||
to_chat(user, "<span class='warning'>Your coffin has been destroyed! You no longer have a destination.</span>")
|
||||
return FALSE
|
||||
if (!owner)
|
||||
if(!owner)
|
||||
return
|
||||
// SEEN?: (effects ONLY if there are witnesses! Otherwise you just POOF)
|
||||
// NOTE: Stolen directly from statue.dm, thanks guys!
|
||||
|
||||
var/am_seen = FALSE // Do Effects (seen by anyone)
|
||||
var/drop_item = FALSE // Drop Stuff (seen by non-vamp)
|
||||
if (isturf(owner.loc)) // Only check if I'm not in a Locker or something.
|
||||
if(isturf(owner.loc)) // Only check if I'm not in a Locker or something.
|
||||
// A) Check for Darkness (we can just leave)
|
||||
var/turf/T = get_turf(user)
|
||||
if(T && T.lighting_object && T.get_lumcount()>= 0.1)
|
||||
// B) Check for Viewers
|
||||
for(var/mob/living/M in viewers(owner))
|
||||
for(var/mob/living/M in viewers(get_turf(owner)))
|
||||
if(M != owner && isliving(M) && M.mind && !M.has_unlimited_silicon_privilege && !M.eye_blind) // M.client <--- add this in after testing!
|
||||
am_seen = TRUE
|
||||
if (!M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
|
||||
@@ -76,7 +78,7 @@
|
||||
var/obj/O = user.legcuffed
|
||||
user.dropItemToGround(O)
|
||||
// SEEN!
|
||||
if (drop_item)
|
||||
if(drop_item)
|
||||
// DROP: Clothes, held items, and cuffs etc
|
||||
// NOTE: Taken from unequip_everything() in inventory.dm. We need to
|
||||
// *force* all items to drop, so we had to just gut the code out of it.
|
||||
@@ -86,30 +88,28 @@
|
||||
user.dropItemToGround(I,TRUE)
|
||||
for(var/obj/item/I in owner.held_items) // drop_all_held_items()
|
||||
user.dropItemToGround(I, TRUE)
|
||||
if (am_seen)
|
||||
if(am_seen)
|
||||
// POOF EFFECTS
|
||||
playsound(get_turf(owner), 'sound/magic/summon_karp.ogg', 60, 1)
|
||||
var/datum/effect_system/steam_spread/puff = new /datum/effect_system/steam_spread/()
|
||||
puff.effect_type = /obj/effect/particle_effect/smoke/vampsmoke
|
||||
puff.set_up(3, 0, get_turf(owner))
|
||||
puff.start()
|
||||
|
||||
//STEP FIVE: Create animal at prev location
|
||||
var/mob/living/simple_animal/SA = pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse,
|
||||
new SA (owner.loc)
|
||||
// TELEPORT: Move to Coffin & Close it!
|
||||
do_teleport(owner, bloodsuckerdatum.coffin, no_effects = TRUE, forced = TRUE, channel = TELEPORT_CHANNEL_QUANTUM) // in teleport.dm?
|
||||
// SLEEP
|
||||
do_teleport(owner, bloodsuckerdatum.coffin, no_effects = TRUE, forced = TRUE, channel = TELEPORT_CHANNEL_QUANTUM)
|
||||
user.set_resting(TRUE, TRUE, FALSE)
|
||||
//user.Unconscious(30,0)
|
||||
user.Stun(30, TRUE)
|
||||
user.Stun(30,1)
|
||||
// CLOSE LID: If fail, force me in.
|
||||
if (!bloodsuckerdatum.coffin.close(owner))
|
||||
if(!bloodsuckerdatum.coffin.close(owner))
|
||||
bloodsuckerdatum.coffin.insert(owner) // Puts me inside.
|
||||
// The following was taken from close() proc in closets.dm
|
||||
// (but we had to do it this way because there is no way to force entry)
|
||||
playsound(bloodsuckerdatum.coffin.loc, bloodsuckerdatum.coffin.close_sound, 15, 1, -3)
|
||||
bloodsuckerdatum.coffin.opened = FALSE
|
||||
bloodsuckerdatum.coffin.density = TRUE
|
||||
bloodsuckerdatum.coffin.update_icon()
|
||||
// Lock Coffin
|
||||
bloodsuckerdatum.coffin.LockMe(owner)
|
||||
// ( STEP FIVE: Create animal at prev location? )
|
||||
//var/mob/living/simple_animal/SA = /mob/living/simple_animal/hostile/retaliate/bat // pick(/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse,/mob/living/simple_animal/mouse, /mob/living/simple_animal/hostile/retaliate/bat) //prob(300) /mob/living/simple_animal/mouse,
|
||||
//new SA (owner.loc)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
desc = "Dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed."
|
||||
button_icon_state = "power_speed"
|
||||
bloodcost = 6
|
||||
cooldown = 30
|
||||
cooldown = 50
|
||||
target_range = 15
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = ""//"Whom will you subvert to your will?"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
desc = "Spring at your target and aggressively grapple them without warning. Attacks from concealment or the rear may even knock them down."
|
||||
button_icon_state = "power_lunge"
|
||||
bloodcost = 10
|
||||
cooldown = 100
|
||||
cooldown = 120
|
||||
target_range = 3
|
||||
power_activates_immediately = TRUE
|
||||
message_Trigger = ""//"Whom will you subvert to your will?"
|
||||
@@ -28,7 +28,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/action/bloodsucker/targeted/lunge/CheckValidTarget(atom/A)
|
||||
return isliving(A)
|
||||
return iscarbon(A)
|
||||
|
||||
/datum/action/bloodsucker/targeted/lunge/CheckCanTarget(atom/A, display_error)
|
||||
// Check: Self
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
desc = "Dominate the mind of a mortal who can see your eyes."
|
||||
button_icon_state = "power_mez"
|
||||
bloodcost = 30
|
||||
cooldown = 200
|
||||
cooldown = 300
|
||||
target_range = 1
|
||||
power_activates_immediately = FALSE
|
||||
message_Trigger = "Whom will you subvert to your will?"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
button_icon_state = "power_tres"
|
||||
|
||||
bloodcost = 10
|
||||
cooldown = 60
|
||||
cooldown = 80
|
||||
amToggle = FALSE
|
||||
//target_range = 2
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -116,7 +116,7 @@ This file contains the cult dagger and rune list code
|
||||
if(user.blood_volume)
|
||||
user.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
|
||||
var/scribe_mod = initial(rune_to_scribe.scribe_delay)
|
||||
if(istype(get_turf(user), /turf/open/floor/engine/cult))
|
||||
if(istype(get_turf(user), /turf/open/floor/engine/cult) && !(ispath(rune_to_scribe, /obj/effect/rune/narsie)))
|
||||
scribe_mod *= 0.5
|
||||
if(!do_after(user, scribe_mod, target = get_turf(user)))
|
||||
for(var/V in shields)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
/obj/machinery/airalarm/ui_data(mob/user)
|
||||
var/data = list(
|
||||
"locked" = locked,
|
||||
"siliconUser" = user.has_unlimited_silicon_privilege,
|
||||
"siliconUser" = user.has_unlimited_silicon_privilege || hasSiliconAccessInArea(user),
|
||||
"emagged" = (obj_flags & EMAGGED ? 1 : 0),
|
||||
"danger_level" = danger_level,
|
||||
)
|
||||
@@ -288,7 +288,7 @@
|
||||
"danger_level" = cur_tlv.get_danger_level(environment.gases[gas_id] * partial_pressure)
|
||||
))
|
||||
|
||||
if(!locked || user.has_unlimited_silicon_privilege)
|
||||
if(!locked || user.has_unlimited_silicon_privilege || hasSiliconAccessInArea(user))
|
||||
data["vents"] = list()
|
||||
for(var/id_tag in A.air_vent_names)
|
||||
var/long_name = A.air_vent_names[id_tag]
|
||||
@@ -368,7 +368,7 @@
|
||||
/obj/machinery/airalarm/ui_act(action, params)
|
||||
if(..() || buildstage != 2)
|
||||
return
|
||||
if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled))
|
||||
if((locked && !usr.has_unlimited_silicon_privilege && !hasSiliconAccessInArea(usr)) || (usr.has_unlimited_silicon_privilege && aidisabled))
|
||||
return
|
||||
var/device_id = params["id_tag"]
|
||||
switch(action)
|
||||
@@ -840,7 +840,7 @@
|
||||
|
||||
/obj/machinery/airalarm/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
|
||||
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)) || !isturf(loc))
|
||||
return
|
||||
togglelock(user)
|
||||
return TRUE
|
||||
|
||||
@@ -251,6 +251,7 @@
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/user)
|
||||
if((isnull(user) || istype(user)) && state_open && !panel_open)
|
||||
..(user)
|
||||
reagent_transfer = 0
|
||||
return occupant
|
||||
|
||||
/obj/machinery/atmospherics/components/unary/cryo_cell/container_resist(mob/living/user)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
return
|
||||
if(reload < reload_cooldown)
|
||||
return
|
||||
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr))
|
||||
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr))
|
||||
priority_announce("Bluespace artillery fire detected. Brace for impact.")
|
||||
message_admins("[ADMIN_LOOKUPFLW(usr)] has launched an artillery strike.")
|
||||
var/list/L = list()
|
||||
|
||||
@@ -105,6 +105,7 @@ datum/bounty/reagent/complex_drink/New()
|
||||
/datum/reagent/consumable/ethanol/hearty_punch,\
|
||||
/datum/reagent/consumable/ethanol/manhattan_proj,\
|
||||
/datum/reagent/consumable/ethanol/narsour,\
|
||||
/datum/reagent/consumable/ethanol/cogchamp,\
|
||||
/datum/reagent/consumable/ethanol/neurotoxin,\
|
||||
/datum/reagent/consumable/ethanol/patron,\
|
||||
/datum/reagent/consumable/ethanol/quadruple_sec,\
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
desc = "Hello brothers from the stars!!! Our fellow brethren have made contact at long last and gave us gifts man! They really did build the prymi- Connection Error- Bro we’ll send you a sheet of advanced alien alloy."
|
||||
cost = 15000
|
||||
DropPodOnly = TRUE
|
||||
contraband = TRUE
|
||||
contains = list(/obj/item/stack/sheet/mineral/abductor)
|
||||
crate_name = "alien bro alloy crate"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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 ////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
/obj/item/supplypod_beacon/AltClick(mob/user)
|
||||
. = ..()
|
||||
if (!user.canUseTopic(src, !issilicon(user)))
|
||||
if (!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
|
||||
return
|
||||
if (express_console)
|
||||
unlink_console()
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -488,4 +488,47 @@
|
||||
if(client && client.prefs.uses_glasses_colour && glasses_equipped)
|
||||
add_client_colour(G.glass_colour_type)
|
||||
else
|
||||
remove_client_colour(G.glass_colour_type)
|
||||
remove_client_colour(G.glass_colour_type)
|
||||
|
||||
/obj/item/clothing/glasses/debug
|
||||
name = "debug glasses"
|
||||
desc = "Medical, security and diagnostic hud. Alt click to toggle xray."
|
||||
icon_state = "nvgmeson"
|
||||
item_state = "nvgmeson"
|
||||
flags_cover = GLASSESCOVERSEYES
|
||||
darkness_view = 8
|
||||
flash_protect = 2
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
glass_colour_type = FALSE
|
||||
clothing_flags = SCAN_REAGENTS
|
||||
vision_flags = SEE_TURFS
|
||||
var/list/hudlist = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED)
|
||||
var/xray = FALSE
|
||||
|
||||
/obj/item/clothing/glasses/debug/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(slot != ITEM_SLOT_EYES)
|
||||
return
|
||||
if(ishuman(user))
|
||||
for(var/hud in hudlist)
|
||||
var/datum/atom_hud/H = GLOB.huds[hud]
|
||||
H.add_hud_to(user)
|
||||
|
||||
/obj/item/clothing/glasses/debug/dropped(mob/user)
|
||||
. = ..()
|
||||
if(ishuman(user))
|
||||
for(var/hud in hudlist)
|
||||
var/datum/atom_hud/H = GLOB.huds[hud]
|
||||
H.remove_hud_from(user)
|
||||
|
||||
/obj/item/clothing/glasses/debug/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(ishuman(user))
|
||||
if(xray)
|
||||
vision_flags -= SEE_MOBS|SEE_OBJS
|
||||
else
|
||||
vision_flags += SEE_MOBS|SEE_OBJS
|
||||
xray = !xray
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.update_sight()
|
||||
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -39,6 +39,12 @@
|
||||
/obj/item/clothing/mask/gas/welding/attack_self(mob/user)
|
||||
weldingvisortoggle(user)
|
||||
|
||||
/obj/item/clothing/mask/gas/welding/up
|
||||
|
||||
/obj/item/clothing/mask/gas/welding/up/Initialize()
|
||||
..()
|
||||
visor_toggling()
|
||||
|
||||
|
||||
// ********************************************************************
|
||||
|
||||
|
||||
@@ -427,14 +427,27 @@
|
||||
/datum/outfit/debug //Debug objs plus hardsuit
|
||||
name = "Debug outfit"
|
||||
uniform = /obj/item/clothing/under/patriotsuit
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite
|
||||
shoes = /obj/item/clothing/shoes/magboots/advance
|
||||
suit_store = /obj/item/tank/internals/oxygen
|
||||
mask = /obj/item/clothing/mask/gas/welding
|
||||
belt = /obj/item/storage/belt/utility/chief/full
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
id = /obj/item/card/id/ert
|
||||
glasses = /obj/item/clothing/glasses/meson/night
|
||||
suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite/debug
|
||||
glasses = /obj/item/clothing/glasses/debug
|
||||
ears = /obj/item/radio/headset/headset_cent/commander
|
||||
mask = /obj/item/clothing/mask/gas/welding/up
|
||||
gloves = /obj/item/clothing/gloves/combat
|
||||
belt = /obj/item/storage/belt/utility/chief/full
|
||||
l_pocket = /obj/item/gun/magic/wand/resurrection/debug
|
||||
r_pocket = /obj/item/gun/magic/wand/death/debug
|
||||
shoes = /obj/item/clothing/shoes/magboots/advance/debug
|
||||
id = /obj/item/card/id/debug
|
||||
suit_store = /obj/item/tank/internals/oxygen
|
||||
back = /obj/item/storage/backpack/holding
|
||||
backpack_contents = list(/obj/item/card/emag=1, /obj/item/flashlight/emp/debug=1, /obj/item/construction/rcd/combat=1, /obj/item/gun/magic/wand/resurrection/debug=1, /obj/item/melee/transforming/energy/axe=1)
|
||||
box = /obj/item/storage/box/debugtools
|
||||
internals_slot = ITEM_SLOT_SUITSTORE
|
||||
backpack_contents = list(
|
||||
/obj/item/melee/transforming/energy/axe=1,\
|
||||
/obj/item/storage/part_replacer/bluespace/tier4=1,\
|
||||
/obj/item/debug/human_spawner=1,\
|
||||
)
|
||||
|
||||
/datum/outfit/debug/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
var/obj/item/card/id/W = H.wear_id
|
||||
W.registered_name = H.real_name
|
||||
W.update_label()
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
magpulse = !magpulse
|
||||
icon_state = "[magboot_state][magpulse]"
|
||||
to_chat(user, "<span class='notice'>You [magpulse ? "enable" : "disable"] the mag-pulse traction system.</span>")
|
||||
user.update_inv_shoes() //so our mob-overlays update
|
||||
user.update_gravity(user.has_gravity())
|
||||
if(user)
|
||||
user.update_inv_shoes() //so our mob-overlays update
|
||||
user.update_gravity(user.has_gravity())
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
@@ -52,8 +53,42 @@
|
||||
slowdown_active = SHOES_SLOWDOWN
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/clothing/shoes/magboots/advance/debug
|
||||
|
||||
/obj/item/clothing/shoes/magboots/advance/debug/Initialize()
|
||||
attack_self(src)
|
||||
|
||||
/obj/item/clothing/shoes/magboots/syndie
|
||||
desc = "Reverse-engineered magnetic boots that have a heavy magnetic pull. Property of Gorlex Marauders."
|
||||
name = "blood-red magboots"
|
||||
icon_state = "syndiemag0"
|
||||
magboot_state = "syndiemag"
|
||||
|
||||
/obj/item/clothing/shoes/magboots/crushing
|
||||
desc = "Normal looking magboots that are altered to increase magnetic pull to crush anything underfoot."
|
||||
|
||||
/obj/item/clothing/shoes/magboots/crushing/proc/crush(mob/living/user)
|
||||
if (!isturf(user.loc) || !magpulse)
|
||||
return
|
||||
var/turf/T = user.loc
|
||||
for (var/mob/living/A in T)
|
||||
if (A != user && A.lying)
|
||||
A.adjustBruteLoss(rand(10,13))
|
||||
to_chat(A,"<span class='userdanger'>[user]'s magboots press down on you, crushing you!</span>")
|
||||
A.emote("scream")
|
||||
|
||||
/obj/item/clothing/shoes/magboots/crushing/attack_self(mob/user)
|
||||
. = ..()
|
||||
if (magpulse)
|
||||
RegisterSignal(user, COMSIG_MOVABLE_MOVED,.proc/crush)
|
||||
else
|
||||
UnregisterSignal(user,COMSIG_MOVABLE_MOVED)
|
||||
|
||||
/obj/item/clothing/shoes/magboots/crushing/equipped(mob/user,slot)
|
||||
. = ..()
|
||||
if (slot == SLOT_SHOES && magpulse)
|
||||
RegisterSignal(user, COMSIG_MOVABLE_MOVED,.proc/crush)
|
||||
|
||||
/obj/item/clothing/shoes/magboots/crushing/dropped(mob/user)
|
||||
. = ..()
|
||||
UnregisterSignal(user,COMSIG_MOVABLE_MOVED)
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
item_state = "syndie_helm"
|
||||
item_color = "syndi"
|
||||
armor = list("melee" = 40, "bullet" = 50, "laser" = 30, "energy" = 15, "bomb" = 35, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 90)
|
||||
on = TRUE
|
||||
on = FALSE
|
||||
var/obj/item/clothing/suit/space/hardsuit/syndi/linkedsuit = null
|
||||
actions_types = list(/datum/action/item_action/toggle_helmet_mode)
|
||||
visor_flags_inv = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR
|
||||
@@ -367,6 +367,12 @@
|
||||
on = FALSE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/debug
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/debug/Initialize()
|
||||
. = ..()
|
||||
soundloop.volume = 0
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/syndi/elite
|
||||
name = "elite syndicate hardsuit"
|
||||
desc = "An elite version of the syndicate hardsuit, with improved armour and fireproofing. It is in travel mode."
|
||||
@@ -380,6 +386,9 @@
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_SNEK_TAURIC|STYLE_PAW_TAURIC
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/syndi/elite/debug
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/debug
|
||||
slowdown = 0
|
||||
|
||||
//The Owl Hardsuit
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/syndi/owl
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
@@ -325,17 +325,16 @@
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
/obj/item/clothing/suit/ran
|
||||
name = "Shikigami costume"
|
||||
name = "shikigami costume"
|
||||
desc = "A costume that looks like a certain shikigami, is super fluffy."
|
||||
icon_state = "ran_suit"
|
||||
item_state = "ran_suit"
|
||||
body_parts_covered = CHEST|GROIN|LEGS
|
||||
flags_inv = HIDEJUMPSUIT|HIDETAUR
|
||||
heat_protection = CHEST|GROIN|LEGS //fluffy tails!
|
||||
//2061
|
||||
|
||||
/obj/item/clothing/head/ran
|
||||
name = "Shikigami hat"
|
||||
name = "shikigami hat"
|
||||
desc = "A hat that looks like it keeps any fluffy ears contained super warm, has little charms over it."
|
||||
icon_state = "ran_hat"
|
||||
item_state = "ran_hat"
|
||||
@@ -880,7 +879,6 @@
|
||||
blood_overlay_type = "armor"
|
||||
body_parts_covered = CHEST
|
||||
resistance_flags = NONE
|
||||
mutantrace_variation = NONE
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 5, "bio" = 0, "rad" = 0, "fire" = -5, "acid" = -15) //nylon sucks against acid
|
||||
|
||||
/obj/item/clothing/suit/assu_suit
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
/obj/item/valentine/examine(mob/user)
|
||||
. = ..()
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
if( !(ishuman(user) || isobserver(user) || issilicon(user)) )
|
||||
if( !(ishuman(user) || isobserver(user) || hasSiliconAccessInArea(user)) )
|
||||
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(message)]</BODY></HTML>", "window=[name]")
|
||||
onclose(user, "[name]")
|
||||
else
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
shuttleId = "pirateship"
|
||||
icon_screen = "syndishuttle"
|
||||
icon_keyboard = "syndie_key"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
light_color = LIGHT_COLOR_RED
|
||||
possible_destinations = "pirateship_away;pirateship_home;pirateship_custom"
|
||||
|
||||
@@ -184,6 +185,7 @@
|
||||
name = "pirate shuttle navigation computer"
|
||||
desc = "Used to designate a precise transit location for the pirate shuttle."
|
||||
shuttleId = "pirateship"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
lock_override = CAMERA_LOCK_STATION
|
||||
shuttlePortId = "pirateship_custom"
|
||||
x_offset = 9
|
||||
@@ -226,6 +228,7 @@
|
||||
desc = "This sophisticated machine scans the nearby space for items of value."
|
||||
icon = 'icons/obj/machines/research.dmi'
|
||||
icon_state = "tdoppler"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
density = TRUE
|
||||
var/cooldown = 300
|
||||
var/next_use = 0
|
||||
@@ -259,6 +262,7 @@
|
||||
name = "cargo hold pad"
|
||||
icon = 'icons/obj/telescience.dmi'
|
||||
icon_state = "lpad-idle-o"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
var/idle_state = "lpad-idle-o"
|
||||
var/warmup_state = "lpad-idle"
|
||||
var/sending_state = "lpad-beam"
|
||||
@@ -272,6 +276,7 @@
|
||||
|
||||
/obj/machinery/computer/piratepad_control
|
||||
name = "cargo hold control terminal"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
var/status_report = "Idle"
|
||||
var/obj/machinery/piratepad/pad
|
||||
var/warmup_time = 100
|
||||
|
||||
@@ -107,9 +107,9 @@
|
||||
smash(hit_atom, throwingdatum?.thrower, TRUE)
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE)
|
||||
if(!isGlass)
|
||||
if(!isGlass && !istype(src, /obj/item/reagent_containers/food/drinks/bottle)) //I don't like this but I also don't want to rework drink container hierarchy
|
||||
return
|
||||
if(QDELING(src) || !target) //Invalid loc
|
||||
if(QDELING(src) || (ranged && !target))
|
||||
return
|
||||
if(bartender_check(target) && ranged)
|
||||
return
|
||||
@@ -126,12 +126,69 @@
|
||||
B.transform = M
|
||||
B.pixel_x = rand(-12, 12)
|
||||
B.pixel_y = rand(-12, 12)
|
||||
if(prob(33))
|
||||
new/obj/item/shard(drop_location())
|
||||
playsound(src, "shatter", 70, 1)
|
||||
if(isGlass)
|
||||
playsound(src, "shatter", 70, 1)
|
||||
if(prob(33))
|
||||
new/obj/item/shard(drop_location())
|
||||
else
|
||||
B.force = 0
|
||||
B.throwforce = 0
|
||||
B.desc = "A carton with the bottom half burst open. Might give you a papercut."
|
||||
transfer_fingerprints_to(B)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/MouseDrop(atom/over, atom/src_location, atom/over_location, src_control, over_control, params)
|
||||
var/mob/user = usr
|
||||
. = ..()
|
||||
if (!istype(src_location) || !istype(over_location))
|
||||
return
|
||||
if (!user || user.incapacitated() || !user.Adjacent(src))
|
||||
return
|
||||
if (!(locate(/obj/structure/table) in src_location) || !(locate(/obj/structure/table) in over_location))
|
||||
return
|
||||
|
||||
//Are we an expert slider?
|
||||
var/datum/action/innate/D = get_action_of_type(user, /datum/action/innate/drink_fling)
|
||||
if(!D?.active)
|
||||
if (!src_location.Adjacent(over_location)) // Regular users can only do short slides.
|
||||
return
|
||||
if (prob(10))
|
||||
user.visible_message("<span class='warning'>\The [user] tries to slide \the [src] down the table, but fails miserably.</span>", "<span class='warning'>You <b>fail</b> to slide \the [src] down the table!</span>")
|
||||
smash(over_location, user, FALSE)
|
||||
return
|
||||
user.visible_message("<span class='notice'>\The [user] slides \the [src] down the table.</span>", "<span class='notice'>You slide \the [src] down the table!</span>")
|
||||
forceMove(over_location)
|
||||
return
|
||||
var/distance = MANHATTAN_DISTANCE(over_location, src)
|
||||
if (distance >= 8 || distance == 0) // More than a full screen to go, or trying to slide to the same tile
|
||||
return
|
||||
|
||||
// Geometrically checking if we're on a straight line.
|
||||
var/datum/vector/V = atoms2vector(src, over_location)
|
||||
var/datum/vector/V_norm = V.duplicate()
|
||||
V_norm.normalize()
|
||||
if (!V_norm.is_integer())
|
||||
return // Only a cardinal vector (north, south, east, west) can pass this test
|
||||
|
||||
// Checks if there's tables on the path.
|
||||
var/turf/dest = get_translated_turf(V)
|
||||
var/turf/temp_turf = src_location
|
||||
|
||||
do
|
||||
temp_turf = temp_turf.get_translated_turf(V_norm)
|
||||
if (!locate(/obj/structure/table) in temp_turf)
|
||||
var/datum/vector/V2 = atoms2vector(src, temp_turf)
|
||||
vector_translate(V2, 0.1 SECONDS)
|
||||
user.visible_message("<span class='warning'>\The [user] slides \the [src] down the table... and straight into the ground!</span>", "<span class='warning'>You slide \the [src] down the table, and straight into the ground!</span>")
|
||||
smash(over_location, user, FALSE)
|
||||
return
|
||||
while (temp_turf != dest)
|
||||
|
||||
vector_translate(V, 0.1 SECONDS)
|
||||
user.visible_message("<span class='notice'>\The [user] expertly slides \the [src] down the table.</span>", "<span class='notice'>You slide \the [src] down the table. What a pro.</span>")
|
||||
return
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Drinks. END
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -289,28 +346,6 @@
|
||||
icon_state = "juicebox"
|
||||
volume = 15 //I figure if you have to craft these it should at least be slightly better than something you can get for free from a watercooler
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/smash(atom/target, mob/thrower, ranged = FALSE)
|
||||
if(bartender_check(target) && ranged)
|
||||
return
|
||||
var/obj/item/broken_bottle/B = new (loc)
|
||||
B.icon_state = icon_state
|
||||
var/icon/I = new('icons/obj/drinks.dmi', src.icon_state)
|
||||
I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1)
|
||||
I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0))
|
||||
B.icon = I
|
||||
B.name = "broken [name]"
|
||||
B.force = 0
|
||||
B.throwforce = 0
|
||||
B.desc = "A carton with the bottom half burst open. Might give you a papercut."
|
||||
if(ranged)
|
||||
var/matrix/M = matrix(B.transform)
|
||||
M.Turn(rand(-170, 170))
|
||||
B.transform = M
|
||||
B.pixel_x = rand(-12, 12)
|
||||
B.pixel_y = rand(-12, 12)
|
||||
transfer_fingerprints_to(B)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/on_reagent_change(changetype)
|
||||
if (reagents.reagent_list.len)
|
||||
switch(reagents.get_master_reagent_id())
|
||||
|
||||
@@ -16,40 +16,6 @@
|
||||
isGlass = TRUE
|
||||
foodtype = ALCOHOL
|
||||
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/bottle/smash(mob/living/target, mob/thrower, ranged = FALSE)
|
||||
//Creates a shattering noise and replaces the bottle with a broken_bottle
|
||||
if(bartender_check(target) && ranged)
|
||||
return
|
||||
var/obj/item/broken_bottle/B = new (loc)
|
||||
if(!ranged)
|
||||
thrower.put_in_hands(B)
|
||||
else
|
||||
var/matrix/M = matrix(B.transform)
|
||||
M.Turn(rand(-170, 170))
|
||||
B.transform = M
|
||||
B.pixel_x = rand(-12, 12)
|
||||
B.pixel_y = rand(-12, 12)
|
||||
B.icon_state = icon_state
|
||||
|
||||
var/icon/I = new('icons/obj/drinks.dmi', src.icon_state)
|
||||
I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1)
|
||||
I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0))
|
||||
B.icon = I
|
||||
|
||||
if(isGlass)
|
||||
if(prob(33))
|
||||
new/obj/item/shard(drop_location())
|
||||
playsound(src, "shatter", 70, 1)
|
||||
else
|
||||
B.force = 0
|
||||
B.throwforce = 0
|
||||
B.desc = "A carton with the bottom half burst open. Might give you a papercut."
|
||||
B.name = "broken [name]"
|
||||
transfer_fingerprints_to(B)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/bottle/attack(mob/living/target, mob/living/user)
|
||||
|
||||
if(!target)
|
||||
@@ -109,7 +75,7 @@
|
||||
//Keeping this here for now, I'll ask if I should keep it here.
|
||||
/obj/item/broken_bottle
|
||||
name = "broken bottle"
|
||||
desc = "A bottle with a sharp broken bottom."
|
||||
desc = "A shattered glass container with sharp edges."
|
||||
icon = 'icons/obj/drinks.dmi'
|
||||
icon_state = "broken_bottle"
|
||||
force = 9
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
if(!operating)
|
||||
. += "<span class='notice'>Alt-click [src] to turn it on.</span>"
|
||||
|
||||
if(!in_range(user, src) && !issilicon(user) && !isobserver(user))
|
||||
if(!in_range(user, src) && !hasSiliconAccessInArea(user) && !isobserver(user))
|
||||
. += "<span class='warning'>You're too far away to examine [src]'s contents and display!</span>"
|
||||
return
|
||||
if(operating)
|
||||
@@ -63,7 +63,7 @@
|
||||
return
|
||||
|
||||
if(length(ingredients))
|
||||
if(issilicon(user))
|
||||
if(hasSiliconAccessInArea(user))
|
||||
. += "<span class='notice'>\The [src] camera shows:</span>"
|
||||
else
|
||||
. += "<span class='notice'>\The [src] contains:</span>"
|
||||
@@ -187,14 +187,14 @@
|
||||
|
||||
/obj/machinery/microwave/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(user.canUseTopic(src, !issilicon(usr)))
|
||||
if(user.canUseTopic(src, !hasSiliconAccessInArea(user)))
|
||||
cook()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/microwave/ui_interact(mob/user)
|
||||
. = ..()
|
||||
|
||||
if(operating || panel_open || !anchored || !user.canUseTopic(src, !issilicon(user)))
|
||||
if(operating || panel_open || !anchored || !user.canUseTopic(src, !hasSiliconAccessInArea(user)))
|
||||
return
|
||||
if(isAI(user) && (stat & NOPOWER))
|
||||
return
|
||||
@@ -206,10 +206,10 @@
|
||||
to_chat(user, "<span class='warning'>\The [src] is empty.</span>")
|
||||
return
|
||||
|
||||
var/choice = show_radial_menu(user, src, isAI(user) ? ai_radial_options : radial_options, require_near = !issilicon(user))
|
||||
var/choice = show_radial_menu(user, src, isAI(user) ? ai_radial_options : radial_options, require_near = !hasSiliconAccessInArea(user))
|
||||
|
||||
// post choice verification
|
||||
if(operating || panel_open || !anchored || !user.canUseTopic(src, !issilicon(user)))
|
||||
if(operating || panel_open || !anchored || !user.canUseTopic(src, !hasSiliconAccessInArea(user)))
|
||||
return
|
||||
if(isAI(user) && (stat & NOPOWER))
|
||||
return
|
||||
|
||||
@@ -585,6 +585,14 @@
|
||||
mix_message = "The mixture develops a sinister glow."
|
||||
mix_sound = 'sound/effects/singlebeat.ogg'
|
||||
|
||||
/datum/chemical_reaction/cogchamp
|
||||
name = "CogChamp"
|
||||
id = /datum/reagent/consumable/ethanol/cogchamp
|
||||
results = list(/datum/reagent/consumable/ethanol/cogchamp = 3)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/cognac = 1, /datum/reagent/fuel = 1, /datum/reagent/consumable/ethanol/screwdrivercocktail = 1)
|
||||
mix_message = "You hear faint sounds of gears turning as it mixes."
|
||||
mix_sound = 'sound/effects/clockcult_gateway_closing.ogg'
|
||||
|
||||
/datum/chemical_reaction/quadruplesec
|
||||
name = "Quadruple Sec"
|
||||
id = /datum/reagent/consumable/ethanol/quadruple_sec
|
||||
|
||||
@@ -244,6 +244,7 @@
|
||||
/datum/reagent/consumable/spacemountainwind = 5
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/snowcones/spacemountainwind
|
||||
subcategory = CAT_ICE
|
||||
|
||||
/datum/crafting_recipe/food/pwrgame_sc
|
||||
name = "Pwrgame snowcone"
|
||||
@@ -273,4 +274,4 @@
|
||||
/datum/reagent/colorful_reagent = 1 //Harder to make
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/snowcones/rainbow
|
||||
subcategory = CAT_ICE
|
||||
subcategory = CAT_ICE
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
data["emagged"] = TRUE
|
||||
data["emag_programs"] = emag_programs
|
||||
data["program"] = program
|
||||
data["can_toggle_safety"] = issilicon(user) || IsAdminGhost(user)
|
||||
data["can_toggle_safety"] = hasSiliconAccessInArea(user) || IsAdminGhost(user)
|
||||
|
||||
return data
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
if(A)
|
||||
load_program(A)
|
||||
if("safety")
|
||||
if(!issilicon(usr) && !IsAdminGhost(usr))
|
||||
if(!hasSiliconAccessInArea(usr) && !IsAdminGhost(usr))
|
||||
var/msg = "[key_name(usr)] attempted to emag the holodeck using a href they shouldn't have!"
|
||||
message_admins(msg)
|
||||
log_admin(msg)
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
return
|
||||
|
||||
var/datum/browser/popup = new(user, "plantdna", "Plant DNA Manipulator", 450, 600)
|
||||
if(!(in_range(src, user) || issilicon(user)))
|
||||
if(!(in_range(src, user) || hasSiliconAccessInArea(user)))
|
||||
popup.close()
|
||||
return
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
interact(user)
|
||||
|
||||
/obj/item/integrated_circuit_printer/interact(mob/user)
|
||||
if(!(in_range(src, user) || issilicon(user)))
|
||||
if(!(in_range(src, user) || hasSiliconAccessInArea(user)))
|
||||
return
|
||||
|
||||
if(isnull(current_category))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//check if it doesn't require any access at all
|
||||
if(src.check_access(null))
|
||||
return TRUE
|
||||
if(issilicon(M))
|
||||
if(hasSiliconAccessInArea(M))
|
||||
if(ispAI(M))
|
||||
return FALSE
|
||||
return TRUE //AI can do whatever it wants
|
||||
|
||||
@@ -28,3 +28,7 @@
|
||||
backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1)
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
|
||||
/datum/job/bartender/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
|
||||
. = ..()
|
||||
var/datum/action/innate/drink_fling/D = new
|
||||
D.Grant(H)
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -124,6 +124,10 @@
|
||||
/datum/language_holder/drone/syndicate
|
||||
only_speaks_language = null
|
||||
|
||||
/datum/language_holder/dwarf
|
||||
languages = list(/datum/language/common, /datum/language/dwarf)
|
||||
only_speaks_language = /datum/language/dwarf
|
||||
|
||||
/datum/language_holder/slime
|
||||
languages = list(/datum/language/common, /datum/language/slime)
|
||||
only_speaks_language = /datum/language/slime
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
req_access = list()
|
||||
circuit = /obj/item/circuitboard/computer/mining_shuttle/common
|
||||
shuttleId = "mining_common"
|
||||
possible_destinations = "whiteship_home;lavaland_common_away;landing_zone_dock;mining_public"
|
||||
possible_destinations = "lavaland_common_away;commonmining_home"
|
||||
|
||||
/**********************Mining car (Crate like thing, not the rail car)**************************/
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
from doing this unless you absolutely know what you are doing, and have defined a
|
||||
conversion in savefile.dm
|
||||
*/
|
||||
/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female,var/roundstart = FALSE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked
|
||||
/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, roundstart = FALSE, skip_prototype = TRUE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked
|
||||
if(!istype(L))
|
||||
L = list()
|
||||
if(!istype(male))
|
||||
@@ -25,7 +25,7 @@
|
||||
female = list()
|
||||
|
||||
for(var/path in typesof(prototype))
|
||||
if(path == prototype)
|
||||
if(path == prototype && skip_prototype)
|
||||
continue
|
||||
if(roundstart)
|
||||
var/datum/sprite_accessory/P = path
|
||||
|
||||
@@ -159,6 +159,11 @@
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/datum/sprite_accessory/ears/bunny
|
||||
name = "Bunny"
|
||||
icon_state = "bunny"
|
||||
color_src = MATRIXED
|
||||
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
|
||||
|
||||
/******************************************
|
||||
*************** Furry Ears ****************
|
||||
@@ -301,3 +306,7 @@
|
||||
/datum/sprite_accessory/mam_ears/wolf
|
||||
name = "Wolf"
|
||||
icon_state = "wolf"
|
||||
|
||||
/datum/sprite_accessory/mam_ears/bunny
|
||||
name = "Bunny"
|
||||
icon_state = "bunny"
|
||||
@@ -479,32 +479,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
pixel_y = 0
|
||||
animate(src, pixel_y = 2, time = 10, loop = -1)
|
||||
|
||||
/mob/dead/observer/verb/observe()
|
||||
set name = "Observe"
|
||||
set category = "Ghost"
|
||||
|
||||
var/list/creatures = getpois()
|
||||
|
||||
reset_perspective(null)
|
||||
|
||||
var/eye_name = null
|
||||
|
||||
eye_name = input("Please, select a player!", "Observe", null, null) as null|anything in creatures
|
||||
|
||||
if (!eye_name)
|
||||
return
|
||||
|
||||
var/mob/mob_eye = creatures[eye_name]
|
||||
//Istype so we filter out points of interest that are not mobs
|
||||
if(client && mob_eye && istype(mob_eye))
|
||||
client.eye = mob_eye
|
||||
if(mob_eye.hud_used)
|
||||
client.screen = list()
|
||||
LAZYINITLIST(mob_eye.observers)
|
||||
mob_eye.observers |= src
|
||||
mob_eye.hud_used.show_hud(mob_eye.hud_used.hud_version, src)
|
||||
observetarget = mob_eye
|
||||
|
||||
/mob/dead/observer/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak
|
||||
set category = "Ghost"
|
||||
set name = "Jump to Mob"
|
||||
@@ -796,7 +770,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
|
||||
@@ -831,6 +805,32 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
client.screen = list()
|
||||
hud_used.show_hud(hud_used.hud_version)
|
||||
|
||||
/mob/dead/observer/verb/observe()
|
||||
set name = "Observe"
|
||||
set category = "OOC"
|
||||
|
||||
var/list/creatures = getpois()
|
||||
|
||||
reset_perspective(null)
|
||||
|
||||
var/eye_name = null
|
||||
|
||||
eye_name = input("Please, select a player!", "Observe", null, null) as null|anything in creatures
|
||||
|
||||
if (!eye_name)
|
||||
return
|
||||
|
||||
var/mob/mob_eye = creatures[eye_name]
|
||||
//Istype so we filter out points of interest that are not mobs
|
||||
if(client && mob_eye && istype(mob_eye))
|
||||
client.eye = mob_eye
|
||||
if(mob_eye.hud_used)
|
||||
client.screen = list()
|
||||
LAZYINITLIST(mob_eye.observers)
|
||||
mob_eye.observers |= src
|
||||
mob_eye.hud_used.show_hud(mob_eye.hud_used.hud_version, src)
|
||||
observetarget = mob_eye
|
||||
|
||||
/mob/dead/observer/verb/register_pai_candidate()
|
||||
set category = "Ghost"
|
||||
set name = "pAI Setup"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
. = say_dead(message)
|
||||
|
||||
/mob/dead/observer/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
|
||||
. = ..()
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args) //parent calls can't overwrite the current proc args.
|
||||
var/atom/movable/to_follow = speaker
|
||||
if(radio_freq)
|
||||
var/atom/movable/virtualspeaker/V = speaker
|
||||
@@ -36,4 +36,3 @@
|
||||
// Recompose the message, because it's scrambled by default
|
||||
message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source)
|
||||
to_chat(src, "[link] [message]")
|
||||
|
||||
|
||||
@@ -252,7 +252,9 @@
|
||||
return 0
|
||||
if(M.getorgan(/obj/item/organ/alien/hivenode))
|
||||
return 0
|
||||
|
||||
if(isvamp(M))
|
||||
return 0
|
||||
|
||||
if(ismonkey(M))
|
||||
return 1
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -99,6 +99,10 @@
|
||||
. += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
|
||||
else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
|
||||
. += "<span class='warning'><B>[t_His] eyes are glowing an unnatural red!</B></span>"
|
||||
else if(HAS_TRAIT(src, TRAIT_HIJACKER))
|
||||
var/obj/item/implant/hijack/H = user.getImplant(/obj/item/implant/hijack)
|
||||
if (H && !H.stealthmode && H.toggled)
|
||||
. += "<b><font color=orange>[t_His] eyes are flickering a bright yellow!</font></b>"
|
||||
|
||||
//ears
|
||||
if(ears && !(SLOT_EARS in obscured))
|
||||
@@ -396,6 +400,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
|
||||
@@ -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)
|
||||
|
||||
@@ -1585,7 +1585,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if (!HAS_TRAIT(target, TRAIT_PERMABONER))
|
||||
stop_wagging_tail(target)
|
||||
return FALSE
|
||||
else if(aim_for_groin && (target == user || target.lying || same_dir) && (target_on_help || target_restrained || target_aiming_for_groin))
|
||||
else if(!(user.client?.prefs.cit_toggles & NO_ASS_SLAP) && aim_for_groin && (target == user || target.lying || same_dir) && (target_on_help || target_restrained || target_aiming_for_groin))
|
||||
if(target.client?.prefs.cit_toggles & NO_ASS_SLAP)
|
||||
to_chat(user,"A force stays your hand, preventing you from slapping \the [target]'s ass!")
|
||||
return FALSE
|
||||
@@ -1886,6 +1886,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if(get_turf(target) == target_oldturf)
|
||||
shove_blocked = TRUE
|
||||
|
||||
var/append_message = ""
|
||||
if(shove_blocked && !target.buckled)
|
||||
var/directional_blocked = !target.Adjacent(target_shove_turf)
|
||||
var/targetatrest = !CHECK_MOBILITY(target, MOBILITY_STAND)
|
||||
@@ -1899,33 +1900,30 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
target_collateral_human.DefaultCombatKnockdown(SHOVE_KNOCKDOWN_COLLATERAL)
|
||||
user.visible_message("<span class='danger'>[user.name] shoves [target.name] into [target_collateral_human.name]!</span>",
|
||||
"<span class='danger'>You shove [target.name] into [target_collateral_human.name]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
log_combat(user, target, "shoved", "into [target_collateral_human.name]")
|
||||
append_message += ", into [target_collateral_human.name]"
|
||||
|
||||
else
|
||||
user.visible_message("<span class='danger'>[user.name] shoves [target.name]!</span>",
|
||||
"<span class='danger'>You shove [target.name]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
var/target_held_item = target.get_active_held_item()
|
||||
var/knocked_item = FALSE
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
||||
target_held_item = null
|
||||
if(!target.has_movespeed_modifier(MOVESPEED_ID_SHOVE))
|
||||
target.add_movespeed_modifier(MOVESPEED_ID_SHOVE, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
|
||||
if(target_held_item)
|
||||
var/obj/item/target_held_item = target.get_active_held_item()
|
||||
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
||||
target_held_item = null
|
||||
if(!target.has_movespeed_modifier(MOVESPEED_ID_SHOVE))
|
||||
target.add_movespeed_modifier(MOVESPEED_ID_SHOVE, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
|
||||
if(target_held_item)
|
||||
if(!HAS_TRAIT(target_held_item, TRAIT_NODROP))
|
||||
target.visible_message("<span class='danger'>[target.name]'s grip on \the [target_held_item] loosens!</span>",
|
||||
"<span class='danger'>Your grip on \the [target_held_item] loosens!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
|
||||
else if(target_held_item)
|
||||
target.dropItemToGround(target_held_item)
|
||||
knocked_item = TRUE
|
||||
append_message += ", loosening their grip on [target_held_item]"
|
||||
else
|
||||
append_message += ", but couldn't loose their grip on [target_held_item]"
|
||||
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
|
||||
else if(target_held_item)
|
||||
if(target.dropItemToGround(target_held_item))
|
||||
target.visible_message("<span class='danger'>[target.name] drops \the [target_held_item]!!</span>",
|
||||
"<span class='danger'>You drop \the [target_held_item]!!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
var/append_message = ""
|
||||
if(target_held_item)
|
||||
if(knocked_item)
|
||||
append_message = "causing them to drop [target_held_item]"
|
||||
else
|
||||
append_message = "loosening their grip on [target_held_item]"
|
||||
log_combat(user, target, "shoved", append_message)
|
||||
append_message += ", causing them to drop [target_held_item]"
|
||||
log_combat(user, target, "shoved", append_message)
|
||||
|
||||
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H, forced = FALSE)
|
||||
var/hit_percent = (100-(blocked+armor))/100
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -31,6 +31,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
. = ..()
|
||||
var/dwarf_hair = pick("Beard (Dwarf)", "Beard (Very Long)", "Beard (Long)") //beard roullette
|
||||
var/mob/living/carbon/human/H = C
|
||||
H.grant_language(/datum/language/dwarf)
|
||||
H.facial_hair_style = dwarf_hair
|
||||
H.update_hair()
|
||||
H.transform = H.transform.Scale(1, 0.8) //We use scale, and yeah. Dwarves can become gnomes with DWARFISM.
|
||||
@@ -41,6 +42,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
. = ..()
|
||||
H.transform = H.transform.Scale(1, 1.25) //And we undo it.
|
||||
UnregisterSignal(H, COMSIG_MOB_SAY) //We register handle_speech is not being used.
|
||||
H.remove_language(/datum/language/dwarf)
|
||||
|
||||
//Dwarf Name stuff
|
||||
/proc/dwarf_name() //hello caller: my name is urist mcuristurister
|
||||
@@ -52,21 +54,20 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
|
||||
//Dwarf Speech handling - Basically a filter/forces them to say things. The IC helper
|
||||
/datum/species/dwarf/proc/handle_speech(datum/source, list/speech_args)
|
||||
var/message = speech_args[SPEECH_MESSAGE]
|
||||
if(message[1] != "*")
|
||||
message = " [message]" //Credits to goonstation for the strings list.
|
||||
var/list/dwarf_words = strings("dwarf_replacement.json", "dwarf") //thanks to regex too.
|
||||
if(speech_args[SPEECH_LANGUAGE] != /datum/language/dwarf) // No accent if they speak their language
|
||||
if(message[1] != "*")
|
||||
message = " [message]" //Credits to goonstation for the strings list.
|
||||
var/list/dwarf_words = strings("dwarf_replacement.json", "dwarf") //thanks to regex too.
|
||||
for(var/key in dwarf_words) //Theres like 1459 words or something man.
|
||||
var/value = dwarf_words[key] //Thus they will always be in character.
|
||||
if(islist(value)) //Whether they like it or not.
|
||||
value = pick(value) //This could be drastically reduced if needed though.
|
||||
message = replacetextEx(message, " [uppertext(key)]", " [uppertext(value)]")
|
||||
message = replacetextEx(message, " [capitalize(key)]", " [capitalize(value)]")
|
||||
message = replacetextEx(message, " [key]", " [value]") //Also its scottish.
|
||||
|
||||
for(var/key in dwarf_words) //Theres like 1459 words or something man.
|
||||
var/value = dwarf_words[key] //Thus they will always be in character.
|
||||
if(islist(value)) //Whether they like it or not.
|
||||
value = pick(value) //This could be drastically reduced if needed though.
|
||||
|
||||
message = replacetextEx(message, " [uppertext(key)]", " [uppertext(value)]")
|
||||
message = replacetextEx(message, " [capitalize(key)]", " [capitalize(value)]")
|
||||
message = replacetextEx(message, " [key]", " [value]") //Also its scottish.
|
||||
|
||||
if(prob(3))
|
||||
message += pick(" By Armok!")
|
||||
if(prob(3))
|
||||
message += " By Armok!"
|
||||
speech_args[SPEECH_MESSAGE] = trim(message)
|
||||
|
||||
//This mostly exists because my testdwarf's liver died while trying to also not die due to no alcohol.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -358,7 +358,7 @@
|
||||
return
|
||||
|
||||
// No decay if formaldehyde in corpse or when the corpse is charred
|
||||
if(reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 15) || HAS_TRAIT(src, TRAIT_HUSK))
|
||||
if(reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 1) || HAS_TRAIT(src, TRAIT_HUSK))
|
||||
return
|
||||
|
||||
// Also no decay if corpse chilled or not organic/undead
|
||||
@@ -397,6 +397,8 @@
|
||||
if(O)
|
||||
O.on_life()
|
||||
else
|
||||
if(reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 1)) // No organ decay if the body contains formaldehyde.
|
||||
return
|
||||
for(var/V in internal_organs)
|
||||
var/obj/item/organ/O = V
|
||||
if(O)
|
||||
@@ -579,6 +581,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
|
||||
if(cultslurring)
|
||||
cultslurring = max(cultslurring-1, 0)
|
||||
|
||||
if(clockcultslurring)
|
||||
clockcultslurring = max(clockcultslurring-1, 0)
|
||||
|
||||
if(silent)
|
||||
silent = max(silent-1, 0)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user