Merge branch 'master' into upstream-merge-33055
This commit is contained in:
+3
-26
@@ -373,32 +373,9 @@
|
||||
ion = list()
|
||||
|
||||
/datum/ai_laws/proc/show_laws(who)
|
||||
|
||||
if (devillaws && devillaws.len) //Yes, devil laws go in FRONT of zeroth laws, as the devil must still obey it's ban/obligation.
|
||||
for(var/i in devillaws)
|
||||
to_chat(who, "666. [i]")
|
||||
|
||||
if (zeroth)
|
||||
to_chat(who, "0. [zeroth]")
|
||||
|
||||
for (var/index = 1, index <= ion.len, index++)
|
||||
var/law = ion[index]
|
||||
var/num = ionnum()
|
||||
to_chat(who, "[num]. [law]")
|
||||
|
||||
var/number = 1
|
||||
for (var/index = 1, index <= inherent.len, index++)
|
||||
var/law = inherent[index]
|
||||
|
||||
if (length(law) > 0)
|
||||
to_chat(who, "[number]. [law]")
|
||||
number++
|
||||
|
||||
for (var/index = 1, index <= supplied.len, index++)
|
||||
var/law = supplied[index]
|
||||
if (length(law) > 0)
|
||||
to_chat(who, "[number]. [law]")
|
||||
number++
|
||||
var/list/printable_laws = get_law_list(include_zeroth = TRUE)
|
||||
for(var/law in printable_laws)
|
||||
to_chat(who,law)
|
||||
|
||||
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
|
||||
if(force)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/datum/antagonist/abductor
|
||||
name = "Abductor"
|
||||
roundend_category = "abductors"
|
||||
job_rank = ROLE_ABDUCTOR
|
||||
var/datum/objective_team/abductor_team/team
|
||||
var/datum/team/abductor_team/team
|
||||
var/sub_role
|
||||
var/outfit
|
||||
var/landmark_type
|
||||
@@ -19,7 +20,7 @@
|
||||
landmark_type = /obj/effect/landmark/abductor/scientist
|
||||
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
|
||||
|
||||
/datum/antagonist/abductor/create_team(datum/objective_team/abductor_team/new_team)
|
||||
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
|
||||
if(!new_team)
|
||||
return
|
||||
if(!istype(new_team))
|
||||
@@ -70,3 +71,65 @@
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
var/datum/species/abductor/A = H.dna.species
|
||||
A.scientist = TRUE
|
||||
|
||||
|
||||
/datum/team/abductor_team
|
||||
member_name = "abductor"
|
||||
var/team_number
|
||||
var/list/datum/mind/abductees = list()
|
||||
|
||||
/datum/team/abductor_team/is_solo()
|
||||
return FALSE
|
||||
|
||||
/datum/team/abductor_team/proc/add_objective(datum/objective/O)
|
||||
O.team = src
|
||||
O.update_explanation_text()
|
||||
objectives += O
|
||||
|
||||
/datum/team/abductor_team/roundend_report()
|
||||
var/list/result = list()
|
||||
|
||||
var/won = TRUE
|
||||
for(var/datum/objective/O in objectives)
|
||||
if(!O.check_completion())
|
||||
won = FALSE
|
||||
if(won)
|
||||
result += "<span class='greentext big'>[name] team fulfilled its mission!</span>"
|
||||
else
|
||||
result += "<span class='redtext big'>[name] team failed its mission.</span>"
|
||||
|
||||
result += "<span class='header'>The abductors of [name] were:</span>"
|
||||
for(var/datum/mind/abductor_mind in members)
|
||||
result += printplayer(abductor_mind)
|
||||
result += printobjectives(abductor_mind)
|
||||
|
||||
return result.Join("<br>")
|
||||
|
||||
|
||||
/datum/antagonist/abductee
|
||||
name = "Abductee"
|
||||
roundend_category = "abductees"
|
||||
|
||||
/datum/antagonist/abductee/on_gain()
|
||||
give_objective()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/abductee/greet()
|
||||
to_chat(owner, "<span class='warning'><b>Your mind snaps!</b></span>")
|
||||
to_chat(owner, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/abductee/proc/give_objective()
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(istype(H))
|
||||
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
|
||||
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
|
||||
var/datum/objective/abductee/O = new objtype()
|
||||
objectives += O
|
||||
owner.objectives += objectives
|
||||
|
||||
/datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override)
|
||||
SSticker.mode.update_abductor_icons_added(mob_override ? mob_override.mind : owner)
|
||||
|
||||
/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
|
||||
SSticker.mode.update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
|
||||
@@ -2,6 +2,8 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
/datum/antagonist
|
||||
var/name = "Antagonist"
|
||||
var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
|
||||
var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
|
||||
var/datum/mind/owner //Mind that owns this datum
|
||||
var/silent = FALSE //Silent will prevent the gain/lose texts to show
|
||||
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
|
||||
@@ -9,6 +11,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/delete_on_mind_deletion = TRUE
|
||||
var/job_rank
|
||||
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
|
||||
var/list/objectives = list()
|
||||
|
||||
/datum/antagonist/New(datum/mind/new_owner)
|
||||
GLOB.antagonists += src
|
||||
@@ -46,7 +49,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
return
|
||||
|
||||
//Assign default team and creates one for one of a kind team antagonists
|
||||
/datum/antagonist/proc/create_team(datum/objective_team/team)
|
||||
/datum/antagonist/proc/create_team(datum/team/team)
|
||||
return
|
||||
|
||||
//Proc called when the datum is given to a mind.
|
||||
@@ -81,7 +84,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
var/datum/objective_team/team = get_team()
|
||||
var/datum/team/team = get_team()
|
||||
if(team)
|
||||
team.remove_member(owner)
|
||||
qdel(src)
|
||||
@@ -96,9 +99,62 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/proc/get_team()
|
||||
return
|
||||
|
||||
//Individual roundend report
|
||||
/datum/antagonist/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
if(!owner)
|
||||
CRASH("antagonist datum without owner")
|
||||
|
||||
report += printplayer(owner)
|
||||
|
||||
var/objectives_complete = TRUE
|
||||
if(owner.objectives.len)
|
||||
report += printobjectives(owner)
|
||||
for(var/datum/objective/objective in owner.objectives)
|
||||
if(!objective.check_completion())
|
||||
objectives_complete = FALSE
|
||||
break
|
||||
|
||||
if(owner.objectives.len == 0 || objectives_complete)
|
||||
report += "<span class='greentext big'>The [name] was successful!</span>"
|
||||
else
|
||||
report += "<span class='redtext big'>The [name] has failed!</span>"
|
||||
|
||||
return report.Join("<br>")
|
||||
|
||||
//Displayed at the start of roundend_category section, default to roundend_category header
|
||||
/datum/antagonist/proc/roundend_report_header()
|
||||
return "<span class='header'>The [roundend_category] were:</span><br>"
|
||||
|
||||
//Displayed at the end of roundend_category section
|
||||
/datum/antagonist/proc/roundend_report_footer()
|
||||
return
|
||||
|
||||
//Should probably be on ticker or job ss ?
|
||||
/proc/get_antagonists(antag_type,specific = FALSE)
|
||||
. = list()
|
||||
for(var/datum/antagonist/A in GLOB.antagonists)
|
||||
if(!specific && istype(A,antag_type) || specific && A.type == antag_type)
|
||||
. += A.owner
|
||||
. += A.owner
|
||||
|
||||
|
||||
|
||||
//This datum will autofill the name with special_role
|
||||
//Used as placeholder for minor antagonists, please create proper datums for these
|
||||
/datum/antagonist/auto_custom
|
||||
|
||||
/datum/antagonist/auto_custom/on_gain()
|
||||
..()
|
||||
name = owner.special_role
|
||||
//Add all objectives not already owned by other datums to this one.
|
||||
var/list/already_registered_objectives = list()
|
||||
for(var/datum/antagonist/A in owner.antag_datums)
|
||||
if(A == src)
|
||||
continue
|
||||
else
|
||||
already_registered_objectives |= A.objectives
|
||||
objectives = owner.objectives - already_registered_objectives
|
||||
|
||||
//This one is created by admin tools for custom objectives
|
||||
/datum/antagonist/custom
|
||||
@@ -2,12 +2,12 @@
|
||||
name = "Brother"
|
||||
job_rank = ROLE_BROTHER
|
||||
var/special_role = "blood brother"
|
||||
var/datum/objective_team/brother_team/team
|
||||
var/datum/team/brother_team/team
|
||||
|
||||
/datum/antagonist/brother/New(datum/mind/new_owner)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/brother/create_team(datum/objective_team/brother_team/new_team)
|
||||
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
|
||||
if(!new_team)
|
||||
return
|
||||
if(!istype(new_team))
|
||||
@@ -55,3 +55,71 @@
|
||||
|
||||
/datum/antagonist/brother/proc/finalize_brother()
|
||||
SSticker.mode.update_brother_icons_added(owner)
|
||||
|
||||
|
||||
/datum/team/brother_team
|
||||
name = "brotherhood"
|
||||
member_name = "blood brother"
|
||||
var/meeting_area
|
||||
|
||||
/datum/team/brother_team/is_solo()
|
||||
return FALSE
|
||||
|
||||
/datum/team/brother_team/proc/update_name()
|
||||
var/list/last_names = list()
|
||||
for(var/datum/mind/M in members)
|
||||
var/list/split_name = splittext(M.name," ")
|
||||
last_names += split_name[split_name.len]
|
||||
|
||||
name = last_names.Join(" & ")
|
||||
|
||||
/datum/team/brother_team/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
parts += "<span class='header'>The blood brothers of [name] were:</span>"
|
||||
for(var/datum/mind/M in members)
|
||||
parts += printplayer(M)
|
||||
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>"
|
||||
else
|
||||
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
win = FALSE
|
||||
objective_count++
|
||||
if(win)
|
||||
parts += "<span class='greentext'>The blood brothers were successful!</span>"
|
||||
else
|
||||
parts += "<span class='redtext'>The blood brothers have failed!</span>"
|
||||
|
||||
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
|
||||
|
||||
/datum/team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
|
||||
O.team = src
|
||||
if(needs_target)
|
||||
O.find_target()
|
||||
O.update_explanation_text()
|
||||
objectives += O
|
||||
|
||||
/datum/team/brother_team/proc/forge_brother_objectives()
|
||||
objectives = list()
|
||||
var/is_hijacker = prob(10)
|
||||
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
|
||||
forge_single_objective()
|
||||
if(is_hijacker)
|
||||
if(!locate(/datum/objective/hijack) in objectives)
|
||||
add_objective(new/datum/objective/hijack)
|
||||
else if(!locate(/datum/objective/escape) in objectives)
|
||||
add_objective(new/datum/objective/escape)
|
||||
|
||||
/datum/team/brother_team/proc/forge_single_objective()
|
||||
if(prob(50))
|
||||
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
|
||||
add_objective(new/datum/objective/destroy, TRUE)
|
||||
else if(prob(30))
|
||||
add_objective(new/datum/objective/maroon, TRUE)
|
||||
else
|
||||
add_objective(new/datum/objective/assassinate, TRUE)
|
||||
else
|
||||
add_objective(new/datum/objective/steal, TRUE)
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
/datum/antagonist/changeling
|
||||
name = "Changeling"
|
||||
roundend_category = "changelings"
|
||||
job_rank = ROLE_CHANGELING
|
||||
|
||||
var/you_are_greet = TRUE
|
||||
var/give_objectives = TRUE
|
||||
var/list/objectives = list()
|
||||
var/team_mode = FALSE //Should assign team objectives ?
|
||||
|
||||
//Changeling Stuff
|
||||
@@ -478,4 +478,35 @@
|
||||
/datum/antagonist/changeling/xenobio
|
||||
name = "Xenobio Changeling"
|
||||
give_objectives = FALSE
|
||||
show_in_roundend = FALSE //These are here for admin tracking purposes only
|
||||
you_are_greet = FALSE
|
||||
|
||||
/datum/antagonist/changeling/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
var/changelingwin = 1
|
||||
if(!owner.current)
|
||||
changelingwin = 0
|
||||
|
||||
parts += printplayer(owner)
|
||||
|
||||
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
|
||||
parts += "<b>Changeling ID:</b> [changelingID]."
|
||||
parts += "<b>Genomes Extracted:</b> [absorbedcount]"
|
||||
parts += " "
|
||||
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>"
|
||||
else
|
||||
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
changelingwin = 0
|
||||
count++
|
||||
|
||||
if(changelingwin)
|
||||
parts += "<span class='greentext'>The changeling was successful!</span>"
|
||||
else
|
||||
parts += "<span class='redtext'>The changeling has failed.</span>"
|
||||
|
||||
return parts.Join("<br>")
|
||||
@@ -1,8 +1,11 @@
|
||||
//CLOCKCULT PROOF OF CONCEPT
|
||||
/datum/antagonist/clockcult
|
||||
name = "Clock Cultist"
|
||||
var/datum/action/innate/hierophant/hierophant_network = new()
|
||||
roundend_category = "clock cultists"
|
||||
job_rank = ROLE_SERVANT_OF_RATVAR
|
||||
var/datum/action/innate/hierophant/hierophant_network = new()
|
||||
var/datum/team/clockcult/clock_team
|
||||
var/make_team = TRUE //This should be only false for tutorial scarabs
|
||||
|
||||
/datum/antagonist/clockcult/silent
|
||||
silent = TRUE
|
||||
@@ -11,6 +14,22 @@
|
||||
qdel(hierophant_network)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/clockcult/get_team()
|
||||
return clock_team
|
||||
|
||||
/datum/antagonist/clockcult/create_team(datum/team/clockcult/new_team)
|
||||
if(!new_team && make_team)
|
||||
//TODO blah blah same as the others, allow multiple
|
||||
for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
|
||||
if(H.clock_team)
|
||||
clock_team = H.clock_team
|
||||
return
|
||||
clock_team = new /datum/team/clockcult
|
||||
return
|
||||
if(make_team && !istype(new_team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
clock_team = new_team
|
||||
|
||||
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
|
||||
. = ..()
|
||||
if(.)
|
||||
@@ -156,7 +175,7 @@
|
||||
SSticker.mode.servants_of_ratvar -= owner
|
||||
SSticker.mode.update_servant_icons_removed(owner)
|
||||
if(!silent)
|
||||
owner.current.visible_message("<span class='big'>[owner] seems to have remembered their true allegiance!</span>", ignored_mob = owner.current)
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner] seems to have remembered their true allegiance!</span>", ignored_mob = owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
|
||||
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
owner.wipe_memory()
|
||||
@@ -164,3 +183,35 @@
|
||||
if(iscyborg(owner.current))
|
||||
to_chat(owner.current, "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>")
|
||||
. = ..()
|
||||
|
||||
|
||||
/datum/team/clockcult
|
||||
name = "Clockcult"
|
||||
var/list/objective
|
||||
var/datum/mind/eminence
|
||||
|
||||
/datum/team/clockcult/proc/check_clockwork_victory()
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/team/clockcult/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
if(check_clockwork_victory())
|
||||
parts += "<span class='greentext big'>Ratvar's servants defended the Ark until its activation!</span>"
|
||||
else
|
||||
parts += "<span class='redtext big'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
|
||||
parts += " "
|
||||
parts += "<b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
|
||||
parts += "<b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
|
||||
for(var/i in SSticker.scripture_states)
|
||||
if(i != SCRIPTURE_DRIVER)
|
||||
parts += "<b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
|
||||
if(eminence)
|
||||
parts += "<span class='header'>The Eminence was:</span> [printplayer(eminence)]"
|
||||
if(members.len)
|
||||
parts += "<span class='header'>Ratvar's servants were:</span>"
|
||||
parts += printplayerlist(members - eminence)
|
||||
|
||||
return "<div class='panel clockborder'>[parts.Join("<br>")]</div>"
|
||||
+197
-62
@@ -2,84 +2,103 @@
|
||||
|
||||
/datum/antagonist/cult
|
||||
name = "Cultist"
|
||||
roundend_category = "cultists"
|
||||
var/datum/action/innate/cult/comm/communion = new
|
||||
var/datum/action/innate/cult/mastervote/vote = new
|
||||
job_rank = ROLE_CULTIST
|
||||
var/ignore_implant = FALSE
|
||||
var/give_equipment = FALSE
|
||||
|
||||
var/datum/team/cult/cult_team
|
||||
|
||||
/datum/antagonist/cult/get_team()
|
||||
return cult_team
|
||||
|
||||
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
|
||||
if(!new_team)
|
||||
//todo remove this and allow admin buttons to create more than one cult
|
||||
for(var/datum/antagonist/cult/H in GLOB.antagonists)
|
||||
if(H.cult_team)
|
||||
cult_team = H.cult_team
|
||||
return
|
||||
cult_team = new /datum/team/cult
|
||||
cult_team.setup_objectives()
|
||||
return
|
||||
if(!istype(new_team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
cult_team = new_team
|
||||
|
||||
/datum/antagonist/cult/proc/add_objectives()
|
||||
objectives |= cult_team.objectives
|
||||
owner.objectives |= objectives
|
||||
|
||||
/datum/antagonist/cult/proc/remove_objectives()
|
||||
owner.objectives -= objectives
|
||||
|
||||
/datum/antagonist/cult/Destroy()
|
||||
QDEL_NULL(communion)
|
||||
QDEL_NULL(vote)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/cult/proc/add_objectives()
|
||||
var/list/target_candidates = list()
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && (player != owner) && player.stat != DEAD)
|
||||
target_candidates += player.mind
|
||||
if(target_candidates.len == 0)
|
||||
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && (player != owner) && player.stat != DEAD)
|
||||
target_candidates += player.mind
|
||||
listclearnulls(target_candidates)
|
||||
if(LAZYLEN(target_candidates))
|
||||
GLOB.sac_mind = pick(target_candidates)
|
||||
if(!GLOB.sac_mind)
|
||||
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
|
||||
else
|
||||
var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
|
||||
var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
|
||||
reshape.Shift(SOUTH, 4)
|
||||
reshape.Shift(EAST, 1)
|
||||
reshape.Crop(7,4,26,31)
|
||||
reshape.Crop(-5,-3,26,30)
|
||||
GLOB.sac_image = reshape
|
||||
else
|
||||
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
|
||||
GLOB.sac_complete = TRUE
|
||||
SSticker.mode.cult_objectives += "sacrifice"
|
||||
if(!GLOB.summon_spots.len)
|
||||
while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
|
||||
var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
|
||||
if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
|
||||
GLOB.summon_spots += summon
|
||||
SSticker.mode.cult_objectives += "eldergod"
|
||||
|
||||
/datum/antagonist/cult/proc/cult_memorization(datum/mind/cult_mind)
|
||||
var/mob/living/current = cult_mind.current
|
||||
for(var/obj_count = 1,obj_count <= SSticker.mode.cult_objectives.len,obj_count++)
|
||||
var/explanation
|
||||
switch(SSticker.mode.cult_objectives[obj_count])
|
||||
if("sacrifice")
|
||||
if(GLOB.sac_mind)
|
||||
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
|
||||
else
|
||||
explanation = "The veil has already been weakened here, proceed to the final objective."
|
||||
GLOB.sac_complete = TRUE
|
||||
if("eldergod")
|
||||
explanation = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. <b>The summoning can only be accomplished in [english_list(GLOB.summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
|
||||
if(!silent)
|
||||
to_chat(current, "<B>Objective #[obj_count]</B>: [explanation]")
|
||||
cult_mind.memory += "<B>Objective #[obj_count]</B>: [explanation]<BR>"
|
||||
|
||||
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
|
||||
. = ..()
|
||||
if(. && !ignore_implant)
|
||||
. = is_convertable_to_cult(new_owner.current)
|
||||
. = is_convertable_to_cult(new_owner.current,cult_team)
|
||||
|
||||
/datum/antagonist/cult/greet()
|
||||
to_chat(owner, "<span class='userdanger'>You are a member of the cult!</span>")
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/cult/on_gain()
|
||||
. = ..()
|
||||
var/mob/living/current = owner.current
|
||||
if(!LAZYLEN(SSticker.mode.cult_objectives))
|
||||
add_objectives()
|
||||
add_objectives()
|
||||
if(give_equipment)
|
||||
equip_cultist()
|
||||
SSticker.mode.cult += owner // Only add after they've been given objectives
|
||||
cult_memorization(owner)
|
||||
SSticker.mode.update_cult_icons_added(owner)
|
||||
current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(GLOB.blood_target && GLOB.blood_target_image && current.client)
|
||||
current.client.images += GLOB.blood_target_image
|
||||
|
||||
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
|
||||
current.client.images += cult_team.blood_target_image
|
||||
|
||||
|
||||
/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
|
||||
var/mob/living/carbon/H = owner.current
|
||||
if(!istype(H))
|
||||
return
|
||||
if (owner.assigned_role == "Clown")
|
||||
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
if(tome)
|
||||
. += cult_give_item(/obj/item/tome, H)
|
||||
else
|
||||
. += cult_give_item(/obj/item/paper/talisman/supply, H)
|
||||
to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.</span>")
|
||||
|
||||
|
||||
/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
|
||||
var/list/slots = list(
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
)
|
||||
|
||||
var/T = new item_path(mob)
|
||||
var/item_name = initial(item_path.name)
|
||||
var/where = mob.equip_in_one_of_slots(T, slots)
|
||||
if(!where)
|
||||
to_chat(mob, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
|
||||
return 0
|
||||
else
|
||||
to_chat(mob, "<span class='danger'>You have a [item_name] in your [where].</span>")
|
||||
if(where == "backpack")
|
||||
var/obj/item/storage/B = mob.back
|
||||
B.orient2hud(mob)
|
||||
B.show_to(mob)
|
||||
return 1
|
||||
|
||||
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
|
||||
. = ..()
|
||||
@@ -89,7 +108,7 @@
|
||||
current.faction |= "cult"
|
||||
current.grant_language(/datum/language/narsie)
|
||||
current.verbs += /mob/living/proc/cult_help
|
||||
if(!GLOB.cult_mastered)
|
||||
if(!cult_team.cult_mastered)
|
||||
vote.Grant(current)
|
||||
communion.Grant(current)
|
||||
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
|
||||
@@ -107,6 +126,7 @@
|
||||
current.clear_alert("bloodsense")
|
||||
|
||||
/datum/antagonist/cult/on_removal()
|
||||
remove_objectives()
|
||||
owner.wipe_memory()
|
||||
SSticker.mode.cult -= owner
|
||||
SSticker.mode.update_cult_icons_removed(owner)
|
||||
@@ -114,8 +134,8 @@
|
||||
owner.current.visible_message("<span class='big'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>", ignored_mob = owner.current)
|
||||
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
|
||||
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
|
||||
owner.current.client.images -= GLOB.blood_target_image
|
||||
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
|
||||
owner.current.client.images -= cult_team.blood_target_image
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/cult/master
|
||||
@@ -145,7 +165,7 @@
|
||||
var/mob/living/current = owner.current
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
if(!GLOB.reckoning_complete)
|
||||
if(!cult_team.reckoning_complete)
|
||||
reckoning.Grant(current)
|
||||
bloodmark.Grant(current)
|
||||
throwing.Grant(current)
|
||||
@@ -162,3 +182,118 @@
|
||||
throwing.Remove(current)
|
||||
current.update_action_buttons_icon()
|
||||
current.remove_status_effect(/datum/status_effect/cult_master)
|
||||
|
||||
/datum/team/cult
|
||||
name = "Cult"
|
||||
|
||||
var/blood_target
|
||||
var/image/blood_target_image
|
||||
var/blood_target_reset_timer
|
||||
|
||||
var/cult_vote_called = FALSE
|
||||
var/cult_mastered = FALSE
|
||||
var/reckoning_complete = FALSE
|
||||
|
||||
|
||||
/datum/team/cult/proc/setup_objectives()
|
||||
//SAC OBJECTIVE , todo: move this to objective internals
|
||||
var/list/target_candidates = list()
|
||||
var/datum/objective/sacrifice/sac_objective = new
|
||||
sac_objective.team = src
|
||||
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && !is_convertable_to_cult(player) && player.stat != DEAD)
|
||||
target_candidates += player.mind
|
||||
|
||||
if(target_candidates.len == 0)
|
||||
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(player.mind && !player.mind.has_antag_datum(ANTAG_DATUM_CULT) && player.stat != DEAD)
|
||||
target_candidates += player.mind
|
||||
listclearnulls(target_candidates)
|
||||
if(LAZYLEN(target_candidates))
|
||||
sac_objective.target = pick(target_candidates)
|
||||
sac_objective.update_explanation_text()
|
||||
|
||||
var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
|
||||
var/datum/preferences/sacface = sac_objective.target.current.client.prefs
|
||||
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
|
||||
reshape.Shift(SOUTH, 4)
|
||||
reshape.Shift(EAST, 1)
|
||||
reshape.Crop(7,4,26,31)
|
||||
reshape.Crop(-5,-3,26,30)
|
||||
sac_objective.sac_image = reshape
|
||||
|
||||
objectives += sac_objective
|
||||
else
|
||||
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
|
||||
|
||||
|
||||
//SUMMON OBJECTIVE
|
||||
|
||||
var/datum/objective/eldergod/summon_objective = new()
|
||||
summon_objective.team = src
|
||||
objectives += summon_objective
|
||||
|
||||
/datum/objective/sacrifice
|
||||
var/sacced = FALSE
|
||||
var/sac_image
|
||||
|
||||
/datum/objective/sacrifice/check_completion()
|
||||
return sacced || completed
|
||||
|
||||
/datum/objective/sacrifice/update_explanation_text()
|
||||
if(target && !sacced)
|
||||
explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
|
||||
else
|
||||
explanation_text = "The veil has already been weakened here, proceed to the final objective."
|
||||
|
||||
/datum/objective/eldergod
|
||||
var/summoned = FALSE
|
||||
var/list/summon_spots = list()
|
||||
|
||||
/datum/objective/eldergod/New()
|
||||
..()
|
||||
var/sanity = 0
|
||||
while(summon_spots.len < SUMMON_POSSIBILITIES && sanity < 100)
|
||||
var/area/summon = pick(GLOB.sortedAreas - summon_spots)
|
||||
if(summon && (summon.z in GLOB.station_z_levels) && summon.valid_territory)
|
||||
summon_spots += summon
|
||||
sanity++
|
||||
update_explanation_text()
|
||||
|
||||
/datum/objective/eldergod/update_explanation_text()
|
||||
explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. <b>The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
|
||||
|
||||
/datum/objective/eldergod/check_completion()
|
||||
return summoned || completed
|
||||
|
||||
/datum/team/cult/proc/check_cult_victory()
|
||||
for(var/datum/objective/O in objectives)
|
||||
if(!O.check_completion())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/team/cult/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
if(check_cult_victory())
|
||||
parts += "<span class='greentext big'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>"
|
||||
else
|
||||
parts += "<span class='redtext big'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>"
|
||||
|
||||
if(objectives.len)
|
||||
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>"
|
||||
else
|
||||
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
count++
|
||||
|
||||
if(members.len)
|
||||
parts += "<span class='header'>The cultists were:</span>"
|
||||
parts += printplayerlist(members)
|
||||
|
||||
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
|
||||
@@ -1,5 +1,6 @@
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
roundend_category = "traitors"
|
||||
job_rank = ROLE_TRAITOR
|
||||
var/should_specialise = FALSE //do we split into AI and human, set to true on inital assignment only
|
||||
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
|
||||
@@ -8,7 +9,6 @@
|
||||
var/employer = "The Syndicate"
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/list/objectives_given = list()
|
||||
|
||||
/datum/antagonist/traitor/human
|
||||
var/should_equip = TRUE
|
||||
@@ -52,9 +52,9 @@
|
||||
if(should_specialise)
|
||||
return ..()//we never did any of this anyway
|
||||
SSticker.mode.traitors -= owner
|
||||
for(var/O in objectives_given)
|
||||
for(var/O in objectives)
|
||||
owner.objectives -= O
|
||||
objectives_given = list()
|
||||
objectives = list()
|
||||
if(!silent && owner.current)
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
|
||||
owner.special_role = null
|
||||
@@ -71,11 +71,11 @@
|
||||
|
||||
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
|
||||
owner.objectives += O
|
||||
objectives_given += O
|
||||
objectives += O
|
||||
|
||||
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
|
||||
owner.objectives -= O
|
||||
objectives_given -= O
|
||||
objectives -= O
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
return
|
||||
@@ -294,3 +294,53 @@
|
||||
where = "In your [equipped_slot]"
|
||||
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
|
||||
|
||||
//TODO Collate
|
||||
/datum/antagonist/traitor/roundend_report()
|
||||
var/list/result = list()
|
||||
|
||||
var/traitorwin = TRUE
|
||||
|
||||
result += printplayer(owner)
|
||||
|
||||
var/TC_uses = 0
|
||||
var/uplink_true = FALSE
|
||||
var/purchases = ""
|
||||
for(var/datum/component/uplink/H in GLOB.uplinks)
|
||||
if(H && H.owner && H.owner == owner.key)
|
||||
TC_uses += H.spent_telecrystals
|
||||
uplink_true = TRUE
|
||||
purchases += H.purchase_log.generate_render(FALSE)
|
||||
|
||||
var/objectives_text = ""
|
||||
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>"
|
||||
else
|
||||
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
traitorwin = FALSE
|
||||
count++
|
||||
|
||||
if(uplink_true)
|
||||
var/uplink_text = "(used [TC_uses] TC) [purchases]"
|
||||
if(TC_uses==0 && traitorwin)
|
||||
var/static/icon/badass = icon('icons/badass.dmi', "badass")
|
||||
uplink_text += "<BIG>[icon2html(badass, world)]</BIG>"
|
||||
result += uplink_text
|
||||
|
||||
result += objectives_text
|
||||
|
||||
var/special_role_text = lowertext(name)
|
||||
|
||||
if(traitorwin)
|
||||
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
|
||||
else
|
||||
result += "<span class='redtext'>The [special_role_text] has failed!</span>"
|
||||
SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
|
||||
|
||||
return result.Join("<br>")
|
||||
|
||||
/datum/antagonist/traitor/roundend_report_footer()
|
||||
return "<br><b>The code phrases were:</b> <span class='codephrase'>[GLOB.syndicate_code_phrase]</span><br>\
|
||||
<b>The code responses were:</b> <span class='codephrase'>[GLOB.syndicate_code_response]</span><br>"
|
||||
@@ -86,6 +86,7 @@ GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon",
|
||||
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
|
||||
/datum/antagonist/devil
|
||||
name = "Devil"
|
||||
roundend_category = "devils"
|
||||
job_rank = ROLE_DEVIL
|
||||
//Don't delete upon mind destruction, otherwise soul re-selling will break.
|
||||
delete_on_mind_deletion = FALSE
|
||||
@@ -508,6 +509,35 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
owner.RemoveSpell(S)
|
||||
.=..()
|
||||
|
||||
/datum/antagonist/devil/proc/printdevilinfo()
|
||||
var/list/parts = list()
|
||||
parts += "The devil's true name is: [truename]"
|
||||
parts += "The devil's bans were:"
|
||||
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
|
||||
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
|
||||
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
|
||||
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
|
||||
return parts.Join("<br>")
|
||||
|
||||
/datum/antagonist/devil/roundend_report()
|
||||
var/list/parts = list()
|
||||
parts += printplayer(owner)
|
||||
parts += printdevilinfo()
|
||||
parts += printobjectives(owner)
|
||||
return parts.Join("<br>")
|
||||
|
||||
/datum/antagonist/devil/roundend_report_footer()
|
||||
//sintouched go here for now as a hack , TODO proper antag datum for these
|
||||
var/list/parts = list()
|
||||
if(SSticker.mode.sintouched.len)
|
||||
parts += "<span class='header'>The sintouched were:</span>"
|
||||
var/list/sintouchedUnique = uniqueList(SSticker.mode.sintouched)
|
||||
for(var/S in sintouchedUnique)
|
||||
var/datum/mind/sintouched_mind = S
|
||||
parts += printplayer(sintouched_mind)
|
||||
parts += printobjectives(sintouched_mind)
|
||||
return parts.Join("<br>")
|
||||
|
||||
//A simple super light weight datum for the codex gigas.
|
||||
/datum/fakeDevil
|
||||
var/truename
|
||||
|
||||
@@ -37,19 +37,20 @@
|
||||
else if(M.assigned_role in GLOB.command_positions)
|
||||
possible_targets[M] = 1 //good-guy
|
||||
|
||||
var/list/objectives = list(1,2,3,4)
|
||||
while(owner.objectives.len < quantity)
|
||||
switch(pick_n_take(objectives))
|
||||
var/list/possible_objectives = list(1,2,3,4)
|
||||
|
||||
while(objectives.len < quantity)
|
||||
switch(pick_n_take(possible_objectives))
|
||||
if(1) //research
|
||||
var/datum/objective/download/O = new /datum/objective/download()
|
||||
O.owner = owner
|
||||
O.gen_amount_goal()
|
||||
owner.objectives += O
|
||||
objectives += O
|
||||
|
||||
if(2) //steal
|
||||
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
|
||||
O.owner = owner
|
||||
owner.objectives += O
|
||||
objectives += O
|
||||
|
||||
if(3) //protect/kill
|
||||
if(!possible_targets.len) continue
|
||||
@@ -63,13 +64,13 @@
|
||||
O.owner = owner
|
||||
O.target = M
|
||||
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
|
||||
owner.objectives += O
|
||||
objectives += O
|
||||
else //protect
|
||||
var/datum/objective/protect/O = new /datum/objective/protect()
|
||||
O.owner = owner
|
||||
O.target = M
|
||||
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
|
||||
owner.objectives += O
|
||||
objectives += O
|
||||
if(4) //debrain/capture
|
||||
if(!possible_targets.len) continue
|
||||
var/selected = rand(1,possible_targets.len)
|
||||
@@ -82,17 +83,17 @@
|
||||
O.owner = owner
|
||||
O.target = M
|
||||
O.explanation_text = "Steal the brain of [M.current.real_name]."
|
||||
owner.objectives += O
|
||||
objectives += O
|
||||
else //capture
|
||||
var/datum/objective/capture/O = new /datum/objective/capture()
|
||||
O.owner = owner
|
||||
O.gen_amount_goal()
|
||||
owner.objectives += O
|
||||
objectives += O
|
||||
else
|
||||
break
|
||||
var/datum/objective/O = new /datum/objective/survive()
|
||||
O.owner = owner
|
||||
owner.objectives += O
|
||||
owner.objectives |= objectives
|
||||
|
||||
|
||||
/proc/remove_ninja(mob/living/L)
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
#define NUKE_RESULT_FLUKE 0
|
||||
#define NUKE_RESULT_NUKE_WIN 1
|
||||
#define NUKE_RESULT_CREW_WIN 2
|
||||
#define NUKE_RESULT_CREW_WIN_SYNDIES_DEAD 3
|
||||
#define NUKE_RESULT_DISK_LOST 4
|
||||
#define NUKE_RESULT_DISK_STOLEN 5
|
||||
#define NUKE_RESULT_NOSURVIVORS 6
|
||||
#define NUKE_RESULT_WRONG_STATION 7
|
||||
#define NUKE_RESULT_WRONG_STATION_DEAD 8
|
||||
|
||||
/datum/antagonist/nukeop
|
||||
name = "Nuclear Operative"
|
||||
roundend_category = "syndicate operatives" //just in case
|
||||
job_rank = ROLE_OPERATIVE
|
||||
var/datum/team/nuclear/nuke_team
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
var/nukeop_outfit = /datum/outfit/syndicate
|
||||
|
||||
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
|
||||
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
|
||||
opshud.join_hud(M)
|
||||
set_antag_hud(M, "synd")
|
||||
|
||||
/datum/antagonist/nukeop/proc/update_synd_icons_removed(mob/living/M)
|
||||
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
|
||||
opshud.leave_hud(M)
|
||||
set_antag_hud(M, null)
|
||||
|
||||
/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_synd_icons_added(M)
|
||||
|
||||
/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/M = mob_override || owner.current
|
||||
update_synd_icons_removed(M)
|
||||
|
||||
/datum/antagonist/nukeop/proc/equip_op()
|
||||
if(!ishuman(owner.current))
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
|
||||
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
|
||||
|
||||
H.equipOutfit(nukeop_outfit)
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/nukeop/greet()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
|
||||
to_chat(owner, "<span class='notice'>You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!</span>")
|
||||
owner.announce_objectives()
|
||||
return
|
||||
|
||||
/datum/antagonist/nukeop/on_gain()
|
||||
give_alias()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
equip_op()
|
||||
memorize_code()
|
||||
if(send_to_spawnpoint)
|
||||
move_to_spawnpoint()
|
||||
|
||||
/datum/antagonist/nukeop/get_team()
|
||||
return nuke_team
|
||||
|
||||
/datum/antagonist/nukeop/proc/assign_nuke()
|
||||
if(nuke_team && !nuke_team.tracked_nuke)
|
||||
nuke_team.memorized_code = random_nukecode()
|
||||
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
|
||||
if(nuke)
|
||||
nuke_team.tracked_nuke = nuke
|
||||
if(nuke.r_code == "ADMIN")
|
||||
nuke.r_code = nuke_team.memorized_code
|
||||
else //Already set by admins/something else?
|
||||
nuke_team.memorized_code = nuke.r_code
|
||||
else
|
||||
stack_trace("Syndicate nuke not found during nuke team creation.")
|
||||
nuke_team.memorized_code = null
|
||||
|
||||
/datum/antagonist/nukeop/proc/give_alias()
|
||||
if(nuke_team && nuke_team.syndicate_name)
|
||||
var/number = 1
|
||||
number = nuke_team.members.Find(owner)
|
||||
owner.current.real_name = "[nuke_team.syndicate_name] Operative #[number]"
|
||||
|
||||
/datum/antagonist/nukeop/proc/memorize_code()
|
||||
if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
|
||||
owner.store_memory("<B>[nuke_team.tracked_nuke] Code</B>: [nuke_team.memorized_code]", 0, 0)
|
||||
to_chat(owner, "The nuclear authorization code is: <B>[nuke_team.memorized_code]</B>")
|
||||
else
|
||||
to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
|
||||
|
||||
/datum/antagonist/nukeop/proc/forge_objectives()
|
||||
if(nuke_team)
|
||||
owner.objectives |= nuke_team.objectives
|
||||
|
||||
/datum/antagonist/nukeop/proc/move_to_spawnpoint()
|
||||
var/team_number = 1
|
||||
if(nuke_team)
|
||||
team_number = nuke_team.members.Find(owner)
|
||||
owner.current.forceMove(GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1])
|
||||
|
||||
/datum/antagonist/nukeop/leader/move_to_spawnpoint()
|
||||
owner.current.forceMove(pick(GLOB.nukeop_leader_start))
|
||||
|
||||
/datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team)
|
||||
if(!new_team)
|
||||
if(!always_new_team)
|
||||
for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
|
||||
if(N.nuke_team)
|
||||
nuke_team = N.nuke_team
|
||||
return
|
||||
nuke_team = new /datum/team/nuclear
|
||||
nuke_team.update_objectives()
|
||||
assign_nuke() //This is bit ugly
|
||||
return
|
||||
if(!istype(new_team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
nuke_team = new_team
|
||||
|
||||
/datum/antagonist/nukeop/leader
|
||||
name = "Nuclear Operative Leader"
|
||||
nukeop_outfit = /datum/outfit/syndicate/leader
|
||||
always_new_team = TRUE
|
||||
var/title
|
||||
|
||||
/datum/antagonist/nukeop/leader/memorize_code()
|
||||
..()
|
||||
if(nuke_team && nuke_team.memorized_code)
|
||||
var/obj/item/paper/P = new
|
||||
P.info = "The nuclear authorization code is: <b>[nuke_team.memorized_code]</b>"
|
||||
P.name = "nuclear bomb code"
|
||||
var/mob/living/carbon/human/H = owner.current
|
||||
if(!istype(H))
|
||||
P.forceMove(get_turf(H))
|
||||
else
|
||||
H.put_in_hands(P, TRUE)
|
||||
H.update_icons()
|
||||
|
||||
/datum/antagonist/nukeop/leader/give_alias()
|
||||
title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
|
||||
if(nuke_team && nuke_team.syndicate_name)
|
||||
owner.current.real_name = "[nuke_team.syndicate_name] [title]"
|
||||
else
|
||||
owner.current.real_name = "Syndicate [title]"
|
||||
|
||||
/datum/antagonist/nukeop/leader/greet()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
|
||||
to_chat(owner, "<B>You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.</B>")
|
||||
to_chat(owner, "<B>If you feel you are not up to this task, give your ID to another operative.</B>")
|
||||
to_chat(owner, "<B>In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.</B>")
|
||||
owner.announce_objectives()
|
||||
addtimer(CALLBACK(src, .proc/nuketeam_name_assign), 1)
|
||||
|
||||
|
||||
/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
|
||||
if(!nuke_team)
|
||||
return
|
||||
nuke_team.rename_team(ask_name())
|
||||
|
||||
/datum/team/nuclear/proc/rename_team(new_name)
|
||||
syndicate_name = new_name
|
||||
name = "[syndicate_name] Team"
|
||||
for(var/I in members)
|
||||
var/datum/mind/synd_mind = I
|
||||
var/mob/living/carbon/human/H = synd_mind.current
|
||||
if(!istype(H))
|
||||
continue
|
||||
var/chosen_name = H.dna.species.random_name(H.gender,0,syndicate_name)
|
||||
H.fully_replace_character_name(H.real_name,chosen_name)
|
||||
|
||||
/datum/antagonist/nukeop/leader/proc/ask_name()
|
||||
var/randomname = pick(GLOB.last_names)
|
||||
var/newname = stripped_input(owner.current,"You are the nuke operative [title]. Please choose a last name for your family.", "Name change",randomname)
|
||||
if (!newname)
|
||||
newname = randomname
|
||||
else
|
||||
newname = reject_bad_name(newname)
|
||||
if(!newname)
|
||||
newname = randomname
|
||||
|
||||
return capitalize(newname)
|
||||
|
||||
/datum/antagonist/nukeop/lone
|
||||
name = "Lone Operative"
|
||||
always_new_team = TRUE
|
||||
send_to_spawnpoint = FALSE //Handled by event
|
||||
nukeop_outfit = /datum/outfit/syndicate/full
|
||||
|
||||
/datum/antagonist/nukeop/lone/assign_nuke()
|
||||
if(nuke_team && !nuke_team.tracked_nuke)
|
||||
nuke_team.memorized_code = random_nukecode()
|
||||
var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.nuke_list
|
||||
if(nuke)
|
||||
nuke_team.tracked_nuke = nuke
|
||||
if(nuke.r_code == "ADMIN")
|
||||
nuke.r_code = nuke_team.memorized_code
|
||||
else //Already set by admins/something else?
|
||||
nuke_team.memorized_code = nuke.r_code
|
||||
else
|
||||
stack_trace("Station self destruct ot found during lone op team creation.")
|
||||
nuke_team.memorized_code = null
|
||||
|
||||
/datum/team/nuclear
|
||||
var/syndicate_name
|
||||
var/obj/machinery/nuclearbomb/tracked_nuke
|
||||
var/core_objective = /datum/objective/nuclear
|
||||
var/memorized_code
|
||||
|
||||
/datum/team/nuclear/New()
|
||||
..()
|
||||
syndicate_name = syndicate_name()
|
||||
|
||||
/datum/team/nuclear/proc/update_objectives()
|
||||
if(core_objective)
|
||||
var/datum/objective/O = new core_objective
|
||||
O.team = src
|
||||
objectives += O
|
||||
|
||||
/datum/team/nuclear/proc/disk_rescued()
|
||||
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
|
||||
if(!D.onCentCom())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/team/nuclear/proc/operatives_dead()
|
||||
for(var/I in members)
|
||||
var/datum/mind/operative_mind = I
|
||||
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/team/nuclear/proc/syndies_escaped()
|
||||
var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate")
|
||||
return (S && (S.z == ZLEVEL_CENTCOM || S.z == ZLEVEL_TRANSIT))
|
||||
|
||||
/datum/team/nuclear/proc/get_result()
|
||||
var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
|
||||
var/disk_rescued = disk_rescued()
|
||||
var/syndies_didnt_escape = !syndies_escaped()
|
||||
var/station_was_nuked = SSticker.mode.station_was_nuked
|
||||
var/nuke_off_station = SSticker.mode.nuke_off_station
|
||||
|
||||
if(nuke_off_station == NUKE_SYNDICATE_BASE)
|
||||
return NUKE_RESULT_FLUKE
|
||||
else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
|
||||
return NUKE_RESULT_NUKE_WIN
|
||||
else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
|
||||
return NUKE_RESULT_NOSURVIVORS
|
||||
else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
|
||||
return NUKE_RESULT_WRONG_STATION
|
||||
else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
|
||||
return NUKE_RESULT_WRONG_STATION_DEAD
|
||||
else if ((disk_rescued || evacuation) && operatives_dead())
|
||||
return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD
|
||||
else if (disk_rescued)
|
||||
return NUKE_RESULT_CREW_WIN
|
||||
else if (!disk_rescued && operatives_dead())
|
||||
return NUKE_RESULT_DISK_LOST
|
||||
else if (!disk_rescued && evacuation)
|
||||
return NUKE_RESULT_DISK_STOLEN
|
||||
else
|
||||
return //Undefined result
|
||||
|
||||
/datum/team/nuclear/roundend_report()
|
||||
var/list/parts = list()
|
||||
parts += "<span class='header'>[syndicate_name] Operatives:</span>"
|
||||
|
||||
switch(get_result())
|
||||
if(NUKE_RESULT_FLUKE)
|
||||
parts += "<span class='redtext big'>Humiliating Syndicate Defeat</span>"
|
||||
parts += "<B>The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed!</B> Next time, don't lose the nuke!"
|
||||
if(NUKE_RESULT_NUKE_WIN)
|
||||
parts += "<span class='greentext big'>Syndicate Major Victory!</span>"
|
||||
parts += "<B>[syndicate_name] operatives have destroyed [station_name()]!</B>"
|
||||
if(NUKE_RESULT_NOSURVIVORS)
|
||||
parts += "<span class='neutraltext big'>Total Annihilation</span>"
|
||||
parts += "<B>[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion.</B> Next time, don't lose the disk!"
|
||||
if(NUKE_RESULT_WRONG_STATION)
|
||||
parts += "<span class='redtext big'>Crew Minor Victory</span>"
|
||||
parts += "<B>[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()].</B> Next time, don't do that!"
|
||||
if(NUKE_RESULT_WRONG_STATION_DEAD)
|
||||
parts += "<span class='redtext big'>[syndicate_name] operatives have earned Darwin Award!</span>"
|
||||
parts += "<B>[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion.</B> Next time, don't do that!"
|
||||
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
|
||||
parts += "<span class='redtext big'>Crew Major Victory!</span>"
|
||||
parts += "<B>The Research Staff has saved the disk and killed the [syndicate_name] Operatives</B>"
|
||||
if(NUKE_RESULT_CREW_WIN)
|
||||
parts += "<span class='redtext big'>Crew Major Victory</span>"
|
||||
parts += "<B>The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!</B>"
|
||||
if(NUKE_RESULT_DISK_LOST)
|
||||
parts += "<span class='neutraltext big'>Neutral Victory!</span>"
|
||||
parts += "<B>The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!</B>"
|
||||
if(NUKE_RESULT_DISK_STOLEN)
|
||||
parts += "<span class='greentext big'>Syndicate Minor Victory!</span>"
|
||||
parts += "<B>[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()].</B> Next time, don't lose the disk!"
|
||||
else
|
||||
parts += "<span class='neutraltext big'>Neutral Victory</span>"
|
||||
parts += "<B>Mission aborted!</B>"
|
||||
|
||||
var/text = "<br><span class='header'>The syndicate operatives were:</span>"
|
||||
var/purchases = ""
|
||||
var/TC_uses = 0
|
||||
for(var/I in members)
|
||||
var/datum/mind/syndicate = I
|
||||
for(var/U in GLOB.uplinks)
|
||||
var/datum/component/uplink/H = U
|
||||
if(H.owner == syndicate.key)
|
||||
TC_uses += H.purchase_log.total_spent
|
||||
if(H.purchase_log)
|
||||
purchases += H.purchase_log.generate_render(show_key = FALSE)
|
||||
else
|
||||
stack_trace("WARNING: Nuke Op uplink with no purchase_log Owner: [H.owner]")
|
||||
text += printplayerlist(members)
|
||||
text += "<br>"
|
||||
text += "(Syndicates used [TC_uses] TC) [purchases]"
|
||||
if(TC_uses == 0 && SSticker.mode.station_was_nuked && !operatives_dead())
|
||||
text += "<BIG>[icon2html('icons/badass.dmi', world, "badass")]</BIG>"
|
||||
|
||||
parts += text
|
||||
|
||||
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
|
||||
@@ -1,7 +1,8 @@
|
||||
/datum/antagonist/pirate
|
||||
name = "Space Pirate"
|
||||
job_rank = ROLE_TRAITOR
|
||||
var/datum/objective_team/pirate/crew
|
||||
roundend_category = "space pirates"
|
||||
var/datum/team/pirate/crew
|
||||
|
||||
/datum/antagonist/pirate/greet()
|
||||
to_chat(owner, "<span class='boldannounce'>You are a Space Pirate!</span>")
|
||||
@@ -11,15 +12,16 @@
|
||||
/datum/antagonist/pirate/get_team()
|
||||
return crew
|
||||
|
||||
/datum/antagonist/pirate/create_team(datum/objective_team/pirate/new_team)
|
||||
/datum/antagonist/pirate/create_team(datum/team/pirate/new_team)
|
||||
if(!new_team)
|
||||
for(var/datum/antagonist/pirate/P in GLOB.antagonists)
|
||||
if(P.crew)
|
||||
new_team = P.crew
|
||||
crew = P.crew
|
||||
return
|
||||
if(!new_team)
|
||||
crew = new /datum/objective_team/pirate
|
||||
crew = new /datum/team/pirate
|
||||
crew.forge_objectives()
|
||||
return
|
||||
return
|
||||
if(!istype(new_team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
crew = new_team
|
||||
@@ -34,11 +36,10 @@
|
||||
owner.objectives -= crew.objectives
|
||||
. = ..()
|
||||
|
||||
/datum/objective_team/pirate
|
||||
/datum/team/pirate
|
||||
name = "Pirate crew"
|
||||
var/list/objectives = list()
|
||||
|
||||
/datum/objective_team/pirate/proc/forge_objectives()
|
||||
/datum/team/pirate/proc/forge_objectives()
|
||||
var/datum/objective/loot/getbooty = new()
|
||||
getbooty.team = src
|
||||
getbooty.storage_area = locate(/area/shuttle/pirate/vault) in GLOB.sortedAreas
|
||||
@@ -84,11 +85,11 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
|
||||
loot_table[lootname] = count
|
||||
else
|
||||
loot_table[lootname] += count
|
||||
var/text = ""
|
||||
var/list/loot_texts = list()
|
||||
for(var/key in loot_table)
|
||||
var/amount = loot_table[key]
|
||||
text += "[amount] [key][amount > 1 ? "s":""], "
|
||||
return text
|
||||
loot_texts += "[amount] [key][amount > 1 ? "s":""]"
|
||||
return loot_texts.Join(", ")
|
||||
|
||||
/datum/objective/loot/proc/get_loot_value()
|
||||
if(!storage_area)
|
||||
@@ -104,32 +105,25 @@ GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
|
||||
/datum/objective/loot/check_completion()
|
||||
return ..() || get_loot_value() >= target_value
|
||||
|
||||
/datum/team/pirate/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
//These need removal ASAP as everything is converted to datum antags.
|
||||
/datum/game_mode/proc/auto_declare_completion_pirates()
|
||||
var/list/datum/mind/pirates = get_antagonists(/datum/antagonist/pirate)
|
||||
var/datum/objective_team/pirate/crew
|
||||
var/text = ""
|
||||
if(pirates.len)
|
||||
text += "<br><b>Space Pirates were:</b>"
|
||||
for(var/datum/mind/M in pirates)
|
||||
text += printplayer(M)
|
||||
if(!crew)
|
||||
var/datum/antagonist/pirate/P = M.has_antag_datum(/datum/antagonist/pirate)
|
||||
crew = P.crew
|
||||
if(crew)
|
||||
text += "<br>Loot stolen: "
|
||||
var/datum/objective/loot/L = locate() in crew.objectives
|
||||
text += L.loot_listing()
|
||||
text += "<br>Total loot value : [L.get_loot_value()]/[L.target_value] credits"
|
||||
parts += "<span class='header'>Space Pirates were:</span>"
|
||||
|
||||
var/all_dead = TRUE
|
||||
for(var/datum/mind/M in crew.members)
|
||||
if(considered_alive(M))
|
||||
all_dead = FALSE
|
||||
break
|
||||
if(L.check_completion() && !all_dead)
|
||||
text += "<br><font color='green'><b>The pirate crew was successful!</b></font>"
|
||||
else
|
||||
text += "<br><span class='boldannounce'>The pirate crew has failed.</span>"
|
||||
to_chat(world, text)
|
||||
var/all_dead = TRUE
|
||||
for(var/datum/mind/M in members)
|
||||
if(considered_alive(M))
|
||||
all_dead = FALSE
|
||||
parts += printplayerlist(members)
|
||||
|
||||
parts += "Loot stolen: "
|
||||
var/datum/objective/loot/L = locate() in objectives
|
||||
parts += L.loot_listing()
|
||||
parts += "Total loot value : [L.get_loot_value()]/[L.target_value] credits"
|
||||
|
||||
if(L.check_completion() && !all_dead)
|
||||
parts += "<span class='greentext big'>The pirate crew was successful!</span>"
|
||||
else
|
||||
parts += "<span class='redtext big'>The pirate crew has failed.</span>"
|
||||
|
||||
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
/datum/antagonist/rev
|
||||
name = "Revolutionary"
|
||||
roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
|
||||
job_rank = ROLE_REV
|
||||
var/hud_type = "rev"
|
||||
var/datum/objective_team/revolution/rev_team
|
||||
var/datum/team/revolution/rev_team
|
||||
|
||||
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
|
||||
. = ..()
|
||||
@@ -39,17 +40,17 @@
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/rev/greet()
|
||||
to_chat(owner, "<span class='danger'><FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</FONT></span>")
|
||||
to_chat(owner, "<span class='userdanger'>You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/rev/create_team(datum/objective_team/revolution/new_team)
|
||||
/datum/antagonist/rev/create_team(datum/team/revolution/new_team)
|
||||
if(!new_team)
|
||||
//For now only one revolution at a time
|
||||
for(var/datum/antagonist/rev/head/H in GLOB.antagonists)
|
||||
if(H.rev_team)
|
||||
rev_team = H.rev_team
|
||||
return
|
||||
rev_team = new /datum/objective_team/revolution
|
||||
rev_team = new /datum/team/revolution
|
||||
rev_team.update_objectives()
|
||||
rev_team.update_heads()
|
||||
return
|
||||
@@ -77,7 +78,7 @@
|
||||
old_owner.add_antag_datum(new_revhead,old_team)
|
||||
new_revhead.silent = FALSE
|
||||
to_chat(old_owner, "<span class='userdanger'>You have proved your devotion to revolution! You are a head revolutionary now!</span>")
|
||||
|
||||
|
||||
|
||||
/datum/antagonist/rev/head
|
||||
name = "Head Revolutionary"
|
||||
@@ -131,14 +132,14 @@
|
||||
old_owner.add_antag_datum(new_rev,old_team)
|
||||
new_rev.silent = FALSE
|
||||
to_chat(old_owner, "<span class='userdanger'>Revolution has been disappointed of your leader traits! You are a regular revolutionary now!</span>")
|
||||
|
||||
|
||||
/datum/antagonist/rev/farewell()
|
||||
if(ishuman(owner.current))
|
||||
owner.current.visible_message("[owner.current] looks like they just remembered their real allegiance!")
|
||||
to_chat(owner, "<span class='userdanger'><FONT size = 3>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</FONT></span>")
|
||||
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like they just remembered their real allegiance!</span>", ignored_mob = owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</span>")
|
||||
else if(issilicon(owner.current))
|
||||
owner.current.visible_message("The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.")
|
||||
to_chat(owner, "<span class='userdanger'><FONT size = 3>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</FONT></span>")
|
||||
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.</span>", ignored_mob = owner.current)
|
||||
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</span>")
|
||||
|
||||
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
|
||||
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
|
||||
@@ -163,7 +164,7 @@
|
||||
if(remove_clumsy && owner.assigned_role == "Clown")
|
||||
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
H.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
|
||||
if(give_flash)
|
||||
var/obj/item/device/assembly/flash/T = new(H)
|
||||
var/list/slots = list (
|
||||
@@ -176,18 +177,17 @@
|
||||
to_chat(H, "The Syndicate were unfortunately unable to get you a flash.")
|
||||
else
|
||||
to_chat(H, "The flash in your [where] will help you to persuade the crew to join your cause.")
|
||||
|
||||
|
||||
if(give_hud)
|
||||
var/obj/item/organ/cyberimp/eyes/hud/security/syndicate/S = new(H)
|
||||
S.Insert(H, special = FALSE, drop_if_replaced = FALSE)
|
||||
to_chat(H, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
|
||||
|
||||
/datum/objective_team/revolution
|
||||
/datum/team/revolution
|
||||
name = "Revolution"
|
||||
var/list/objectives = list()
|
||||
var/max_headrevs = 3
|
||||
|
||||
/datum/objective_team/revolution/proc/update_objectives(initial = FALSE)
|
||||
/datum/team/revolution/proc/update_objectives(initial = FALSE)
|
||||
var/untracked_heads = SSjob.get_all_heads()
|
||||
for(var/datum/objective/mutiny/O in objectives)
|
||||
untracked_heads -= O.target
|
||||
@@ -199,16 +199,16 @@
|
||||
objectives += new_target
|
||||
for(var/datum/mind/M in members)
|
||||
M.objectives |= objectives
|
||||
|
||||
|
||||
addtimer(CALLBACK(src,.proc/update_objectives),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
|
||||
|
||||
/datum/objective_team/revolution/proc/head_revolutionaries()
|
||||
/datum/team/revolution/proc/head_revolutionaries()
|
||||
. = list()
|
||||
for(var/datum/mind/M in members)
|
||||
if(M.has_antag_datum(/datum/antagonist/rev/head))
|
||||
. += M
|
||||
|
||||
/datum/objective_team/revolution/proc/update_heads()
|
||||
/datum/team/revolution/proc/update_heads()
|
||||
if(SSticker.HasRoundStarted())
|
||||
var/list/datum/mind/head_revolutionaries = head_revolutionaries()
|
||||
var/list/datum/mind/heads = SSjob.get_all_heads()
|
||||
@@ -227,3 +227,56 @@
|
||||
rev.promote()
|
||||
|
||||
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
|
||||
|
||||
|
||||
/datum/team/revolution/roundend_report()
|
||||
if(!members.len)
|
||||
return
|
||||
|
||||
var/list/result = list()
|
||||
|
||||
result += "<div class='panel redborder'>"
|
||||
|
||||
var/num_revs = 0
|
||||
var/num_survivors = 0
|
||||
for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
|
||||
if(survivor.ckey)
|
||||
num_survivors++
|
||||
if(survivor.mind)
|
||||
if(is_revolutionary(survivor))
|
||||
num_revs++
|
||||
if(num_survivors)
|
||||
result += "Command's Approval Rating: <B>[100 - round((num_revs/num_survivors)*100, 0.1)]%</B><br>"
|
||||
|
||||
|
||||
var/list/targets = list()
|
||||
var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
|
||||
var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
|
||||
if(headrevs.len)
|
||||
var/list/headrev_part = list()
|
||||
headrev_part += "<span class='header'>The head revolutionaries were:</span>"
|
||||
headrev_part += printplayerlist(headrevs,TRUE)
|
||||
result += headrev_part.Join("<br>")
|
||||
|
||||
if(revs.len)
|
||||
var/list/rev_part = list()
|
||||
rev_part += "<span class='header'>The revolutionaries were:</span>"
|
||||
rev_part += printplayerlist(revs,TRUE)
|
||||
result += rev_part.Join("<br>")
|
||||
|
||||
var/list/heads = SSjob.get_all_heads()
|
||||
if(heads.len)
|
||||
var/head_text = "<span class='header'>The heads of staff were:</span>"
|
||||
head_text += "<ul class='playerlist'>"
|
||||
for(var/datum/mind/head in heads)
|
||||
var/target = (head in targets)
|
||||
head_text += "<li>"
|
||||
if(target)
|
||||
head_text += "<span class='redtext'>Target</span>"
|
||||
head_text += "[printplayer(head, 1)]</li>"
|
||||
head_text += "</ul><br>"
|
||||
result += head_text
|
||||
|
||||
result += "</div>"
|
||||
|
||||
return result.Join()
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
/datum/antagonist/wizard
|
||||
name = "Space Wizard"
|
||||
roundend_category = "wizards/witches"
|
||||
job_rank = ROLE_WIZARD
|
||||
var/give_objectives = TRUE
|
||||
var/strip = TRUE //strip before equipping
|
||||
var/allow_rename = TRUE
|
||||
var/hud_version = "wizard"
|
||||
var/datum/objective_team/wizard/wiz_team //Only created if wizard summons apprentices
|
||||
var/list/objectives = list() //this should be base datum antag proc and list, todo make lazy
|
||||
var/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
|
||||
var/move_to_lair = TRUE
|
||||
var/outfit_type = /datum/outfit/wizard
|
||||
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
|
||||
@@ -33,7 +33,7 @@
|
||||
/datum/antagonist/wizard/proc/unregister()
|
||||
SSticker.mode.wizards -= src
|
||||
|
||||
/datum/antagonist/wizard/create_team(datum/objective_team/wizard/new_team)
|
||||
/datum/antagonist/wizard/create_team(datum/team/wizard/new_team)
|
||||
if(!new_team)
|
||||
return
|
||||
if(!istype(new_team))
|
||||
@@ -43,12 +43,14 @@
|
||||
/datum/antagonist/wizard/get_team()
|
||||
return wiz_team
|
||||
|
||||
/datum/objective_team/wizard
|
||||
/datum/team/wizard
|
||||
name = "wizard team"
|
||||
var/datum/antagonist/wizard/master_wizard
|
||||
|
||||
/datum/antagonist/wizard/proc/create_wiz_team()
|
||||
wiz_team = new(owner)
|
||||
wiz_team.name = "[owner.current.real_name] team"
|
||||
wiz_team.master_wizard = src
|
||||
update_wiz_icons_added(owner.current)
|
||||
|
||||
/datum/antagonist/wizard/proc/send_to_lair()
|
||||
@@ -283,4 +285,46 @@
|
||||
var/datum/objective/new_objective = new("Protect Wizard Academy from the intruders")
|
||||
new_objective.owner = owner
|
||||
owner.objectives += new_objective
|
||||
objectives += new_objective
|
||||
objectives += new_objective
|
||||
|
||||
//Solo wizard report
|
||||
/datum/antagonist/wizard/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
parts += printplayer(owner)
|
||||
|
||||
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>"
|
||||
else
|
||||
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
|
||||
wizardwin = 0
|
||||
count++
|
||||
|
||||
if(wizardwin)
|
||||
parts += "<span class='greentext'>The wizard was successful!</span>"
|
||||
else
|
||||
parts += "<span class='redtext'>The wizard has failed!</span>"
|
||||
|
||||
if(owner.spell_list.len>0)
|
||||
parts += "<B>[owner.name] used the following spells: </B>"
|
||||
var/list/spell_names = list()
|
||||
for(var/obj/effect/proc_holder/spell/S in owner.spell_list)
|
||||
spell_names += S.name
|
||||
parts += spell_names.Join(", ")
|
||||
|
||||
return parts.Join("<br>")
|
||||
|
||||
//Wizard with apprentices report
|
||||
/datum/team/wizard/roundend_report()
|
||||
var/list/parts = list()
|
||||
|
||||
parts += "<span class='header'>Wizards/witches of [master_wizard.owner.name] team were:</span>"
|
||||
parts += master_wizard.roundend_report()
|
||||
parts += " "
|
||||
parts += "<span class='header'>[master_wizard.owner.name] apprentices were:</span>"
|
||||
parts += printplayerlist(members - master_wizard.owner)
|
||||
|
||||
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
|
||||
+2
-2
@@ -128,11 +128,11 @@
|
||||
//Position the effect so the beam is one continous line
|
||||
var/a
|
||||
if(abs(Pixel_x)>32)
|
||||
a = Pixel_x > 0 ? round(Pixel_x/32) : Ceiling(Pixel_x/32)
|
||||
a = Pixel_x > 0 ? round(Pixel_x/32) : CEILING(Pixel_x/32, 1)
|
||||
X.x += a
|
||||
Pixel_x %= 32
|
||||
if(abs(Pixel_y)>32)
|
||||
a = Pixel_y > 0 ? round(Pixel_y/32) : Ceiling(Pixel_y/32)
|
||||
a = Pixel_y > 0 ? round(Pixel_y/32) : CEILING(Pixel_y/32, 1)
|
||||
X.y += a
|
||||
Pixel_y %= 32
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/datum/brain_trauma/special/imaginary_friend
|
||||
name = "Imaginary Friend"
|
||||
desc = "Patient can see and hear an imaginary person."
|
||||
scan_desc = "partial schizophrenia"
|
||||
gain_text = "<span class='notice'>You feel in good company, for some reason.</span>"
|
||||
lose_text = "<span class='warning'>You feel lonely again.</span>"
|
||||
var/mob/camera/imaginary_friend/friend
|
||||
var/friend_initialized = FALSE
|
||||
|
||||
/datum/brain_trauma/special/imaginary_friend/on_gain()
|
||||
..()
|
||||
make_friend()
|
||||
get_ghost()
|
||||
|
||||
/datum/brain_trauma/special/imaginary_friend/on_life()
|
||||
if(get_dist(owner, friend) > 9)
|
||||
friend.yank()
|
||||
if(!friend)
|
||||
qdel(src)
|
||||
return
|
||||
if(!friend.client && friend_initialized)
|
||||
addtimer(CALLBACK(src, .proc/reroll_friend), 600)
|
||||
|
||||
/datum/brain_trauma/special/imaginary_friend/on_lose()
|
||||
..()
|
||||
QDEL_NULL(friend)
|
||||
|
||||
//If the friend goes afk, make a brand new friend. Plenty of fish in the sea of imagination.
|
||||
/datum/brain_trauma/special/imaginary_friend/proc/reroll_friend()
|
||||
if(friend.client) //reconnected
|
||||
return
|
||||
friend_initialized = FALSE
|
||||
QDEL_NULL(friend)
|
||||
make_friend()
|
||||
get_ghost()
|
||||
|
||||
/datum/brain_trauma/special/imaginary_friend/proc/make_friend()
|
||||
friend = new(get_turf(src), src)
|
||||
|
||||
/datum/brain_trauma/special/imaginary_friend/proc/get_ghost()
|
||||
set waitfor = FALSE
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend)
|
||||
if(LAZYLEN(candidates))
|
||||
var/client/C = pick(candidates)
|
||||
friend.key = C.key
|
||||
friend_initialized = TRUE
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/mob/camera/imaginary_friend
|
||||
name = "imaginary friend"
|
||||
real_name = "imaginary friend"
|
||||
move_on_shuttle = TRUE
|
||||
desc = "A wonderful yet fake friend."
|
||||
see_in_dark = 0
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
|
||||
sight = NONE
|
||||
see_invisible = SEE_INVISIBLE_LIVING
|
||||
var/icon/human_image
|
||||
var/image/current_image
|
||||
var/mob/living/carbon/owner
|
||||
var/datum/brain_trauma/special/imaginary_friend/trauma
|
||||
|
||||
/mob/camera/imaginary_friend/Login()
|
||||
..()
|
||||
to_chat(src, "<span class='notice'><b>You are the imaginary friend of [owner]!</b></span>")
|
||||
to_chat(src, "<span class='notice'>You are absolutely loyal to your friend, no matter what.</span>")
|
||||
to_chat(src, "<span class='notice'>You cannot directly influence the world around you, but you can see what [owner] cannot.</span>")
|
||||
|
||||
/mob/camera/imaginary_friend/Initialize(mapload, _trauma)
|
||||
. = ..()
|
||||
var/gender = pick(MALE, FEMALE)
|
||||
real_name = random_unique_name(gender)
|
||||
name = real_name
|
||||
trauma = _trauma
|
||||
owner = trauma.owner
|
||||
human_image = get_flat_human_icon(null, pick(SSjob.occupations))
|
||||
Show()
|
||||
|
||||
/mob/camera/imaginary_friend/proc/Show()
|
||||
if(!client) //nobody home
|
||||
return
|
||||
|
||||
//Remove old image from owner and friend
|
||||
if(owner.client)
|
||||
owner.client.images.Remove(current_image)
|
||||
|
||||
client.images.Remove(current_image)
|
||||
|
||||
//Generate image from the static icon and the current dir
|
||||
current_image = image(human_image, src, , MOB_LAYER, dir=src.dir)
|
||||
current_image.override = TRUE
|
||||
current_image.name = name
|
||||
|
||||
//Add new image to owner and friend
|
||||
if(owner.client)
|
||||
owner.client.images |= current_image
|
||||
|
||||
client.images |= current_image
|
||||
|
||||
/mob/camera/imaginary_friend/Destroy()
|
||||
if(owner.client)
|
||||
owner.client.images.Remove(human_image)
|
||||
if(client)
|
||||
client.images.Remove(human_image)
|
||||
return ..()
|
||||
|
||||
/mob/camera/imaginary_friend/proc/yank()
|
||||
if(!client) //don't bother if the friend is braindead
|
||||
return
|
||||
forceMove(get_turf(owner))
|
||||
Show()
|
||||
|
||||
/mob/camera/imaginary_friend/say(message)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
if (src.client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "You cannot send IC messages (muted).")
|
||||
return
|
||||
if (src.client.handle_spam_prevention(message,MUTE_IC))
|
||||
return
|
||||
|
||||
friend_talk(message)
|
||||
|
||||
/mob/camera/imaginary_friend/proc/friend_talk(message)
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if(!message)
|
||||
return
|
||||
|
||||
log_talk(src,"[key_name(src)] : [message]",LOGSAY)
|
||||
|
||||
var/rendered = "<span class='game say'><span class='name'>[name]</span> <span class='message'>[say_quote(message)]</span></span>"
|
||||
var/dead_rendered = "<span class='game say'><span class='name'>[name] (Imaginary friend of [owner])</span> <span class='message'>[say_quote(message)]</span></span>"
|
||||
|
||||
to_chat(owner, "[rendered]")
|
||||
to_chat(src, "[rendered]")
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
var/link = FOLLOW_LINK(M, owner)
|
||||
to_chat(M, "[link] [dead_rendered]")
|
||||
|
||||
/mob/camera/imaginary_friend/emote(act,m_type=1,message = null)
|
||||
return
|
||||
|
||||
/mob/camera/imaginary_friend/forceMove(atom/destination)
|
||||
dir = get_dir(get_turf(src), destination)
|
||||
loc = destination
|
||||
if(get_dist(src, owner) > 9)
|
||||
yank()
|
||||
return
|
||||
Show()
|
||||
|
||||
/mob/camera/imaginary_friend/movement_delay()
|
||||
return 2
|
||||
@@ -107,6 +107,26 @@
|
||||
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/healthy
|
||||
name = "Anosognosia"
|
||||
desc = "Patient always feels healthy, regardless of their condition."
|
||||
scan_desc = "self-awareness deficit"
|
||||
gain_text = "<span class='notice'>You feel great!</span>"
|
||||
lose_text = "<span class='warning'>You no longer feel perfectly healthy.</span>"
|
||||
|
||||
/datum/brain_trauma/mild/healthy/on_gain()
|
||||
owner.set_screwyhud(SCREWYHUD_HEALTHY)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/healthy/on_life()
|
||||
owner.set_screwyhud(SCREWYHUD_HEALTHY) //just in case of hallucinations
|
||||
owner.adjustStaminaLoss(-5) //no pain, no fatigue
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/healthy/on_lose()
|
||||
owner.set_screwyhud(SCREWYHUD_NONE)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/muscle_weakness
|
||||
name = "Muscle Weakness"
|
||||
desc = "Patient experiences occasional bouts of muscle weakness."
|
||||
@@ -133,3 +153,62 @@
|
||||
to_chat(owner, "<span class='warning'>You feel a sudden weakness in your muscles!</span>")
|
||||
owner.adjustStaminaLoss(50)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/muscle_spasms
|
||||
name = "Muscle Spasms"
|
||||
desc = "Patient has occasional muscle spasms, causing them to move unintentionally."
|
||||
scan_desc = "nervous fits"
|
||||
gain_text = "<span class='warning'>Your muscles feel oddly faint.</span>"
|
||||
lose_text = "<span class='notice'>You feel in control of your muscles again.</span>"
|
||||
|
||||
/datum/brain_trauma/mild/muscle_spasms/on_life()
|
||||
if(prob(7))
|
||||
switch(rand(1,5))
|
||||
if(1)
|
||||
if(owner.canmove && !isspaceturf(owner.loc))
|
||||
to_chat(owner, "<span class='warning'>Your leg spasms!</span>")
|
||||
step(owner, pick(GLOB.cardinals))
|
||||
if(2)
|
||||
if(owner.incapacitated())
|
||||
return
|
||||
var/obj/item/I = owner.get_active_held_item()
|
||||
if(I)
|
||||
to_chat(owner, "<span class='warning'>Your fingers spasm!</span>")
|
||||
log_attack("[key_name(owner)] used [I] due to a Muscle Spasm.")
|
||||
I.attack_self(owner)
|
||||
if(3)
|
||||
var/prev_intent = owner.a_intent
|
||||
owner.a_intent = INTENT_HARM
|
||||
|
||||
var/range = 1
|
||||
if(istype(owner.get_active_held_item(), /obj/item/gun)) //get targets to shoot at
|
||||
range = 7
|
||||
|
||||
var/list/mob/living/targets = list()
|
||||
for(var/mob/M in oview(owner, range))
|
||||
if(isliving(M))
|
||||
targets += M
|
||||
if(LAZYLEN(targets))
|
||||
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
|
||||
log_attack("[key_name(owner)] attacked someone due to a Muscle Spasm.") //the following attack will log itself
|
||||
owner.ClickOn(pick(targets))
|
||||
owner.a_intent = prev_intent
|
||||
if(4)
|
||||
var/prev_intent = owner.a_intent
|
||||
owner.a_intent = INTENT_HARM
|
||||
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
|
||||
log_attack("[key_name(owner)] attacked himself to a Muscle Spasm.")
|
||||
owner.ClickOn(owner)
|
||||
owner.a_intent = prev_intent
|
||||
if(5)
|
||||
if(owner.incapacitated())
|
||||
return
|
||||
var/obj/item/I = owner.get_active_held_item()
|
||||
var/list/turf/targets = list()
|
||||
for(var/turf/T in oview(owner, 3))
|
||||
targets += T
|
||||
if(LAZYLEN(targets) && I)
|
||||
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
|
||||
log_attack("[key_name(owner)] threw [I] due to a Muscle Spasm.")
|
||||
owner.throw_item(pick(targets))
|
||||
..()
|
||||
@@ -7,7 +7,7 @@
|
||||
/datum/brain_trauma/severe/mute
|
||||
name = "Mutism"
|
||||
desc = "Patient is completely unable to speak."
|
||||
scan_desc = "extensive damage to the brain's language center"
|
||||
scan_desc = "extensive damage to the brain's speech center"
|
||||
gain_text = "<span class='warning'>You forget how to speak!</span>"
|
||||
lose_text = "<span class='notice'>You suddenly remember how to speak.</span>"
|
||||
|
||||
@@ -19,6 +19,29 @@
|
||||
owner.remove_disability(MUTE, TRAUMA_DISABILITY)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/aphasia
|
||||
name = "Aphasia"
|
||||
desc = "Patient is unable to speak or understand any language."
|
||||
scan_desc = "extensive damage to the brain's language center"
|
||||
gain_text = "<span class='warning'>You have trouble forming words in your head...</span>"
|
||||
lose_text = "<span class='notice'>You suddenly remember how languages work.</span>"
|
||||
var/datum/language_holder/prev_language
|
||||
var/datum/language_holder/mob_language
|
||||
|
||||
/datum/brain_trauma/severe/aphasia/on_gain()
|
||||
mob_language = owner.get_language_holder()
|
||||
prev_language = mob_language.copy()
|
||||
mob_language.remove_all_languages()
|
||||
mob_language.grant_language(/datum/language/aphasia)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/aphasia/on_lose()
|
||||
mob_language.remove_language(/datum/language/aphasia)
|
||||
mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma
|
||||
QDEL_NULL(prev_language)
|
||||
mob_language = null
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/blindness
|
||||
name = "Cerebral Blindness"
|
||||
desc = "Patient's brain is no longer connected to its eyes."
|
||||
@@ -180,3 +203,18 @@
|
||||
/datum/brain_trauma/severe/pacifism/on_lose()
|
||||
owner.remove_disability(PACIFISM, TRAUMA_DISABILITY)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/pacifism
|
||||
name = "Traumatic Non-Violence"
|
||||
desc = "Patient is extremely unwilling to harm others in violent ways."
|
||||
scan_desc = "pacific syndrome"
|
||||
gain_text = "<span class='notice'>You feel oddly peaceful.</span>"
|
||||
lose_text = "<span class='notice'>You no longer feel compelled to not harm.</span>"
|
||||
|
||||
/datum/brain_trauma/severe/pacifism/on_gain()
|
||||
owner.disabilities |= PACIFISM
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/pacifism/on_lose()
|
||||
owner.disabilities &= ~PACIFISM
|
||||
..()
|
||||
@@ -9,25 +9,35 @@
|
||||
scan_desc = "god delusion"
|
||||
gain_text = "<span class='notice'>You feel a higher power inside your mind...</span>"
|
||||
lose_text = "<span class='warning'>The divine presence leaves your head, no longer interested.</span>"
|
||||
var/next_speech = 0
|
||||
var/inspiration = FALSE
|
||||
|
||||
/datum/brain_trauma/special/godwoken/on_life()
|
||||
..()
|
||||
if(!inspiration && world.time > next_speech && prob(4))
|
||||
to_chat(owner, "<span class='notice'>[pick("You feel inspired!","You feel power course through you...","You feel something within you itching to speak...")]</span>")
|
||||
inspiration = TRUE
|
||||
if(prob(4))
|
||||
if(prob(33) && (owner.IsStun() || owner.IsKnockdown() || owner.IsUnconscious()))
|
||||
speak("unstun", TRUE)
|
||||
else if(prob(60) && owner.health <= HEALTH_THRESHOLD_CRIT)
|
||||
speak("heal", TRUE)
|
||||
else if(prob(30) && owner.a_intent == INTENT_HARM)
|
||||
speak("aggressive")
|
||||
else
|
||||
speak("neutral", prob(25))
|
||||
|
||||
/datum/brain_trauma/special/godwoken/on_say(message)
|
||||
if(world.time > next_speech && inspiration)
|
||||
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 300, 1, 5)
|
||||
var/cooldown = voice_of_god(message, owner, list("colossus","yell"), 2)
|
||||
cooldown *= 0.33
|
||||
next_speech = world.time + cooldown
|
||||
inspiration = FALSE
|
||||
return ""
|
||||
else
|
||||
return message
|
||||
/datum/brain_trauma/special/godwoken/proc/speak(type, include_owner = FALSE)
|
||||
var/message
|
||||
switch(type)
|
||||
if("unstun")
|
||||
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_unstun")
|
||||
if("heal")
|
||||
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_heal")
|
||||
if("neutral")
|
||||
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
|
||||
if("aggressive")
|
||||
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_aggressive")
|
||||
else
|
||||
message = pick_list_replacements(BRAIN_DAMAGE_FILE, "god_neutral")
|
||||
|
||||
playsound(get_turf(owner), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 5)
|
||||
voice_of_god(message, owner, list("colossus","yell"), 2.5, include_owner, FALSE)
|
||||
|
||||
/datum/brain_trauma/special/bluespace_prophet
|
||||
name = "Bluespace Prophecy"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
|
||||
set waitfor = FALSE
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", null, null, null, 75, stranger_backseat)
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat)
|
||||
if(LAZYLEN(candidates))
|
||||
var/client/C = pick(candidates)
|
||||
stranger_backseat.key = C.key
|
||||
@@ -136,6 +136,7 @@
|
||||
/mob/living/split_personality/Login()
|
||||
..()
|
||||
to_chat(src, "<span class='notice'>As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality.</span>")
|
||||
to_chat(src, "<span class='warning'><b>Do not commit suicide or put the body in a deadly position. Behave like you care about it as much as the owner.</b></span>")
|
||||
|
||||
/mob/living/split_personality/say(message)
|
||||
to_chat(src, "<span class='warning'>You cannot speak, your other self is controlling your body!</span>")
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
var/datum/object = GLOBAL_PROC
|
||||
var/delegate
|
||||
var/list/arguments
|
||||
var/datum/weakref/user
|
||||
|
||||
/datum/callback/New(thingtocall, proctocall, ...)
|
||||
if (thingtocall)
|
||||
@@ -55,6 +56,8 @@
|
||||
delegate = proctocall
|
||||
if (length(args) > 2)
|
||||
arguments = args.Copy(3)
|
||||
if(usr)
|
||||
user = WEAKREF(usr)
|
||||
|
||||
/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
|
||||
set waitfor = FALSE
|
||||
@@ -70,8 +73,16 @@
|
||||
call(thingtocall, proctocall)(arglist(calling_arguments))
|
||||
|
||||
/datum/callback/proc/Invoke(...)
|
||||
if(!usr)
|
||||
var/datum/weakref/W = user
|
||||
if(W)
|
||||
var/mob/M = W.resolve()
|
||||
if(M)
|
||||
return world.PushUsr(M, src)
|
||||
|
||||
if (!object)
|
||||
return
|
||||
|
||||
var/list/calling_arguments = arguments
|
||||
if (length(args))
|
||||
if (length(arguments))
|
||||
@@ -87,8 +98,17 @@
|
||||
//copy and pasted because fuck proc overhead
|
||||
/datum/callback/proc/InvokeAsync(...)
|
||||
set waitfor = FALSE
|
||||
|
||||
if(!usr)
|
||||
var/datum/weakref/W = user
|
||||
if(W)
|
||||
var/mob/M = W.resolve()
|
||||
if(M)
|
||||
return world.PushUsr(M, src)
|
||||
|
||||
if (!object)
|
||||
return
|
||||
|
||||
var/list/calling_arguments = arguments
|
||||
if (length(args))
|
||||
if (length(arguments))
|
||||
|
||||
@@ -40,6 +40,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* `COMPONENT_DUPE_HIGHLANDER` (default): Old component will be deleted, new component will first have `/datum/component/proc/InheritComponent(datum/component/old, FALSE)` on it
|
||||
* `COMPONENT_DUPE_ALLOWED`: The components will be treated as separate, `GetComponent()` will return the first added
|
||||
* `COMPONENT_DUPE_UNIQUE`: New component will be deleted, old component will first have `/datum/component/proc/InheritComponent(datum/component/new, TRUE)` on it
|
||||
* `COMPONENT_DUPE_UNIQUE_PASSARGS`: New component will never exist and instead its initialization arguments will be passed on to the old component.
|
||||
1. `/datum/component/var/dupe_type` (protected, type)
|
||||
* Definition of a duplicate component type
|
||||
* `null` means exact match on `type` (default)
|
||||
@@ -66,6 +67,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* All components a datum owns are deleted with the datum
|
||||
* Returns the component that was created. Or the old component in a dupe situation where `COMPONENT_DUPE_UNIQUE` was set
|
||||
* If this tries to add an component to an incompatible type, the component will be deleted and the result will be `null`. This is very unperformant, try not to do it
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
|
||||
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
|
||||
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
|
||||
@@ -104,9 +106,8 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
* Allows the component to react to ownership transfers
|
||||
1. `/datum/component/proc/_RemoveFromParent()` (private, final)
|
||||
* Clears `parent` and removes the component from it's component list
|
||||
1. `/datum/component/proc/_CheckDupesAndJoinParent` (private, final)
|
||||
1. `/datum/component/proc/_JoinParent` (private, final)
|
||||
* Tries to add the component to it's `parent`s `datum_components` list
|
||||
* Properly handles duplicate situations based on the `dupe_mode` var
|
||||
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
|
||||
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
|
||||
* Makes a component listen for the specified `signal` on it's `parent` datum.
|
||||
|
||||
@@ -6,54 +6,16 @@
|
||||
var/datum/parent
|
||||
|
||||
/datum/component/New(datum/P, ...)
|
||||
if(type == /datum/component)
|
||||
qdel(src)
|
||||
CRASH("[type] instantiated!")
|
||||
|
||||
//check for common mishaps
|
||||
if(!isnum(dupe_mode))
|
||||
qdel(src)
|
||||
CRASH("[type]: Invalid dupe_mode!")
|
||||
var/dt = dupe_type
|
||||
if(dt && !ispath(dt))
|
||||
qdel(src)
|
||||
CRASH("[type]: Invalid dupe_type!")
|
||||
|
||||
parent = P
|
||||
var/list/arguments = args.Copy(2)
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
qdel(src, TRUE, TRUE)
|
||||
return
|
||||
|
||||
_CheckDupesAndJoinParent(P)
|
||||
_JoinParent(P)
|
||||
|
||||
/datum/component/proc/_CheckDupesAndJoinParent()
|
||||
/datum/component/proc/_JoinParent()
|
||||
var/datum/P = parent
|
||||
var/dm = dupe_mode
|
||||
|
||||
var/datum/component/old
|
||||
if(dm != COMPONENT_DUPE_ALLOWED)
|
||||
var/dt = dupe_type
|
||||
if(!dt)
|
||||
old = P.GetExactComponent(type)
|
||||
else
|
||||
old = P.GetComponent(dt)
|
||||
if(old)
|
||||
//One or the other has to die
|
||||
switch(dm)
|
||||
if(COMPONENT_DUPE_UNIQUE)
|
||||
old.InheritComponent(src, TRUE)
|
||||
qdel(src, TRUE, TRUE)
|
||||
return
|
||||
if(COMPONENT_DUPE_HIGHLANDER)
|
||||
InheritComponent(old, FALSE)
|
||||
qdel(old, FALSE, TRUE)
|
||||
|
||||
//provided we didn't eat someone
|
||||
if(!old)
|
||||
//let the others know
|
||||
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
|
||||
|
||||
//lazy init the parent's dc list
|
||||
var/list/dc = P.datum_components
|
||||
if(!dc)
|
||||
@@ -212,10 +174,59 @@
|
||||
return list(.)
|
||||
|
||||
/datum/proc/AddComponent(new_type, ...)
|
||||
var/nt = new_type
|
||||
var/datum/component/nt = new_type
|
||||
var/dm = initial(nt.dupe_mode)
|
||||
var/dt = initial(nt.dupe_type)
|
||||
|
||||
var/datum/component/old_comp
|
||||
var/datum/component/new_comp
|
||||
|
||||
if(ispath(nt))
|
||||
if(nt == /datum/component)
|
||||
CRASH("[nt] attempted instantiation!")
|
||||
if(!isnum(dm))
|
||||
CRASH("[nt]: Invalid dupe_mode ([dm])!")
|
||||
if(dt && !ispath(dt))
|
||||
CRASH("[nt]: Invalid dupe_type ([dt])!")
|
||||
else
|
||||
new_comp = nt
|
||||
|
||||
args[1] = src
|
||||
var/datum/component/C = new nt(arglist(args))
|
||||
return QDELING(C) ? GetExactComponent(new_type) : C
|
||||
|
||||
if(dm != COMPONENT_DUPE_ALLOWED)
|
||||
if(!dt)
|
||||
old_comp = GetExactComponent(nt)
|
||||
else
|
||||
old_comp = GetComponent(dt)
|
||||
if(old_comp)
|
||||
switch(dm)
|
||||
if(COMPONENT_DUPE_UNIQUE)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(arglist(args))
|
||||
if(!QDELETED(new_comp))
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
qdel(new_comp)
|
||||
if(COMPONENT_DUPE_HIGHLANDER)
|
||||
if(!new_comp)
|
||||
new_comp = new nt(arglist(args))
|
||||
if(!QDELETED(new_comp))
|
||||
new_comp.InheritComponent(old_comp, FALSE)
|
||||
qdel(old_comp)
|
||||
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
|
||||
if(!new_comp)
|
||||
var/list/arguments = args.Copy(2)
|
||||
old_comp.InheritComponent(null, TRUE, arguments)
|
||||
else
|
||||
old_comp.InheritComponent(new_comp, TRUE)
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
|
||||
else if(!new_comp)
|
||||
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
|
||||
|
||||
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
|
||||
SendSignal(COMSIG_COMPONENT_ADDED, new_comp)
|
||||
return new_comp
|
||||
return old_comp
|
||||
|
||||
/datum/proc/LoadComponent(component_type, ...)
|
||||
. = GetComponent(component_type)
|
||||
@@ -235,7 +246,8 @@
|
||||
C._RemoveFromParent()
|
||||
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
|
||||
C.parent = src
|
||||
C._CheckDupesAndJoinParent()
|
||||
if(C == AddComponent(C))
|
||||
C._JoinParent()
|
||||
|
||||
/datum/proc/TransferComponents(datum/target)
|
||||
var/list/dc = datum_components
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
var/datum/callback/callback
|
||||
|
||||
/datum/component/archaeology/Initialize(_prob2drop, list/_archdrops = list(), datum/callback/_callback)
|
||||
prob2drop = Clamp(_prob2drop, 0, 100)
|
||||
prob2drop = CLAMP(_prob2drop, 0, 100)
|
||||
archdrops = _archdrops
|
||||
callback = _callback
|
||||
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/Dig)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/datum/component/cleaning
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
|
||||
/datum/component/cleaning/Initialize()
|
||||
if(!ismovableatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("[type] added to a [parent.type]")
|
||||
RegisterSignal(list(COMSIG_MOVABLE_MOVED), .proc/Clean)
|
||||
|
||||
/datum/component/cleaning/proc/Clean()
|
||||
var/atom/movable/AM = parent
|
||||
var/turf/tile = AM.loc
|
||||
if(!isturf(tile))
|
||||
return
|
||||
|
||||
tile.clean_blood()
|
||||
for(var/A in tile)
|
||||
if(is_cleanable(A))
|
||||
qdel(A)
|
||||
else if(istype(A, /obj/item))
|
||||
var/obj/item/cleaned_item = A
|
||||
cleaned_item.clean_blood()
|
||||
else if(ishuman(A))
|
||||
var/mob/living/carbon/human/cleaned_human = A
|
||||
if(cleaned_human.lying)
|
||||
if(cleaned_human.head)
|
||||
cleaned_human.head.clean_blood()
|
||||
cleaned_human.update_inv_head()
|
||||
if(cleaned_human.wear_suit)
|
||||
cleaned_human.wear_suit.clean_blood()
|
||||
cleaned_human.update_inv_wear_suit()
|
||||
else if(cleaned_human.w_uniform)
|
||||
cleaned_human.w_uniform.clean_blood()
|
||||
cleaned_human.update_inv_w_uniform()
|
||||
if(cleaned_human.shoes)
|
||||
cleaned_human.shoes.clean_blood()
|
||||
cleaned_human.update_inv_shoes()
|
||||
cleaned_human.clean_blood()
|
||||
cleaned_human.wash_cream()
|
||||
to_chat(cleaned_human, "<span class='danger'>[AM] cleans your face!</span>")
|
||||
@@ -48,8 +48,7 @@
|
||||
if(old_dir == new_dir)
|
||||
return
|
||||
remove()
|
||||
var/rotation = SimplifyDegrees(dir2angle(new_dir)-dir2angle(old_dir))
|
||||
pic.dir = turn(pic.dir, rotation)
|
||||
pic.dir = turn(pic.dir, dir2angle(old_dir) - dir2angle(new_dir))
|
||||
apply()
|
||||
|
||||
/datum/component/decal/proc/clean_react(strength)
|
||||
@@ -57,4 +56,4 @@
|
||||
qdel(src)
|
||||
|
||||
/datum/component/decal/proc/examine(mob/user)
|
||||
to_chat(user, description)
|
||||
to_chat(user, description)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/datum/component/jousting
|
||||
var/current_direction = NONE
|
||||
var/max_tile_charge = 5
|
||||
var/min_tile_charge = 2 //tiles before this code gets into effect.
|
||||
var/current_tile_charge = 0
|
||||
var/movement_reset_tolerance = 2 //deciseconds
|
||||
var/unmounted_damage_boost_per_tile = 0
|
||||
var/unmounted_knockdown_chance_per_tile = 0
|
||||
var/unmounted_knockdown_time = 0
|
||||
var/mounted_damage_boost_per_tile = 2
|
||||
var/mounted_knockdown_chance_per_tile = 20
|
||||
var/mounted_knockdown_time = 20
|
||||
var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
|
||||
var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
|
||||
var/mob/current_holder
|
||||
var/datum/component/redirect/listener
|
||||
var/current_timerid
|
||||
|
||||
/datum/component/jousting/Initialize()
|
||||
if(!isitem(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
stack_trace("Warning: Jousting component incorrectly applied to invalid parent type [parent.type]")
|
||||
RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/on_attack)
|
||||
|
||||
/datum/component/jousting/Destroy()
|
||||
QDEL_NULL(listener)
|
||||
return ..()
|
||||
|
||||
/datum/component/jousting/proc/on_equip(mob/user, slot)
|
||||
QDEL_NULL(listener)
|
||||
current_holder = user
|
||||
listener = new(user, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/mob_move))
|
||||
|
||||
/datum/component/jousting/proc/on_drop(mob/user)
|
||||
QDEL_NULL(listener)
|
||||
current_holder = null
|
||||
current_direction = NONE
|
||||
current_tile_charge = 0
|
||||
|
||||
/datum/component/jousting/proc/on_attack(mob/living/target, mob/user)
|
||||
if(user != current_holder)
|
||||
return
|
||||
var/current = current_tile_charge
|
||||
var/obj/item/I = parent
|
||||
var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
|
||||
if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
|
||||
return
|
||||
var/turf/target_turf = get_step(user, current_direction)
|
||||
if(target in range(1, target_turf))
|
||||
var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
|
||||
var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
|
||||
var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
|
||||
var/sharp = I.is_sharp()
|
||||
var/msg
|
||||
if(damage)
|
||||
msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
|
||||
target.apply_damage(damage, BRUTE, user.zone_selected, 0)
|
||||
if(prob(knockdown_chance))
|
||||
msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
|
||||
if(target_buckled)
|
||||
target.buckled.unbuckle_mob(target)
|
||||
target.Knockdown(knockdown_time)
|
||||
if(length(msg))
|
||||
user.visible_message("<span class='danger'>[msg]!</span>")
|
||||
|
||||
/datum/component/jousting/proc/mob_move(newloc, dir)
|
||||
if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
|
||||
return
|
||||
if(dir != current_direction)
|
||||
current_tile_charge = 0
|
||||
current_direction = dir
|
||||
if(current_tile_charge < max_tile_charge)
|
||||
current_tile_charge++
|
||||
if(current_timerid)
|
||||
deltimer(current_timerid)
|
||||
current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
|
||||
|
||||
/datum/component/jousting/proc/reset_charge()
|
||||
current_tile_charge = 0
|
||||
@@ -0,0 +1,53 @@
|
||||
//Items with these will have a chance to get knocked off when disarming
|
||||
/datum/component/knockoff
|
||||
var/knockoff_chance = 100 //Chance to knockoff
|
||||
var/list/target_zones //Aiming for these zones will cause the knockoff, null means all zones allowed
|
||||
var/list/slots_knockoffable //Can be only knocked off from these slots, null means all slots allowed
|
||||
var/datum/component/redirect/disarm_redirect
|
||||
|
||||
/datum/component/knockoff/Initialize(knockoff_chance,zone_override,slots_knockoffable)
|
||||
if(!isitem(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Knockoff component misuse")
|
||||
RegisterSignal(COMSIG_ITEM_EQUIPPED,.proc/OnEquipped)
|
||||
RegisterSignal(COMSIG_ITEM_DROPPED,.proc/OnDropped)
|
||||
|
||||
src.knockoff_chance = knockoff_chance
|
||||
|
||||
if(zone_override)
|
||||
target_zones = zone_override
|
||||
|
||||
if(slots_knockoffable)
|
||||
src.slots_knockoffable = slots_knockoffable
|
||||
|
||||
/datum/component/knockoff/proc/Knockoff(mob/living/attacker,zone)
|
||||
var/obj/item/I = parent
|
||||
var/mob/living/carbon/human/wearer = I.loc
|
||||
if(!istype(wearer))
|
||||
return
|
||||
if(target_zones && !(zone in target_zones))
|
||||
return
|
||||
if(!prob(knockoff_chance))
|
||||
return
|
||||
if(!wearer.dropItemToGround(I))
|
||||
return
|
||||
|
||||
wearer.visible_message("<span class='warning'>[attacker] knocks off [wearer]'s [I.name]!</span>","<span class='userdanger'>[attacker] knocks off your [I.name]!</span>")
|
||||
|
||||
/datum/component/knockoff/proc/OnEquipped(mob/living/carbon/human/H,slot)
|
||||
if(!istype(H))
|
||||
return
|
||||
if(slots_knockoffable && !(slot in slots_knockoffable))
|
||||
if(disarm_redirect)
|
||||
QDEL_NULL(disarm_redirect)
|
||||
return
|
||||
if(!disarm_redirect)
|
||||
disarm_redirect = H.AddComponent(/datum/component/redirect,list(COMSIG_HUMAN_DISARM_HIT),CALLBACK(src,.proc/Knockoff))
|
||||
|
||||
/datum/component/knockoff/proc/OnDropped(mob/living/M)
|
||||
if(disarm_redirect)
|
||||
QDEL_NULL(disarm_redirect)
|
||||
|
||||
/datum/component/knockoff/Destroy()
|
||||
QDEL_NULL(disarm_redirect)
|
||||
. = ..()
|
||||
@@ -4,7 +4,7 @@
|
||||
#define RAD_AMOUNT_EXTREME 1000
|
||||
|
||||
/datum/component/radioactive
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
|
||||
var/source
|
||||
|
||||
@@ -47,13 +47,16 @@
|
||||
if(strength <= RAD_BACKGROUND_RADIATION)
|
||||
return PROCESS_KILL
|
||||
|
||||
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original)
|
||||
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, list/arguments)
|
||||
if(!i_am_original)
|
||||
return
|
||||
if(!hl3_release_date) // Permanently radioactive things don't get to grow stronger
|
||||
return
|
||||
var/datum/component/radioactive/other = C
|
||||
strength = max(strength, other.strength)
|
||||
if(C)
|
||||
var/datum/component/radioactive/other = C
|
||||
strength = max(strength, other.strength)
|
||||
else
|
||||
strength = max(strength, arguments[1])
|
||||
|
||||
/datum/component/radioactive/proc/rad_examine(mob/user, atom/thing)
|
||||
var/atom/master = parent
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/datum/component/thermite
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
var/amount
|
||||
var/overlay
|
||||
|
||||
@@ -46,10 +46,13 @@
|
||||
master.cut_overlay(overlay)
|
||||
return ..()
|
||||
|
||||
/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original)
|
||||
/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original, list/arguments)
|
||||
if(!i_am_original)
|
||||
return
|
||||
amount += newC.amount
|
||||
if(newC)
|
||||
amount += newC.amount
|
||||
else
|
||||
amount += arguments[1]
|
||||
|
||||
/datum/component/thermite/proc/thermite_melt(mob/user)
|
||||
var/turf/master = parent
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
addtimer(CALLBACK(src, .proc/charge), charge_rate)
|
||||
|
||||
/datum/action/innate/dash/proc/charge()
|
||||
current_charges = Clamp(current_charges + 1, 0, max_charges)
|
||||
current_charges = CLAMP(current_charges + 1, 0, max_charges)
|
||||
holder.update_action_buttons_icon()
|
||||
if(recharge_sound)
|
||||
playsound(dashing_item, recharge_sound, 50, 1)
|
||||
|
||||
@@ -185,10 +185,10 @@
|
||||
if(properties["stealth"] >= 2)
|
||||
visibility_flags = HIDDEN_SCANNER
|
||||
|
||||
SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
|
||||
SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE))
|
||||
|
||||
permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
|
||||
cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
|
||||
permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1)
|
||||
cure_chance = 15 - CLAMP(properties["resistance"], -5, 5) // can be between 10 and 20
|
||||
stage_prob = max(properties["stage_rate"], 2)
|
||||
SetSeverity(properties["severity"])
|
||||
GenerateCure(properties)
|
||||
@@ -243,7 +243,7 @@
|
||||
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
|
||||
/datum/disease/advance/proc/GenerateCure()
|
||||
if(properties && properties.len)
|
||||
var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
|
||||
var/res = CLAMP(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
|
||||
cures = list(advance_cures[res])
|
||||
|
||||
// Get the cure name from the cure_id
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/disease/gbs
|
||||
name = "GBS"
|
||||
max_stages = 5
|
||||
max_stages = 4
|
||||
spread_text = "On contact"
|
||||
spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS
|
||||
cure_text = "Synaptizine & Sulfur"
|
||||
@@ -16,25 +16,15 @@
|
||||
..()
|
||||
switch(stage)
|
||||
if(2)
|
||||
if(prob(45))
|
||||
affected_mob.adjustToxLoss(5)
|
||||
affected_mob.updatehealth()
|
||||
if(prob(1))
|
||||
affected_mob.emote("sneeze")
|
||||
if(3)
|
||||
if(prob(5))
|
||||
affected_mob.emote("cough")
|
||||
else if(prob(5))
|
||||
if(3)
|
||||
if(prob(5))
|
||||
affected_mob.emote("gasp")
|
||||
if(prob(10))
|
||||
to_chat(affected_mob, "<span class='danger'>You're starting to feel very weak...</span>")
|
||||
to_chat(affected_mob, "<span class='danger'>Your body hurts all over!</span>")
|
||||
if(4)
|
||||
if(prob(10))
|
||||
affected_mob.emote("cough")
|
||||
affected_mob.adjustToxLoss(5)
|
||||
affected_mob.updatehealth()
|
||||
if(5)
|
||||
to_chat(affected_mob, "<span class='danger'>Your body feels as if it's trying to rip itself open...</span>")
|
||||
to_chat(affected_mob, "<span class='userdanger'>Your body feels as if it's trying to rip itself apart!</span>")
|
||||
if(prob(50))
|
||||
affected_mob.gib()
|
||||
else
|
||||
|
||||
@@ -121,7 +121,7 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
M.playsound_local(epicenter, null, 100, 1, frequency, falloff = 5, S = explosion_sound)
|
||||
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
|
||||
else if(dist <= far_dist)
|
||||
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
|
||||
var/far_volume = CLAMP(far_dist, 30, 50) // Volume is based on explosion size and dist
|
||||
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
|
||||
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
|
||||
EX_PREPROCESS_CHECK_TICK
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
set name = "Show Server Revision"
|
||||
set desc = "Check the current server code revision"
|
||||
|
||||
if(GLOB.round_id)
|
||||
to_chat(src, "<b>Round ID:</b> [GLOB.round_id]")
|
||||
if(GLOB.revdata.originmastercommit)
|
||||
to_chat(src, "<b>Server revision compiled on:</b> [GLOB.revdata.date]")
|
||||
var/prefix = ""
|
||||
|
||||
@@ -10,6 +10,7 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
DATA_HUD_MEDICAL_ADVANCED = new/datum/atom_hud/data/human/medical/advanced(),
|
||||
DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(),
|
||||
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
|
||||
DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
|
||||
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
|
||||
mid_length = 2
|
||||
end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg'
|
||||
volume = 25
|
||||
volume = 15
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
"<span class='userdanger'>[A] slams your chest! You can't breathe!</span>")
|
||||
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
|
||||
if(D.losebreath <= 10)
|
||||
D.losebreath = Clamp(D.losebreath + 5, 0, 10)
|
||||
D.losebreath = CLAMP(D.losebreath + 5, 0, 10)
|
||||
D.adjustOxyLoss(10)
|
||||
add_logs(A, D, "quickchoked")
|
||||
return 1
|
||||
@@ -112,7 +112,7 @@
|
||||
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE)
|
||||
if(D.silent <= 10)
|
||||
D.silent = Clamp(D.silent + 10, 0, 10)
|
||||
D.silent = CLAMP(D.silent + 10, 0, 10)
|
||||
add_logs(A, D, "neck chopped")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -44,11 +44,9 @@
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1)
|
||||
D.apply_damage(rand(5,10), BRUTE, "head")
|
||||
A.apply_damage(rand(5,10), BRUTE, "head")
|
||||
if(!istype(A.head,/obj/item/clothing/head/helmet/) && !istype(A.head,/obj/item/clothing/head/hardhat))
|
||||
A.adjustBrainLoss(5)
|
||||
if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat))
|
||||
D.adjustBrainLoss(5)
|
||||
A.Stun(rand(5,30))
|
||||
A.Stun(rand(10,45))
|
||||
D.Stun(rand(5,30))
|
||||
if(5,6)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
|
||||
+62
-97
@@ -149,7 +149,7 @@
|
||||
return
|
||||
LAZYADD(antag_datums, A)
|
||||
A.create_team(team)
|
||||
var/datum/objective_team/antag_team = A.get_team()
|
||||
var/datum/team/antag_team = A.get_team()
|
||||
if(antag_team)
|
||||
antag_team.add_member(src)
|
||||
A.on_gain()
|
||||
@@ -185,12 +185,6 @@
|
||||
objectives, uplinks, powers etc are all handled.
|
||||
*/
|
||||
|
||||
/datum/mind/proc/remove_objectives()
|
||||
if(objectives.len)
|
||||
for(var/datum/objective/O in objectives)
|
||||
objectives -= O
|
||||
qdel(O)
|
||||
|
||||
/datum/mind/proc/remove_changeling()
|
||||
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
|
||||
if(C)
|
||||
@@ -207,13 +201,12 @@
|
||||
remove_antag_datum(ANTAG_DATUM_BROTHER)
|
||||
SSticker.mode.update_brother_icons_removed(src)
|
||||
|
||||
|
||||
/datum/mind/proc/remove_nukeop()
|
||||
if(src in SSticker.mode.syndicates)
|
||||
SSticker.mode.syndicates -= src
|
||||
SSticker.mode.update_synd_icons_removed(src)
|
||||
special_role = null
|
||||
remove_objectives()
|
||||
remove_antag_equip()
|
||||
var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(nuke)
|
||||
remove_antag_datum(nuke.type)
|
||||
special_role = null
|
||||
|
||||
/datum/mind/proc/remove_wizard()
|
||||
remove_antag_datum(/datum/antagonist/wizard)
|
||||
@@ -223,7 +216,6 @@
|
||||
if(src in SSticker.mode.cult)
|
||||
SSticker.mode.remove_cultist(src, 0, 0)
|
||||
special_role = null
|
||||
remove_objectives()
|
||||
remove_antag_equip()
|
||||
|
||||
/datum/mind/proc/remove_rev()
|
||||
@@ -329,14 +321,19 @@
|
||||
SSticker.mode.add_cultist(src)
|
||||
|
||||
else if(is_revolutionary(creator))
|
||||
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev)
|
||||
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
|
||||
converter.add_revolutionary(src,FALSE)
|
||||
|
||||
else if(is_servant_of_ratvar(creator))
|
||||
add_servant_of_ratvar(current)
|
||||
|
||||
else if(is_nuclear_operative(creator))
|
||||
make_Nuke(null, null, 0, FALSE)
|
||||
var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
var/datum/antagonist/nukeop/N = new(src)
|
||||
N.send_to_spawnpoint = FALSE
|
||||
N.nukeop_outfit = null
|
||||
add_antag_datum(N,converter.nuke_team)
|
||||
|
||||
|
||||
enslaved_to = creator
|
||||
|
||||
@@ -493,7 +490,8 @@
|
||||
if (SSticker.mode.config_tag=="nuclear")
|
||||
text = uppertext(text)
|
||||
text = "<i><b>[text]</b></i>: "
|
||||
if (src in SSticker.mode.syndicates)
|
||||
var/datum/antagonist/nukeop/N = has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(N)
|
||||
text += "<b>OPERATIVE</b> | <a href='?src=[REF(src)];nuclear=clear'>nanotrasen</a>"
|
||||
text += "<br><a href='?src=[REF(src)];nuclear=lair'>To shuttle</a>, <a href='?src=[REF(src)];common=undress'>undress</a>, <a href='?src=[REF(src)];nuclear=dressup'>dress up</a>."
|
||||
var/code
|
||||
@@ -713,7 +711,7 @@
|
||||
out += sections[i]+"<br>"
|
||||
|
||||
|
||||
if(((src in SSticker.mode.traitors) || (src in SSticker.mode.syndicates)) && ishuman(current))
|
||||
if(((src in SSticker.mode.traitors) || is_nuclear_operative(current)) && ishuman(current))
|
||||
text = "Uplink: <a href='?src=[REF(src)];common=uplink'>give</a>"
|
||||
var/datum/component/uplink/U = find_syndicate_uplink()
|
||||
if(U)
|
||||
@@ -769,17 +767,44 @@
|
||||
var/objective_pos
|
||||
var/def_value
|
||||
|
||||
|
||||
|
||||
var/datum/antagonist/target_antag
|
||||
|
||||
if (href_list["obj_edit"])
|
||||
objective = locate(href_list["obj_edit"])
|
||||
if (!objective)
|
||||
return
|
||||
objective_pos = objectives.Find(objective)
|
||||
|
||||
for(var/datum/antagonist/A in antag_datums)
|
||||
if(objective in A.objectives)
|
||||
target_antag = A
|
||||
objective_pos = A.objectives.Find(objective)
|
||||
break
|
||||
|
||||
if(!target_antag) //Shouldn't happen
|
||||
stack_trace("objective without antagonist found")
|
||||
objective_pos = objectives.Find(objective)
|
||||
|
||||
//Text strings are easy to manipulate. Revised for simplicity.
|
||||
var/temp_obj_type = "[objective.type]"//Convert path into a text string.
|
||||
def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
|
||||
if(!def_value)//If it's a custom objective, it will be an empty string.
|
||||
def_value = "custom"
|
||||
else
|
||||
switch(antag_datums.len)
|
||||
if(0)
|
||||
target_antag = add_antag_datum(/datum/antagonist/custom)
|
||||
if(1)
|
||||
target_antag = antag_datums[1]
|
||||
else
|
||||
var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
|
||||
if (QDELETED(target))
|
||||
return
|
||||
else if(target == "(new custom antag)")
|
||||
target_antag = add_antag_datum(/datum/antagonist/custom)
|
||||
else
|
||||
target_antag = target
|
||||
|
||||
var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "late-assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
|
||||
if (!new_obj_type)
|
||||
@@ -901,11 +926,15 @@
|
||||
return
|
||||
|
||||
if (objective)
|
||||
if(target_antag)
|
||||
target_antag.objectives -= objective
|
||||
objectives -= objective
|
||||
objectives.Insert(objective_pos, new_objective)
|
||||
target_antag.objectives.Insert(objective_pos, new_objective)
|
||||
message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
|
||||
log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
|
||||
else
|
||||
if(target_antag)
|
||||
target_antag.objectives += new_objective
|
||||
objectives += new_objective
|
||||
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
|
||||
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
|
||||
@@ -914,6 +943,11 @@
|
||||
var/datum/objective/objective = locate(href_list["obj_delete"])
|
||||
if(!istype(objective))
|
||||
return
|
||||
|
||||
for(var/datum/antagonist/A in antag_datums)
|
||||
if(objective in A.objectives)
|
||||
A.objectives -= objective
|
||||
break
|
||||
objectives -= objective
|
||||
message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
|
||||
log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")
|
||||
@@ -996,11 +1030,13 @@
|
||||
message_admins("[key_name_admin(usr)] has cult'ed [current].")
|
||||
log_admin("[key_name(usr)] has cult'ed [current].")
|
||||
if("tome")
|
||||
if (!SSticker.mode.equip_cultist(current,1))
|
||||
var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if (C.equip_cultist(current,1))
|
||||
to_chat(usr, "<span class='danger'>Spawning tome failed!</span>")
|
||||
|
||||
if("amulet")
|
||||
if (!SSticker.mode.equip_cultist(current))
|
||||
var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if (C.equip_cultist(current))
|
||||
to_chat(usr, "<span class='danger'>Spawning amulet failed!</span>")
|
||||
|
||||
else if(href_list["clockcult"])
|
||||
@@ -1071,36 +1107,14 @@
|
||||
message_admins("[key_name_admin(usr)] has de-nuke op'ed [current].")
|
||||
log_admin("[key_name(usr)] has de-nuke op'ed [current].")
|
||||
if("nuclear")
|
||||
if(!(src in SSticker.mode.syndicates))
|
||||
SSticker.mode.syndicates += src
|
||||
SSticker.mode.update_synd_icons_added(src)
|
||||
if (SSticker.mode.syndicates.len==1)
|
||||
SSticker.mode.prepare_syndicate_leader(src)
|
||||
else
|
||||
current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
|
||||
if(!has_antag_datum(/datum/antagonist/nukeop,TRUE))
|
||||
add_antag_datum(/datum/antagonist/nukeop)
|
||||
special_role = "Syndicate"
|
||||
assigned_role = "Syndicate"
|
||||
to_chat(current, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
|
||||
SSticker.mode.forge_syndicate_objectives(src)
|
||||
SSticker.mode.greet_syndicate(src)
|
||||
message_admins("[key_name_admin(usr)] has nuke op'ed [current].")
|
||||
log_admin("[key_name(usr)] has nuke op'ed [current].")
|
||||
if("lair")
|
||||
current.forceMove(pick(GLOB.nukeop_start))
|
||||
if("dressup")
|
||||
var/mob/living/carbon/human/H = current
|
||||
qdel(H.belt)
|
||||
qdel(H.back)
|
||||
qdel(H.ears)
|
||||
qdel(H.gloves)
|
||||
qdel(H.head)
|
||||
qdel(H.shoes)
|
||||
qdel(H.wear_id)
|
||||
qdel(H.wear_suit)
|
||||
qdel(H.w_uniform)
|
||||
|
||||
if (!SSticker.mode.equip_syndicate(current))
|
||||
to_chat(usr, "<span class='danger'>Equipping a syndicate failed!</span>")
|
||||
if("tellcode")
|
||||
var/code
|
||||
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
|
||||
@@ -1348,50 +1362,6 @@
|
||||
T.should_specialise = TRUE
|
||||
add_antag_datum(T)
|
||||
|
||||
|
||||
/datum/mind/proc/make_Nuke(turf/spawnloc, nuke_code, leader=0, telecrystals = TRUE)
|
||||
if(!(src in SSticker.mode.syndicates))
|
||||
SSticker.mode.syndicates += src
|
||||
SSticker.mode.update_synd_icons_added(src)
|
||||
assigned_role = "Syndicate"
|
||||
special_role = "Syndicate"
|
||||
SSticker.mode.forge_syndicate_objectives(src)
|
||||
SSticker.mode.greet_syndicate(src)
|
||||
current.faction |= "syndicate"
|
||||
|
||||
if(spawnloc)
|
||||
current.forceMove(spawnloc)
|
||||
|
||||
if(ishuman(current))
|
||||
var/mob/living/carbon/human/H = current
|
||||
qdel(H.belt)
|
||||
qdel(H.back)
|
||||
qdel(H.ears)
|
||||
qdel(H.gloves)
|
||||
qdel(H.head)
|
||||
qdel(H.shoes)
|
||||
qdel(H.wear_id)
|
||||
qdel(H.wear_suit)
|
||||
qdel(H.w_uniform)
|
||||
|
||||
SSticker.mode.equip_syndicate(current, telecrystals)
|
||||
|
||||
if (nuke_code)
|
||||
store_memory("<B>Syndicate Nuclear Bomb Code</B>: [nuke_code]", 0, 0)
|
||||
to_chat(current, "The nuclear authorization code is: <B>[nuke_code]</B>")
|
||||
else
|
||||
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
|
||||
if(nuke)
|
||||
store_memory("<B>Syndicate Nuclear Bomb Code</B>: [nuke.r_code]", 0, 0)
|
||||
to_chat(current, "The nuclear authorization code is: <B>nuke.r_code</B>")
|
||||
else
|
||||
to_chat(current, "You were not provided with a nuclear code. Trying asking your team leader or contacting syndicate command.</B>")
|
||||
|
||||
if (leader)
|
||||
SSticker.mode.prepare_syndicate_leader(src,nuke_code)
|
||||
else
|
||||
current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]"
|
||||
|
||||
/datum/mind/proc/make_Changling()
|
||||
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!C)
|
||||
@@ -1407,16 +1377,11 @@
|
||||
|
||||
|
||||
/datum/mind/proc/make_Cultist()
|
||||
if(!(src in SSticker.mode.cult))
|
||||
SSticker.mode.add_cultist(src,FALSE)
|
||||
if(!has_antag_datum(/datum/antagonist/cult,TRUE))
|
||||
SSticker.mode.add_cultist(src,FALSE,equip=TRUE)
|
||||
special_role = "Cultist"
|
||||
to_chat(current, "<font color=\"purple\"><b><i>You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar-Sie.</b></i></font>")
|
||||
to_chat(current, "<font color=\"purple\"><b><i>Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</b></i></font>")
|
||||
var/datum/antagonist/cult/C
|
||||
C.cult_memorization(src)
|
||||
var/mob/living/carbon/human/H = current
|
||||
if (!SSticker.mode.equip_cultist(current))
|
||||
to_chat(H, "Spawning an amulet from your Master failed.")
|
||||
|
||||
/datum/mind/proc/make_Rev()
|
||||
var/datum/antagonist/rev/head/head = new(src)
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
if (user.client)
|
||||
user.client.images += bar
|
||||
|
||||
progress = Clamp(progress, 0, goal)
|
||||
progress = CLAMP(progress, 0, goal)
|
||||
bar.icon_state = "prog_bar_[round(((progress / goal) * 100), 5)]"
|
||||
if (!shown)
|
||||
user.client.images += bar
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
var/strength
|
||||
if(steps>1)
|
||||
strength = InverseSquareLaw(intensity, max(range_modifier*steps, 1), 1)
|
||||
strength = INVERSE_SQUARE(intensity, max(range_modifier*steps, 1), 1)
|
||||
else
|
||||
strength = intensity
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
radiate(atoms, Floor(strength))
|
||||
radiate(atoms, FLOOR(strength, 1))
|
||||
|
||||
check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
if(istype(L)) //this is probably more safety than actually needed
|
||||
var/vanguard = L.stun_absorption["vanguard"]
|
||||
desc = initial(desc)
|
||||
desc += "<br><b>[Floor(vanguard["stuns_absorbed"] * 0.1)]</b> seconds of stuns held back.\
|
||||
[GLOB.ratvar_awakens ? "":"<br><b>[Floor(min(vanguard["stuns_absorbed"] * 0.025, 20))]</b> seconds of stun will affect you."]"
|
||||
desc += "<br><b>[FLOOR(vanguard["stuns_absorbed"] * 0.1, 1)]</b> seconds of stuns held back.\
|
||||
[GLOB.ratvar_awakens ? "":"<br><b>[FLOOR(min(vanguard["stuns_absorbed"] * 0.025, 20), 1)]</b> seconds of stun will affect you."]"
|
||||
..()
|
||||
|
||||
/datum/status_effect/vanguard_shield/Destroy()
|
||||
@@ -87,7 +87,7 @@
|
||||
var/vanguard = owner.stun_absorption["vanguard"]
|
||||
var/stuns_blocked = 0
|
||||
if(vanguard)
|
||||
stuns_blocked = Floor(min(vanguard["stuns_absorbed"] * 0.25, 400))
|
||||
stuns_blocked = FLOOR(min(vanguard["stuns_absorbed"] * 0.25, 400), 1)
|
||||
vanguard["end_time"] = 0 //so it doesn't absorb the stuns we're about to apply
|
||||
if(owner.stat != DEAD)
|
||||
var/message_to_owner = "<span class='warning'>You feel your Vanguard quietly fade...</span>"
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
if(prob(severity * 0.15))
|
||||
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(mania_messages))]\"</span>")
|
||||
owner.playsound_local(get_turf(motor), hum, severity, 1)
|
||||
owner.adjust_drugginess(Clamp(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
|
||||
owner.adjust_drugginess(CLAMP(max(severity * 0.075, 1), 0, max(0, 50 - owner.druggy))) //7.5% of severity per second, minimum 1
|
||||
if(owner.hallucination < 50)
|
||||
owner.hallucination = min(owner.hallucination + max(severity * 0.075, 1), 50) //7.5% of severity per second, minimum 1
|
||||
if(owner.dizziness < 50)
|
||||
@@ -310,7 +310,7 @@
|
||||
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
|
||||
var/icon_height = I.Height()
|
||||
bleed_overlay.pixel_x = -owner.pixel_x
|
||||
bleed_overlay.pixel_y = Floor(icon_height * 0.25)
|
||||
bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
|
||||
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
|
||||
bleed_underlay.pixel_x = -owner.pixel_x
|
||||
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
|
||||
|
||||
Reference in New Issue
Block a user