Merge branch 'master' into upstream-merge-33634

This commit is contained in:
LetterJay
2017-12-24 02:39:35 -06:00
committed by GitHub
384 changed files with 3361 additions and 3068 deletions
+1
View File
@@ -145,6 +145,7 @@
#define ADMIN_PUNISHMENT_GIB "Gib"
#define ADMIN_PUNISHMENT_BSA "Bluespace Artillery Device"
#define ADMIN_PUNISHMENT_FIREBALL "Fireball"
#define ADMIN_PUNISHMENT_ROD "Immovable Rod"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
-1
View File
@@ -6,7 +6,6 @@
#define HIEROPHANT_ANSIBLE "hierophant_ansible" //Use this for construction-related scripture!
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
GLOBAL_VAR_INIT(clockwork_caches, 0) //How many clockwork caches exist in the world (not each individual)
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
+4 -3
View File
@@ -6,9 +6,10 @@
// How multiple components of the exact same type are handled in the same datum
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
#define COMPONENT_DUPE_ALLOWED 1 //duplicates allowed
#define COMPONENT_DUPE_UNIQUE 2 //new component is deleted
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4 //old component is given the initialization args of the new
// All signals. Format:
// When the signal is called: (signal arguments)
+3 -7
View File
@@ -334,9 +334,9 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#endif
#endif
// Consider these images/atoms as part of the UI/HUD
// Consider these images/atoms as part of the UI/HUD
#define APPEARANCE_UI_IGNORE_ALPHA RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|RESET_ALPHA|PIXEL_SCALE
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR
#define APPEARANCE_UI RESET_COLOR|RESET_TRANSFORM|NO_CLIENT_COLOR|PIXEL_SCALE
//Just space
#define SPACE_ICON_STATE "[((x + y) ^ ~(x * y) + z) % 25]"
@@ -444,6 +444,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define GIBTONITE_ACTIVE 1
#define GIBTONITE_STABLE 2
#define GIBTONITE_DETONATE 3
//for obj explosion block calculation
#define EXPLOSION_BLOCK_PROC -1
@@ -452,8 +453,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define BEAT_SLOW 2
#define BEAT_NONE 0
#define BEAT_CHANNEL 150
//http://www.byond.com/docs/ref/info.html#/atom/var/mouse_opacity
#define MOUSE_OPACITY_TRANSPARENT 0
#define MOUSE_OPACITY_ICON 1
@@ -484,9 +483,6 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define SYRINGE_DRAW 0
#define SYRINGE_INJECT 1
#define RESEARCH_MATERIAL_RECLAMATION_ID "0"
//gold slime core spawning
#define NO_SPAWN 0
#define HOSTILE_SPAWN 1
+26 -15
View File
@@ -1,19 +1,30 @@
#define SOLID 1
#define LIQUID 2
#define GAS 3
#define SOLID 1
#define LIQUID 2
#define GAS 3
#define INJECTABLE_1 1024 //Makes reagents addable through droppers and syringes
#define DRAWABLE_1 2048 //If a syringe can draw from it
#define OPENCONTAINER_1 4096 //Is an open container for chemistry purposes
#define TRANSPARENT_1 8192 //Used for non-open containers which you still want to be able to see the reagents off.
#define TOUCH 1 //splashing
#define INGEST 2 //ingestion
#define VAPOR 3 //foam, spray, blob attack
#define PATCH 4 //patches
#define INJECT 5 //injection
// container_type defines
#define INJECTABLE 1 // Makes it possible to add reagents through droppers and syringes.
#define DRAWABLE 2 // Makes it possible to remove reagents through syringes.
#define REFILLABLE 4 // Makes it possible to add reagents through any reagent container.
#define DRAINABLE 8 // Makes it possible to remove reagents through any reagent container.
#define TRANSPARENT 16 // Used on containers which you want to be able to see the reagents off.
#define AMOUNT_VISIBLE 32 // For non-transparent containers that still have the general amount of reagents in them visible.
// Is an open container for all intents and purposes.
#define OPENCONTAINER REFILLABLE | DRAINABLE | TRANSPARENT
#define TOUCH 1 // splashing
#define INGEST 2 // ingestion
#define VAPOR 3 // foam, spray, blob attack
#define PATCH 4 // patches
#define INJECT 5 // injection
//defines passed through to the on_reagent_change proc
#define DEL_REAGENT 1 //reagent deleted (fully cleared)
#define ADD_REAGENT 2 // reagent added
#define REM_REAGENT 3 // reagent removed (may still exist)
#define DEL_REAGENT 1 // reagent deleted (fully cleared)
#define ADD_REAGENT 2 // reagent added
#define REM_REAGENT 3 // reagent removed (may still exist)
+6
View File
@@ -1,4 +1,8 @@
#define RDCONSOLE_UI_MODE_NORMAL 1
#define RDCONSOLE_UI_MODE_EXPERT 2
#define RDCONSOLE_UI_MODE_LIST 3
//RDSCREEN screens
#define RDSCREEN_MENU 0
#define RDSCREEN_TECHDISK 1
@@ -59,3 +63,5 @@
//#define DEPARTMENTAL_FLAG_MINING 128
#define DESIGN_ID_IGNORE "IGNORE_THIS_DESIGN"
#define RESEARCH_MATERIAL_RECLAMATION_ID "__materials"
+420
View File
@@ -0,0 +1,420 @@
/datum/controller/subsystem/ticker/proc/gather_roundend_feedback()
var/clients = GLOB.player_list.len
var/surviving_humans = 0
var/surviving_total = 0
var/ghosts = 0
var/escaped_humans = 0
var/escaped_total = 0
for(var/mob/M in GLOB.player_list)
if(ishuman(M))
if(!M.stat)
surviving_humans++
if(M.z == ZLEVEL_CENTCOM)
escaped_humans++
if(!M.stat)
surviving_total++
if(M.z == ZLEVEL_CENTCOM)
escaped_total++
if(isobserver(M))
ghosts++
if(clients)
SSblackbox.record_feedback("nested tally", "round_end_stats", clients, list("clients"))
if(ghosts)
SSblackbox.record_feedback("nested tally", "round_end_stats", ghosts, list("ghosts"))
if(surviving_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_humans, list("survivors", "human"))
if(surviving_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_total, list("survivors", "total"))
if(escaped_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_humans, list("escapees", "human"))
if(escaped_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_total, list("escapees", "total"))
gather_antag_success_rate()
/datum/controller/subsystem/ticker/proc/gather_antag_success_rate()
var/team_gid = 1
var/list/team_ids = list()
for(var/datum/antagonist/A in GLOB.antagonists)
var/list/antag_info = list()
antag_info["key"] = A.owner.key
antag_info["name"] = A.owner.name
antag_info["antagonist_type"] = A.type
antag_info["antagonist_name"] = A.name //For auto and custom roles
antag_info["objectives"] = list()
antag_info["team"] = list()
var/datum/team/T = A.get_team()
if(T)
antag_info["team"]["type"] = T.type
antag_info["team"]["name"] = T.name
if(!team_ids[T])
team_ids[T] = team_gid++
antag_info["team"]["id"] = team_ids[T]
if(!A.owner)
continue
if(A.objectives.len)
for(var/datum/objective/O in A.objectives)
var/result = O.check_completion() ? "SUCCESS" : "FAIL"
antag_info["objectives"] += list(list("objective_type"=O.type,"text"=O.explanation_text,"result"=result))
SSblackbox.record_feedback("associative", "antagonists", 1, antag_info)
/datum/controller/subsystem/ticker/proc/declare_completion()
set waitfor = FALSE
to_chat(world, "<BR><BR><BR><FONT size=3><B>The round has ended.</B></FONT>")
if(LAZYLEN(GLOB.round_end_notifiees))
send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
/*for(var/client/C in GLOB.clients)
if(!C.credits)
C.RollCredits()
C.playtitlemusic(40)*/
display_report()
gather_roundend_feedback()
CHECK_TICK
// Add AntagHUD to everyone, see who was really evil the whole time!
for(var/datum/atom_hud/antag/H in GLOB.huds)
for(var/m in GLOB.player_list)
var/mob/M = m
H.add_hud_to(M)
CHECK_TICK
//Set news report and mode result
mode.set_round_result()
send2irc("Server", "Round just ended.")
if(CONFIG_GET(string/cross_server_address))
send_news_report()
CHECK_TICK
//These need update to actually reflect the real antagonists
//Print a list of antagonists to the server log
var/list/total_antagonists = list()
//Look into all mobs in world, dead or alive
for(var/datum/mind/Mind in minds)
var/temprole = Mind.special_role
if(temprole) //if they are an antagonist of some sort.
if(temprole in total_antagonists) //If the role exists already, add the name to it
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
else
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
CHECK_TICK
//Now print them all into the log!
log_game("Antagonists at round end were...")
for(var/i in total_antagonists)
log_game("[i]s[total_antagonists[i]].")
CHECK_TICK
//Collects persistence features
if(mode.allow_persistence_save)
SSpersistence.CollectData()
//stop collecting feedback during grifftime
SSblackbox.Seal()
sleep(50)
ready_for_reboot = TRUE
standard_reboot()
/datum/controller/subsystem/ticker/proc/standard_reboot()
if(ready_for_reboot)
if(mode.station_was_nuked)
Reboot("Station destroyed by Nuclear Device.", "nuke")
else
Reboot("Round ended.", "proper completion")
else
CRASH("Attempted standard reboot without ticker roundend completion")
//Common part of the report
/datum/controller/subsystem/ticker/proc/build_roundend_report()
var/list/parts = list()
//Gamemode specific things. Should be empty most of the time.
parts += mode.special_report()
CHECK_TICK
//AI laws
parts += law_report()
CHECK_TICK
//Antagonists
parts += antag_report()
CHECK_TICK
//Medals
parts += medal_report()
//Station Goals
parts += goal_report()
listclearnulls(parts)
return parts.Join()
/datum/controller/subsystem/ticker/proc/survivor_report()
var/list/parts = list()
var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
var/num_survivors = 0
var/num_escapees = 0
var/num_shuttle_escapees = 0
//Player status report
for(var/i in GLOB.mob_list)
var/mob/Player = i
if(Player.mind && !isnewplayer(Player))
if(Player.stat != DEAD && !isbrain(Player))
num_survivors++
if(station_evacuated) //If the shuttle has already left the station
var/list/area/shuttle_areas
if(SSshuttle && SSshuttle.emergency)
shuttle_areas = SSshuttle.emergency.shuttle_areas
if(Player.onCentCom() || Player.onSyndieBase())
num_escapees++
if(shuttle_areas[get_area(Player)])
num_shuttle_escapees++
//Round statistics report
var/datum/station_state/end_state = new /datum/station_state()
end_state.count()
var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
parts += "[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>"
parts += "[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<span class='redtext'>Destroyed</span>" : "[station_integrity]%"]</B>"
var/total_players = GLOB.joined_player_list.len
if(total_players)
parts+= "[GLOB.TAB]Total Population: <B>[total_players]</B>"
if(station_evacuated)
parts += "<BR>[GLOB.TAB]Evacuation Rate: <B>[num_escapees] ([PERCENT(num_escapees/total_players)]%)</B>"
parts += "[GLOB.TAB](on emergency shuttle): <B>[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)</B>"
parts += "[GLOB.TAB]Survival Rate: <B>[num_survivors] ([PERCENT(num_survivors/total_players)]%)</B>"
return parts.Join("<br>")
/datum/controller/subsystem/ticker/proc/show_roundend_report(client/C,common_report)
var/list/report_parts = list()
report_parts += personal_report(C)
report_parts += common_report
var/datum/browser/roundend_report = new(C, "roundend")
roundend_report.width = 800
roundend_report.height = 600
roundend_report.set_content(report_parts.Join())
roundend_report.stylesheets = list()
roundend_report.add_stylesheet("roundend",'html/browser/roundend.css')
roundend_report.open(0)
/datum/controller/subsystem/ticker/proc/personal_report(client/C)
var/list/parts = list()
var/mob/M = C.mob
if(M.mind && !isnewplayer(M))
if(M.stat != DEAD && !isbrain(M))
if(EMERGENCY_ESCAPED_OR_ENDGAMED)
if(!M.onCentCom() || !M.onSyndieBase())
parts += "<div class='panel stationborder'>"
parts += "<span class='marooned'>You managed to survive, but were marooned on [station_name()]...</span>"
else
parts += "<div class='panel greenborder'>"
parts += "<span class='greentext'>You managed to survive the events on [station_name()] as [M.real_name].</span>"
else
parts += "<div class='panel greenborder'>"
parts += "<span class='greentext'>You managed to survive the events on [station_name()] as [M.real_name].</span>"
else
parts += "<div class='panel redborder'>"
parts += "<span class='redtext'>You did not survive the events on [station_name()]...</span>"
else
parts += "<div class='panel stationborder'>"
parts += "<br>"
if(GLOB.survivor_report)
parts += GLOB.survivor_report
else
parts += survivor_report()
parts += "</div>"
return parts.Join()
/datum/controller/subsystem/ticker/proc/display_report()
GLOB.common_report = build_roundend_report()
for(var/client/C in GLOB.clients)
show_roundend_report(C,GLOB.common_report)
give_show_report_button(C)
CHECK_TICK
/datum/controller/subsystem/ticker/proc/law_report()
var/list/parts = list()
//Silicon laws report
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if(aiPlayer.mind)
parts += "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws [aiPlayer.stat != DEAD ? "at the end of the round" : "when it was deactivated"] were:</b>"
parts += aiPlayer.laws.get_law_list(include_zeroth=TRUE)
parts += "<b>Total law changes: [aiPlayer.law_change_counter]</b>"
if (aiPlayer.connected_robots.len)
var/robolist = "<b>[aiPlayer.real_name]'s minions were:</b> "
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
if(robo.mind)
robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
parts += "[robolist]"
for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
if (!robo.connected_ai && robo.mind)
if (robo.stat != DEAD)
parts += "<b>[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:</b>"
else
parts += "<b>[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:</b>"
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
parts += robo.laws.get_law_list(include_zeroth=TRUE)
if(parts.len)
return "<div class='panel stationborder'>[parts.Join("<br>")]</div>"
else
return ""
/datum/controller/subsystem/ticker/proc/goal_report()
var/list/parts = list()
if(mode.station_goals.len)
for(var/V in mode.station_goals)
var/datum/station_goal/G = V
parts += G.get_result()
return "<div class='panel stationborder'><ul>[parts.Join()]</ul></div>"
/datum/controller/subsystem/ticker/proc/medal_report()
if(GLOB.commendations.len)
var/list/parts = list()
parts += "<span class='header'>Medal Commendations:</span>"
for (var/com in GLOB.commendations)
parts += com
return "<div class='panel stationborder'>[parts.Join("<br>")]</div>"
return ""
/datum/controller/subsystem/ticker/proc/antag_report()
var/list/result = list()
var/list/all_teams = list()
var/list/all_antagonists = list()
for(var/datum/antagonist/A in GLOB.antagonists)
all_teams |= A.get_team()
all_antagonists += A
for(var/datum/team/T in all_teams)
result += T.roundend_report()
for(var/datum/antagonist/X in all_antagonists)
if(X.get_team() == T)
all_antagonists -= X
result += " "//newline between teams
var/currrent_category
var/datum/antagonist/previous_category
sortTim(all_antagonists, /proc/cmp_antag_category)
for(var/datum/antagonist/A in all_antagonists)
if(!A.show_in_roundend)
continue
if(A.roundend_category != currrent_category)
if(previous_category)
result += previous_category.roundend_report_footer()
result += "</div>"
result += "<div class='panel redborder'>"
result += A.roundend_report_header()
currrent_category = A.roundend_category
previous_category = A
result += A.roundend_report()
result += "<br>"
if(all_antagonists.len)
var/datum/antagonist/last = all_antagonists[all_antagonists.len]
result += last.roundend_report_footer()
result += "</div>"
return result.Join()
/proc/cmp_antag_category(datum/antagonist/A,datum/antagonist/B)
return sorttext(B.roundend_category,A.roundend_category)
/datum/controller/subsystem/ticker/proc/give_show_report_button(client/C)
var/datum/action/report/R = new
C.player_details.player_actions += R
R.Grant(C.mob)
to_chat(C,"<a href='?src=[REF(R)];report=1'>Show roundend report again</a>")
/datum/action/report
name = "Show roundend report"
button_icon_state = "vote"
/datum/action/report/Trigger()
if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED)
SSticker.show_roundend_report(owner.client,GLOB.common_report)
/datum/action/report/IsAvailable()
return 1
/datum/action/report/Topic(href,href_list)
if(usr != owner)
return
if(href_list["report"])
Trigger()
return
/proc/printplayer(datum/mind/ply, fleecheck)
var/text = "<b>[ply.key]</b> was <b>[ply.name]</b> the <b>[ply.assigned_role]</b> and"
if(ply.current)
if(ply.current.stat == DEAD)
text += " <span class='redtext'>died</span>"
else
text += " <span class='greentext'>survived</span>"
if(fleecheck)
var/turf/T = get_turf(ply.current)
if(!T || !(T.z in GLOB.station_z_levels))
text += " while <span class='redtext'>fleeing the station</span>"
if(ply.current.real_name != ply.name)
text += " as <b>[ply.current.real_name]</b>"
else
text += " <span class='redtext'>had their body destroyed</span>"
return text
/proc/printplayerlist(list/players,fleecheck)
var/list/parts = list()
parts += "<ul class='playerlist'>"
for(var/datum/mind/M in players)
parts += "<li>[printplayer(M,fleecheck)]</li>"
parts += "</ul>"
return parts.Join()
/proc/printobjectives(datum/mind/ply)
var/list/objective_parts = list()
var/count = 1
for(var/datum/objective/objective in ply.objectives)
if(objective.check_completion())
objective_parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
objective_parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
count++
return objective_parts.Join("<br>")
+6 -12
View File
@@ -1,18 +1,12 @@
GLOBAL_VAR_INIT(master_mode, "traitor") //"extended"
GLOBAL_VAR_INIT(secret_force_mode, "secret") // if this is anything but "secret", the secret rotation will forceably choose this mode
GLOBAL_VAR(common_report) //Contains commmon part of roundend report
GLOBAL_VAR(survivor_report) //Contains shared surivor report for roundend report (part of personal report)
GLOBAL_VAR_INIT(wavesecret, 0) // meteor mode, delays wave progression, terrible name
GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report
// Cult, needs to be global so admin cultists are functional
GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master
GLOBAL_DATUM(blood_target_image, /image)
GLOBAL_VAR_INIT(blood_target_reset_timer, null)
GLOBAL_DATUM(sac_mind, /datum/mind)
GLOBAL_VAR_INIT(sac_image, null)
GLOBAL_VAR_INIT(cult_vote_called, FALSE)
GLOBAL_VAR_INIT(cult_mastered, FALSE)
GLOBAL_VAR_INIT(reckoning_complete, FALSE)
GLOBAL_VAR_INIT(sac_complete, FALSE)
GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
GLOBAL_LIST_EMPTY(summon_spots)
//TODO clear this one up too
GLOBAL_DATUM(cult_narsie, /obj/singularity/narsie/large/cult)
+2
View File
@@ -16,3 +16,5 @@ GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a perce
GLOBAL_LIST_EMPTY(powernets)
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
+21 -10
View File
@@ -302,32 +302,41 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
/obj/screen/alert/bloodsense/process()
var/atom/blood_target
if(GLOB.blood_target)
if(!get_turf(GLOB.blood_target))
GLOB.blood_target = null
var/datum/antagonist/cult/antag = mob_viewer.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
if(antag.cult_team.blood_target)
if(!get_turf(antag.cult_team.blood_target))
antag.cult_team.blood_target = null
else
blood_target = GLOB.blood_target
blood_target = antag.cult_team.blood_target
if(Cviewer && Cviewer.seeking && Cviewer.master)
blood_target = Cviewer.master
desc = "Your blood sense is leading you to [Cviewer.master]"
if(!blood_target)
if(!GLOB.sac_complete)
if(sac_objective && !sac_objective.check_completion())
if(icon_state == "runed_sense0")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense0"
desc = "Nar-Sie demands that [GLOB.sac_mind] be sacrificed before the summoning ritual can begin."
add_overlay(GLOB.sac_image)
desc = "Nar-Sie demands that [sac_objective.target] be sacrificed before the summoning ritual can begin."
add_overlay(sac_objective.sac_image)
else
var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
if(!summon_objective)
return
if(icon_state == "runed_sense1")
return
animate(src, transform = null, time = 1, loop = 0)
angle = 0
cut_overlays()
icon_state = "runed_sense1"
desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(GLOB.summon_spots)]!"
desc = "The sacrifice is complete, summon Nar-Sie! The summoning can only take place in [english_list(summon_objective.summon_spots)]!"
add_overlay(narnar)
return
var/turf/P = get_turf(blood_target)
@@ -388,11 +397,13 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
desc = "<font size=3><b>CHETR<br>NYY<br>HAGEHUGF-NAQ-UBABE<br>RATVAR.</b></font>"
else
var/servants = 0
var/list/textlist
var/list/textlist = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L))
servants++
textlist = list("[SSticker.mode.eminence ? "There is an Eminence." : "<b>There is no Eminence! Get one ASAP!</b>"]<br>")
var/datum/antagonist/clockcult/C = mob_viewer.mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(C && C.clock_team)
textlist += "[C.clock_team.eminence ? "There is an Eminence." : "<b>There is no Eminence! Get one ASAP!</b>"]<br>"
textlist += "There are currently <b>[servants]</b> servant[servants > 1 ? "s" : ""] of Ratvar.<br>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER) //ignore the always-unlocked stuff
@@ -22,7 +22,7 @@ GLOBAL_PROTECT(config_dir)
config = src
InitEntries()
LoadModes()
if(!LoadEntries("config.txt"))
if(LoadEntries("config.txt") <= 1)
log_config("No $include directives found in config.txt! Loading legacy game_options/dbconfig/comms files...")
LoadEntries("game_options.txt")
LoadEntries("dbconfig.txt")
@@ -97,6 +97,13 @@ GLOBAL_PROTECT(config_dir)
if(!entry)
continue
if(entry == "$include")
if(!value)
log_config("Warning: Invalid $include directive: [value]")
else
LoadEntries(value, stack)
++.
continue
if(entry == "$include")
if(!value)
@@ -123,8 +130,8 @@ GLOBAL_PROTECT(config_dir)
if(validated)
E.modified = TRUE
. = TRUE
++.
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
+6 -2
View File
@@ -10,7 +10,8 @@ SUBSYSTEM_DEF(blackbox)
var/sealed = FALSE //time to stop tracking stats?
var/list/research_levels = list() //list of highest tech levels attained that isn't lost lost by destruction of RD computers
var/list/versions = list("time_dilation_current" = 2,
"science_techweb_unlock" = 2) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
"science_techweb_unlock" = 2,
"antagonists" = 3) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
/datum/controller/subsystem/blackbox/Initialize()
@@ -225,7 +226,10 @@ Versioning
var/pos = length(FV.json["data"]) + 1
FV.json["data"]["[pos]"] = list() //in 512 "pos" can be replaced with "[FV.json["data"].len+1]"
for(var/i in data)
FV.json["data"]["[pos]"]["[i]"] = "[data[i]]" //and here with "[FV.json["data"].len]"
if(islist(data[i]))
FV.json["data"]["[pos]"]["[i]"] = data[i] //and here with "[FV.json["data"].len]"
else
FV.json["data"]["[pos]"]["[i]"] = "[data[i]]"
else
CRASH("Invalid feedback key_type: [key_type]")
-198
View File
@@ -398,204 +398,6 @@ SUBSYSTEM_DEF(ticker)
var/mob/living/L = I
L.notransform = FALSE
/datum/controller/subsystem/ticker/proc/declare_completion()
set waitfor = FALSE
var/station_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED
var/num_survivors = 0
var/num_escapees = 0
var/num_shuttle_escapees = 0
var/list/successfulCrew = list()
var/list/miscreants = list()
to_chat(world, "<BR><BR><BR><FONT size=3><B>The round has ended.</B></FONT>")
if(LAZYLEN(GLOB.round_end_notifiees))
send2irc("Notice", "[GLOB.round_end_notifiees.Join(", ")] the round has ended.")
/* var/nocredits = config.no_credits_round_end
for(var/client/C in GLOB.clients)
if(!C.credits && !nocredits)
C.RollCredits()
C.playtitlemusic(40)*/
//Player status report
for(var/i in GLOB.mob_list)
var/mob/Player = i
if(Player.mind && !isnewplayer(Player))
if(Player.stat != DEAD && !isbrain(Player))
num_survivors++
if(station_evacuated) //If the shuttle has already left the station
var/list/area/shuttle_areas
if(SSshuttle && SSshuttle.emergency)
shuttle_areas = SSshuttle.emergency.shuttle_areas
if(!Player.onCentCom() && !Player.onSyndieBase())
to_chat(Player, "<font color='blue'><b>You managed to survive, but were marooned on [station_name()]...</b></FONT>")
else
num_escapees++
to_chat(Player, "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></FONT>")
if(shuttle_areas[get_area(Player)])
num_shuttle_escapees++
else
to_chat(Player, "<font color='green'><b>You managed to survive the events on [station_name()] as [Player.real_name].</b></FONT>")
else
to_chat(Player, "<font color='red'><b>You did not survive the events on [station_name()]...</b></FONT>")
CHECK_TICK
//Round statistics report
var/datum/station_state/end_state = new /datum/station_state()
end_state.count()
var/station_integrity = min(PERCENT(GLOB.start_state.score(end_state)), 100)
to_chat(world, "<BR>[GLOB.TAB]Shift Duration: <B>[DisplayTimeText(world.time - SSticker.round_start_time)]</B>")
to_chat(world, "<BR>[GLOB.TAB]Station Integrity: <B>[mode.station_was_nuked ? "<font color='red'>Destroyed</font>" : "[station_integrity]%"]</B>")
if(mode.station_was_nuked)
SSticker.news_report = STATION_DESTROYED_NUKE
var/total_players = GLOB.joined_player_list.len
if(total_players)
to_chat(world, "<BR>[GLOB.TAB]Total Population: <B>[total_players]</B>")
if(station_evacuated)
to_chat(world, "<BR>[GLOB.TAB]Evacuation Rate: <B>[num_escapees] ([PERCENT(num_escapees/total_players)]%)</B>")
to_chat(world, "<BR>[GLOB.TAB](on emergency shuttle): <B>[num_shuttle_escapees] ([PERCENT(num_shuttle_escapees/total_players)]%)</B>")
news_report = STATION_EVACUATED
if(SSshuttle.emergency.is_hijacked())
news_report = SHUTTLE_HIJACK
to_chat(world, "<BR>[GLOB.TAB]Survival Rate: <B>[num_survivors] ([PERCENT(num_survivors/total_players)]%)</B>")
to_chat(world, "<BR>")
CHECK_TICK
//Silicon laws report
for (var/i in GLOB.ai_list)
var/mob/living/silicon/ai/aiPlayer = i
if (aiPlayer.stat != DEAD && aiPlayer.mind)
to_chat(world, "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws at the end of the round were:</b>")
aiPlayer.show_laws(1)
else if (aiPlayer.mind) //if the dead ai has a mind, use its key instead
to_chat(world, "<b>[aiPlayer.name] (Played by: [aiPlayer.mind.key])'s laws when it was deactivated were:</b>")
aiPlayer.show_laws(1)
to_chat(world, "<b>Total law changes: [aiPlayer.law_change_counter]</b>")
if (aiPlayer.connected_robots.len)
var/robolist = "<b>[aiPlayer.real_name]'s minions were:</b> "
for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots)
if(robo.mind)
robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.mind.key]), ":" (Played by: [robo.mind.key]), "]"
to_chat(world, "[robolist]")
CHECK_TICK
for (var/mob/living/silicon/robot/robo in GLOB.silicon_mobs)
if (!robo.connected_ai && robo.mind)
if (robo.stat != DEAD)
to_chat(world, "<b>[robo.name] (Played by: [robo.mind.key]) survived as an AI-less borg! Its laws were:</b>")
else
to_chat(world, "<b>[robo.name] (Played by: [robo.mind.key]) was unable to survive the rigors of being a cyborg without an AI. Its laws were:</b>")
if(robo) //How the hell do we lose robo between here and the world messages directly above this?
robo.laws.show_laws(world)
CHECK_TICK
mode.declare_completion()//To declare normal completion.
CHECK_TICK
//calls auto_declare_completion_* for all modes
for(var/handler in typesof(/datum/game_mode/proc))
if (findtext("[handler]","auto_declare_completion_"))
call(mode, handler)(force_ending)
CHECK_TICK
if(CONFIG_GET(string/cross_server_address))
send_news_report()
CHECK_TICK
//Print a list of antagonists to the server log
var/list/total_antagonists = list()
//Look into all mobs in world, dead or alive
for(var/datum/mind/Mind in minds)
var/temprole = Mind.special_role
if(temprole) //if they are an antagonist of some sort.
if(temprole in total_antagonists) //If the role exists already, add the name to it
total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
else
total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
CHECK_TICK
//Now print them all into the log!
log_game("Antagonists at round end were...")
for(var/i in total_antagonists)
log_game("[i]s[total_antagonists[i]].")
CHECK_TICK
for(var/datum/mind/crewMind in minds)
if(!crewMind.current || !crewMind.objectives.len)
continue
for(var/datum/objective/miscreant/MO in crewMind.objectives)
miscreants += "<B>[crewMind.current.real_name]</B> (Played by: <B>[crewMind.key]</B>)<BR><B>Objective</B>: [MO.explanation_text] <font color='grey'>(Optional)</font>"
for(var/datum/objective/crew/CO in crewMind.objectives)
if(CO.check_completion())
to_chat(crewMind.current, "<br><B>Your optional objective</B>: [CO.explanation_text] <font color='green'><B>Success!</B></font>")
successfulCrew += "<B>[crewMind.current.real_name]</B> (Played by: <B>[crewMind.key]</B>)<BR><B>Objective</B>: [CO.explanation_text] <font color='green'><B>Success!</B></font> <font color='grey'>(Optional)</font>"
else
to_chat(crewMind.current, "<br><B>Your optional objective</B>: [CO.explanation_text] <font color='red'><B>Failed.</B></font>")
if (successfulCrew.len)
var/completedObjectives = "<B>The following crew members completed their Crew Objectives:</B><BR>"
for(var/i in successfulCrew)
completedObjectives += "[i]<BR>"
to_chat(world, "[completedObjectives]<BR>")
else
if(CONFIG_GET(flag/allow_crew_objectives))
to_chat(world, "<B>Nobody completed their Crew Objectives!</B><BR>")
CHECK_TICK
if (miscreants.len)
var/miscreantObjectives = "<B>The following crew members were miscreants:</B><BR>"
for(var/i in miscreants)
miscreantObjectives += "[i]<BR>"
to_chat(world, "[miscreantObjectives]<BR>")
CHECK_TICK
mode.declare_station_goal_completion()
CHECK_TICK
//medals, placed far down so that people can actually see the commendations.
if(GLOB.commendations.len)
to_chat(world, "<b><font size=3>Medal Commendations:</font></b>")
for (var/com in GLOB.commendations)
to_chat(world, com)
CHECK_TICK
//Collects persistence features
if(mode.allow_persistence_save)
SSpersistence.CollectData()
//stop collecting feedback during grifftime
SSblackbox.Seal()
sleep(50)
ready_for_reboot = TRUE
standard_reboot()
/datum/controller/subsystem/ticker/proc/standard_reboot()
if(ready_for_reboot)
if(mode.station_was_nuked)
Reboot("Station destroyed by Nuclear Device.", "nuke")
else
Reboot("Round ended.", "proper completion")
else
CRASH("Attempted standard reboot without ticker roundend completion")
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
var/m
if(selected_tip)
+11
View File
@@ -206,6 +206,7 @@ SUBSYSTEM_DEF(vote)
var/datum/action/vote/V = new
if(question)
V.name = "Vote: [question]"
C.player_details.player_actions += V
V.Grant(C.mob)
generated_actions += V
return 1
@@ -299,6 +300,7 @@ SUBSYSTEM_DEF(vote)
for(var/v in generated_actions)
var/datum/action/vote/V = v
if(!QDELETED(V))
V.remove_from_client()
V.Remove(V.owner)
generated_actions = list()
@@ -318,7 +320,16 @@ SUBSYSTEM_DEF(vote)
/datum/action/vote/Trigger()
if(owner)
owner.vote()
remove_from_client()
Remove(owner)
/datum/action/vote/IsAvailable()
return 1
/datum/action/vote/proc/remove_from_client()
if(owner.client)
owner.client.player_details.player_actions -= src
else if(owner.ckey)
var/datum/player_details/P = GLOB.player_details[owner.ckey]
if(P)
P.player_actions -= src
+3 -26
View File
@@ -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)
+65 -2
View File
@@ -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)
+59 -3
View File
@@ -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
+70 -2
View File
@@ -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)
+32 -1
View File
@@ -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>")
+53 -2
View File
@@ -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
View File
@@ -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>"
+55 -5
View File
@@ -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>"
+30
View File
@@ -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
+11 -10
View File
@@ -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)
+44 -42
View File
@@ -10,8 +10,9 @@
/datum/antagonist/nukeop
name = "Nuclear Operative"
roundend_category = "syndicate operatives" //just in case
job_rank = ROLE_OPERATIVE
var/datum/objective_team/nuclear/nuke_team
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
@@ -38,7 +39,7 @@
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)
@@ -102,14 +103,14 @@
/datum/antagonist/nukeop/leader/move_to_spawnpoint()
owner.current.forceMove(pick(GLOB.nukeop_leader_start))
/datum/antagonist/nukeop/create_team(datum/objective_team/nuclear/new_team)
/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/objective_team/nuclear
nuke_team = new /datum/team/nuclear
nuke_team.update_objectives()
assign_nuke() //This is bit ugly
return
@@ -157,7 +158,7 @@
return
nuke_team.rename_team(ask_name())
/datum/objective_team/nuclear/proc/rename_team(new_name)
/datum/team/nuclear/proc/rename_team(new_name)
syndicate_name = new_name
name = "[syndicate_name] Team"
for(var/I in members)
@@ -200,43 +201,40 @@
stack_trace("Station self destruct ot found during lone op team creation.")
nuke_team.memorized_code = null
/datum/objective_team/nuclear
var/list/objectives
/datum/team/nuclear
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
var/core_objective = /datum/objective/nuclear
var/memorized_code
/datum/objective_team/nuclear/New()
/datum/team/nuclear/New()
..()
syndicate_name = syndicate_name()
/datum/objective_team/nuclear/proc/update_objectives()
objectives = list()
/datum/team/nuclear/proc/update_objectives()
if(core_objective)
var/datum/objective/O = new core_objective
O.team = src
objectives += O
return
/datum/objective_team/nuclear/proc/disk_rescued()
/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/objective_team/nuclear/proc/operatives_dead()
/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/objective_team/nuclear/proc/syndies_escaped()
/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/objective_team/nuclear/proc/get_result()
/datum/team/nuclear/proc/get_result()
var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
var/disk_rescued = disk_rescued()
var/syndies_didnt_escape = !syndies_escaped()
@@ -264,57 +262,61 @@
else
return //Undefined result
/datum/objective_team/nuclear/proc/roundend_display()
to_chat(world,"<span class='roundendh'>[syndicate_name] Operatives:</span>")
/datum/team/nuclear/roundend_report()
var/list/parts = list()
parts += "<span class='header'>[syndicate_name] Operatives:</span>"
switch(get_result())
if(NUKE_RESULT_FLUKE)
to_chat(world, "<FONT size = 3><B>Humiliating Syndicate Defeat</B></FONT>")
to_chat(world, "<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!")
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)
to_chat(world, "<FONT size = 3><B>Syndicate Major Victory!</B></FONT>")
to_chat(world, "<B>[syndicate_name] operatives have destroyed [station_name()]!</B>")
parts += "<span class='greentext big'>Syndicate Major Victory!</span>"
parts += "<B>[syndicate_name] operatives have destroyed [station_name()]!</B>"
if(NUKE_RESULT_NOSURVIVORS)
to_chat(world, "<FONT size = 3><B>Total Annihilation</B></FONT>")
to_chat(world, "<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!")
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)
to_chat(world, "<FONT size = 3><B>Crew Minor Victory</B></FONT>")
to_chat(world, "<B>[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()].</B> Next time, don't do that!")
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)
to_chat(world, "<FONT size = 3><B>[syndicate_name] operatives have earned Darwin Award!</B></FONT>")
to_chat(world, "<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!")
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)
to_chat(world, "<FONT size = 3><B>Crew Major Victory!</B></FONT>")
to_chat(world, "<B>The Research Staff has saved the disk and killed the [syndicate_name] Operatives</B>")
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)
to_chat(world, "<FONT size = 3><B>Crew Major Victory</B></FONT>")
to_chat(world, "<B>The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!</B>")
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)
to_chat(world, "<FONT size = 3><B>Neutral Victory!</B></FONT>")
to_chat(world, "<B>The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!</B>")
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)
to_chat(world, "<FONT size = 3><B>Syndicate Minor Victory!</B></FONT>")
to_chat(world, "<B>[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()].</B> Next time, don't lose the disk!")
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
to_chat(world, "<FONT size = 3><B>Neutral Victory</B></FONT>")
to_chat(world, "<B>Mission aborted!</B>")
parts += "<span class='neutraltext big'>Neutral Victory</span>"
parts += "<B>Mission aborted!</B>"
var/text = "<br><FONT size=3><B>The syndicate operatives were:</B></FONT>"
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
text += SSticker.mode.printplayer(syndicate) //to be moved
for(var/U in GLOB.uplinks)
var/datum/component/uplink/H = U
if(H.owner == syndicate.key)
TC_uses += H.spent_telecrystals
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>"
to_chat(world, text)
parts += text
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+32 -38
View File
@@ -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>"
+71 -18
View File
@@ -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()
+49 -5
View File
@@ -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>"
+3 -2
View File
@@ -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.
+56 -44
View File
@@ -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
+2 -3
View File
@@ -48,8 +48,7 @@
if(old_dir == new_dir)
return
remove()
var/rotation = SIMPLIFY_DEGREES(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)
+7 -4
View File
@@ -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
+6 -3
View File
@@ -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
+47 -20
View File
@@ -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,6 +201,7 @@
remove_antag_datum(ANTAG_DATUM_BROTHER)
SSticker.mode.update_brother_icons_removed(src)
/datum/mind/proc/remove_nukeop()
var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(nuke)
@@ -221,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()
@@ -339,7 +333,7 @@
N.send_to_spawnpoint = FALSE
N.nukeop_outfit = null
add_antag_datum(N,converter.nuke_team)
enslaved_to = creator
@@ -773,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)
@@ -905,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]")
@@ -918,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]")
@@ -1000,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"])
@@ -1345,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)
+31 -29
View File
@@ -194,27 +194,22 @@
set waitfor = FALSE
return
// Convenience proc to see if a container is open for chemistry handling
// returns true if open
// false if closed
// Convenience procs to see if a container is open for chemistry handling
/atom/proc/is_open_container()
return container_type & OPENCONTAINER_1
/atom/proc/is_transparent()
return container_type & TRANSPARENT_1
return is_refillable() && is_drainable()
/atom/proc/is_injectable(allowmobs = TRUE)
if(isliving(src) && allowmobs)
var/mob/living/L = src
return L.can_inject()
if(container_type & OPENCONTAINER_1)
return TRUE
return container_type & INJECTABLE_1
return reagents && (container_type & (INJECTABLE | REFILLABLE))
/atom/proc/is_drawable(allowmobs = TRUE)
if(is_injectable(allowmobs)) //Everything that can be injected can also be drawn from, but not vice versa
return TRUE
return container_type & DRAWABLE_1
return reagents && (container_type & (DRAWABLE | DRAINABLE))
/atom/proc/is_refillable()
return reagents && (container_type & REFILLABLE)
/atom/proc/is_drainable()
return reagents && (container_type & DRAINABLE)
/atom/proc/AllowDrop()
return FALSE
@@ -256,19 +251,26 @@
if(desc)
to_chat(user, desc)
if(reagents && (is_open_container() || is_transparent())) //is_open_container() isn't really the right proc for this, but w/e
to_chat(user, "It contains:")
if(reagents.reagent_list.len)
if(user.can_see_reagents()) //Show each individual reagent
for(var/datum/reagent/R in reagents.reagent_list)
to_chat(user, "[R.volume] units of [R.name]")
else //Otherwise, just show the total volume
var/total_volume = 0
for(var/datum/reagent/R in reagents.reagent_list)
total_volume += R.volume
to_chat(user, "[total_volume] units of various reagents")
else
to_chat(user, "Nothing.")
if(reagents)
if(container_type & TRANSPARENT)
to_chat(user, "It contains:")
if(reagents.reagent_list.len)
if(user.can_see_reagents()) //Show each individual reagent
for(var/datum/reagent/R in reagents.reagent_list)
to_chat(user, "[R.volume] units of [R.name]")
else //Otherwise, just show the total volume
var/total_volume = 0
for(var/datum/reagent/R in reagents.reagent_list)
total_volume += R.volume
to_chat(user, "[total_volume] units of various reagents")
else
to_chat(user, "Nothing.")
else if(container_type & AMOUNT_VISIBLE)
if(reagents.total_volume)
to_chat(user, "<span class='notice'>It has [reagents.total_volume] unit\s left.</span>")
else
to_chat(user, "<span class='danger'>It's empty.</span>")
SendSignal(COMSIG_PARENT_EXAMINE, user)
/atom/proc/relaymove(mob/user)
+4 -3
View File
@@ -73,7 +73,7 @@
C.prefs.copy_to(M)
M.key = C.key
var/datum/mind/app_mind = M.mind
var/datum/antagonist/wizard/apprentice/app = new(app_mind)
app.master = user
app.school = kind
@@ -165,7 +165,7 @@
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(!creator_op)
return
switch(borg_to_spawn)
if("Medical")
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
@@ -187,7 +187,7 @@
R.real_name = R.name
R.key = C.key
var/datum/antagonist/nukeop/new_borg = new(R.mind)
new_borg.send_to_spawnpoint = FALSE
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
@@ -247,6 +247,7 @@
new_objective2.owner = S.mind
new_objective2.explanation_text = "[objective_verb] everyone[usr ? " else while you're at it":""]."
S.mind.objectives += new_objective2
S.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. \
Ctrl+Click a blood pool to manifest.</B>")
+34
View File
@@ -0,0 +1,34 @@
//A barebones antagonist team.
/datum/team
var/list/datum/mind/members = list()
var/name = "team"
var/member_name = "member"
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
/datum/team/New(starting_members)
. = ..()
if(starting_members)
if(islist(starting_members))
for(var/datum/mind/M in starting_members)
add_member(M)
else
add_member(starting_members)
/datum/team/proc/is_solo()
return members.len == 1
/datum/team/proc/add_member(datum/mind/new_member)
members |= new_member
/datum/team/proc/remove_member(datum/mind/member)
members -= member
//Display members/victory/failure/objectives for the team
/datum/team/proc/roundend_report()
var/list/report = list()
report += "<b>[name]:</b>"
report += "The [member_name]s were:"
report += printplayerlist(members)
return report.Join("<br>")
+6 -74
View File
@@ -1,44 +1,6 @@
/datum/objective_team/brother_team
name = "brotherhood"
member_name = "blood brother"
var/list/objectives = list()
var/meeting_area
/datum/objective_team/brother_team/is_solo()
return FALSE
/datum/objective_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/objective_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/objective_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)
/datum/game_mode
var/list/datum/mind/brothers = list()
var/list/datum/objective_team/brother_team/brother_teams = list()
var/list/datum/team/brother_team/brother_teams = list()
/datum/game_mode/traitor/bros
name = "traitor+brothers"
@@ -51,9 +13,10 @@
<span class='danger'>Blood Brothers</span>: Accomplish your objectives.\n\
<span class='notice'>Crew</span>: Do not let the traitors or brothers succeed!"
var/list/datum/objective_team/brother_team/pre_brother_teams = list()
var/list/datum/team/brother_team/pre_brother_teams = list()
var/const/team_amount = 2 //hard limit on brother teams if scaling is turned off
var/const/min_team_size = 2
traitors_required = FALSE //Only teams are possible
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
@@ -73,7 +36,7 @@
for(var/j = 1 to num_teams)
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
break
var/datum/objective_team/brother_team/team = new
var/datum/team/brother_team/team = new
var/team_size = prob(10) ? min(3, possible_brothers.len) : 2
for(var/k = 1 to team_size)
var/datum/mind/bro = pick(possible_brothers)
@@ -86,50 +49,19 @@
return ..()
/datum/game_mode/traitor/bros/post_setup()
for(var/datum/objective_team/brother_team/team in pre_brother_teams)
for(var/datum/team/brother_team/team in pre_brother_teams)
team.meeting_area = pick(meeting_areas)
meeting_areas -= team.meeting_area
team.forge_brother_objectives()
for(var/datum/mind/M in team.members)
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
team.update_name()
brother_teams += pre_brother_teams
return ..()
/datum/game_mode/traitor/bros/generate_report()
return "It's Syndicate recruiting season. Be alert for potential Syndicate infiltrators, but also watch out for disgruntled employees trying to defect. Unlike Nanotrasen, the Syndicate prides itself in teamwork and will only recruit pairs that share a brotherly trust."
/datum/game_mode/proc/auto_declare_completion_brother()
if(!LAZYLEN(brother_teams))
return
var/text = "<br><font size=4><b>The blood brothers were:</b></font>"
var/teamnumber = 1
for(var/datum/objective_team/brother_team/team in brother_teams)
if(!team.members.len)
continue
text += "<br><font size=3><b>Team #[teamnumber++]</b></font>"
for(var/datum/mind/M in team.members)
text += printplayer(M)
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in team.objectives)
if(objective.check_completion())
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
win = FALSE
objective_count++
if(win)
text += "<br><font color='green'><B>The blood brothers were successful!</B></font>"
SSblackbox.record_feedback("tally", "brother_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The blood brothers have failed!</B></font>"
SSblackbox.record_feedback("tally", "brother_success", 1, "FAIL")
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/update_brother_icons_added(datum/mind/brother_mind)
var/datum/atom_hud/antag/brotherhud = GLOB.huds[ANTAG_HUD_BROTHER]
brotherhud.join_hud(brother_mind.current)
@@ -94,47 +94,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \
as paranoia may spread and inhibit workplace efficiency."
/datum/game_mode/proc/auto_declare_completion_changeling()
var/list/changelings = get_antagonists(/datum/antagonist/changeling,TRUE) //Only real lings get a mention
if(changelings.len)
var/text = "<br><font size=3><b>The changelings were:</b></font>"
for(var/datum/mind/changeling in changelings)
var/datum/antagonist/changeling/ling = changeling.has_antag_datum(/datum/antagonist/changeling)
var/changelingwin = 1
if(!changeling.current)
changelingwin = 0
text += printplayer(changeling)
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
text += "<br><b>Changeling ID:</b> [ling.changelingID]."
text += "<br><b>Genomes Extracted:</b> [ling.absorbedcount]"
if(changeling.objectives.len)
var/count = 1
for(var/datum/objective/objective in changeling.objectives)
if(objective.check_completion())
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <font color='green'><b>Success!</b></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='danger'>Fail.</span> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
changelingwin = 0
count++
if(changelingwin)
text += "<br><font color='green'><b>The changeling was successful!</b></font>"
SSblackbox.record_feedback("tally", "changeling_success", 1, "SUCCESS")
else
text += "<br><span class='boldannounce'>The changeling has failed.</span>"
SSblackbox.record_feedback("tally", "changeling_success", 1, "FAIL")
text += "<br>"
to_chat(world, text)
return 1
/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof)
var/datum/dna/chosen_dna = chosen_prof.dna
user.real_name = chosen_prof.name
+15 -36
View File
@@ -65,13 +65,16 @@ Credit where due:
return TRUE
return FALSE
/proc/add_servant_of_ratvar(mob/L, silent = FALSE)
/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
if(!L || !L.mind)
return
var/update_type = ANTAG_DATUM_CLOCKCULT
if(silent)
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
. = L.mind.add_antag_datum(update_type)
var/datum/antagonist/clockcult/C = new update_type(L.mind)
C.make_team = create_team
C.show_in_roundend = create_team //tutorial scarabs begone
. = L.mind.add_antag_datum(C)
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
@@ -88,7 +91,6 @@ Credit where due:
///////////////
/datum/game_mode
var/datum/mind/eminence //The clockwork Eminence
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
@@ -111,6 +113,8 @@ Credit where due:
var/roundstart_player_count
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
var/datum/team/clockcult/main_clockcult
/datum/game_mode/clockwork_cult/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -185,22 +189,21 @@ Credit where due:
return FALSE
/datum/game_mode/clockwork_cult/check_finished()
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
if(GLOB.ark_of_the_clockwork_justiciar && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
return FALSE
. = ..()
return ..()
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
return main_clockcult.check_clockwork_victory()
/datum/game_mode/clock_cult/set_round_result()
..()
if(GLOB.clockwork_gateway_activated)
SSticker.news_report = CLOCK_SUMMON
return TRUE
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
SSticker.news_report = CULT_FAILURE
return FALSE
/datum/game_mode/clockwork_cult/declare_completion()
..()
return //Doesn't end until the round does
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
/datum/game_mode/clockwork_cult/generate_report()
return "Bluespace monitors near your sector have detected a continuous stream of patterned fluctuations since the station was completed. It is most probable that a powerful entity \
@@ -210,30 +213,6 @@ Credit where due:
working for this entity and utilizing highly-advanced technology to cross the great distance at will. If they should turn out to be a credible threat, the task falls on you and \
your crew to dispatch it in a timely manner."
/datum/game_mode/proc/auto_declare_completion_clockwork_cult()
var/text = ""
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
var/datum/game_mode/clockwork_cult/C = SSticker.mode
if(C.check_clockwork_victory())
text += "<span class='bold large_brass'>Ratvar's servants defended the Ark until its activation!</span>"
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
text += "<span class='userdanger'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
text += "<br><b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
text += "<br>Ratvar's servants had <b>[GLOB.clockwork_caches]</b> Tinkerer's Caches."
text += "<br><b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER)
text += "<br><b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
if(SSticker.mode.eminence)
text += "<br><b>The Eminence was:</b> [printplayer(SSticker.mode.eminence)]"
if(servants_of_ratvar.len)
text += "<br><b>Ratvar's servants were:</b>"
for(var/datum/mind/M in servants_of_ratvar - SSticker.mode.eminence)
text += printplayer(M)
to_chat(world, text)
/datum/game_mode/proc/update_servant_icons_added(datum/mind/M)
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
A.join_hud(M.current)
@@ -275,7 +275,6 @@
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
return
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
sleep(10)
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
@@ -355,5 +354,4 @@
if(sigil_active)
animation_number = initial(animation_number)
sigil_active = FALSE
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
@@ -91,7 +91,8 @@
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
if(infinite_resources)
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar //During rounds where they can't interact with the station, let them experiment with builds
//During rounds where they can't interact with the station, let them experiment with builds
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
if(infinite_resources) //Allow them to build stuff and recite scripture
@@ -18,16 +18,6 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/static/superheated_walls = 0
/mob/camera/eminence/Initialize()
if(SSticker.mode.eminence)
return INITIALIZE_HINT_QDEL
. = ..()
/mob/camera/eminence/Destroy(force)
if(!force && mind && SSticker.mode.eminence == mind)
return QDEL_HINT_LETMELIVE
return ..()
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
return TRUE
@@ -46,20 +36,20 @@
/mob/camera/eminence/Login()
..()
add_servant_of_ratvar(src, TRUE)
var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(C && C.clock_team)
if(C.clock_team.eminence)
remove_servant_of_ratvar(src,TRUE)
qdel(src)
return
else
C.clock_team.eminence = src
if(!C)
add_servant_of_ratvar(src, TRUE)
C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(C && C.clock_team)
if(C.clock_team.eminence)
remove_servant_of_ratvar(src,TRUE)
qdel(src)
else
C.clock_team.eminence = src
to_chat(src, "<span class='bold large_brass'>You have been selected as the Eminence!</span>")
to_chat(src, "<span class='brass'>As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.</span>")
to_chat(src, "<span class='brass'>Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.</span>")
to_chat(src, "<span class='brass'>Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.</span>")
SSticker.mode.eminence = mind
eminence_help()
for(var/V in actions)
var/datum/action/A = V
@@ -17,7 +17,11 @@
return
if(kingmaking)
return
if(SSticker.mode.eminence)
var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
if(!C || !C.clock_team)
return
if(C.clock_team.eminence)
to_chat(user, "<span class='warning'>There's already an Eminence!</span>")
return
if(!GLOB.servants_active)
+25 -183
View File
@@ -2,24 +2,23 @@
/datum/game_mode
var/list/datum/mind/cult = list()
var/list/cult_objectives = list()
var/eldergod = 1 //for the summon god objective
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CULT)
/proc/is_sacrifice_target(datum/mind/mind)
if(mind == GLOB.sac_mind)
return TRUE
/datum/team/cult/proc/is_sacrifice_target(datum/mind/mind)
for(var/datum/objective/sacrifice/sac_objective in objectives)
if(mind == sac_objective.target)
return TRUE
return FALSE
/proc/is_convertable_to_cult(mob/living/M)
/proc/is_convertable_to_cult(mob/living/M,datum/team/cult/specific_cult)
if(!istype(M))
return FALSE
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return FALSE
if(is_sacrifice_target(M.mind))
if(specific_cult && specific_cult.is_sacrifice_target(M.mind))
return FALSE
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
return FALSE
@@ -55,10 +54,10 @@
var/list/cultists_to_cult = list() //the cultists we'll convert
var/datum/team/cult/main_cult
/datum/game_mode/cult/pre_setup()
cult_objectives += "sacrifice"
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -86,82 +85,19 @@
/datum/game_mode/cult/post_setup()
if("sacrifice" in cult_objectives)
var/list/possible_targets = get_unconvertables()
if(!possible_targets.len)
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 in cultists_to_cult))
possible_targets += player.mind
if(possible_targets.len > 0)
GLOB.sac_mind = pick(possible_targets)
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!")
if(!GLOB.summon_spots.len)
while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
if((summon.z in GLOB.station_z_levels) && summon.valid_territory)
GLOB.summon_spots += summon
cult_objectives += "eldergod"
for(var/datum/mind/cult_mind in cultists_to_cult)
equip_cultist(cult_mind.current)
update_cult_icons_added(cult_mind)
to_chat(cult_mind.current, "<span class='userdanger'>You are a member of the cult!</span>")
cult_mind.current.playsound_local(get_turf(cult_mind.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
add_cultist(cult_mind, 0)
add_cultist(cult_mind, 0, equip=TRUE)
..()
/datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob,tome = 0)
if(!istype(mob))
return
if (mob.mind)
if (mob.mind.assigned_role == "Clown")
to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
mob.dna.remove_mutation(CLOWNMUT)
if(tome)
. += cult_give_item(/obj/item/tome, mob)
else
. += cult_give_item(/obj/item/paper/talisman/supply, mob)
to_chat(mob, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.</span>")
/datum/game_mode/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/game_mode/proc/add_cultist(datum/mind/cult_mind, stun) //BASE
/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun , equip = FALSE) //BASE
if (!istype(cult_mind))
return 0
if(cult_mind.add_antag_datum(ANTAG_DATUM_CULT))
var/datum/antagonist/cult/new_cultist = new(cult_mind)
new_cultist.give_equipment = equip
if(cult_mind.add_antag_datum(new_cultist))
if(stun)
cult_mind.current.Unconscious(100)
return 1
@@ -187,25 +123,19 @@
culthud.leave_hud(cult_mind.current)
set_antag_hud(cult_mind.current, null)
/datum/game_mode/cult/proc/get_unconvertables()
var/list/ucs = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !is_convertable_to_cult(player) && !(player.mind in cultists_to_cult))
ucs += player.mind
return ucs
/datum/game_mode/cult/proc/check_cult_victory()
var/cult_fail = 0
if(cult_objectives.Find("survive"))
cult_fail += check_survive() //the proc returns 1 if there are not enough cultists on the shuttle, 0 otherwise
if(cult_objectives.Find("eldergod"))
cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once
if(cult_objectives.Find("sacrifice"))
if(GLOB.sac_mind && !GLOB.sac_complete) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
cult_fail++
return cult_fail //if any objectives aren't met, failure
return main_cult.check_cult_victory()
/datum/game_mode/cult/set_round_result()
..()
if(check_cult_victory())
SSticker.mode_result = "win - cult win"
SSticker.news_report = CULT_SUMMON
else
SSticker.mode_result = "loss - staff stopped the cult"
SSticker.news_report = CULT_FAILURE
/datum/game_mode/cult/proc/check_survive()
var/acolytes_survived = 0
for(var/datum/mind/cult_mind in cult)
@@ -218,57 +148,6 @@
return 1
/datum/game_mode/cult/declare_completion()
if(!check_cult_victory())
SSticker.mode_result = "win - cult win"
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
else
SSticker.mode_result = "loss - staff stopped the cult"
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
var/text = ""
if(cult_objectives.len)
text += "<br><b>The cultists' objectives were:</b>"
for(var/obj_count=1, obj_count <= cult_objectives.len, obj_count++)
var/explanation
switch(cult_objectives[obj_count])
if("survive")
if(!check_survive())
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "SUCCESS"))
SSticker.news_report = CULT_ESCAPE
else
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "FAIL"))
SSticker.news_report = CULT_FAILURE
if("sacrifice")
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
else
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
if("eldergod")
if(!eldergod)
explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)].<span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
SSticker.news_report = CULT_SUMMON
else
explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)]<span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
SSticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
if(cult.len)
text += "<br><b>The cultists were:</b>"
for(var/datum/mind/M in cult)
text += printplayer(M)
to_chat(world, text)
..()
return 1
/datum/game_mode/cult/generate_report()
return "Some stations in your sector have reported evidence of blood sacrifice and strange magic. Ties to the Wizards' Federation have been proven not to exist, and many employees \
have disappeared; even Central Command employees light-years away have felt strange presences and at times hysterical compulsions. Interrogations point towards this being the work of \
@@ -276,41 +155,4 @@
devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will prevent conversion \
altogether."
/datum/game_mode/proc/datum_cult_completion()
var/text = ""
var/cult_fail = 0
cult_fail += eldergod
if(!GLOB.sac_complete)
cult_fail++
if(!cult_fail)
SSticker.mode_result = "win - cult win"
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
else
SSticker.mode_result = "loss - staff stopped the cult"
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
if(cult_objectives.len)
text += "<br><b>The cultists' objectives were:</b>"
for(var/obj_count in 1 to 2)
var/explanation
switch(cult_objectives[obj_count])
if("sacrifice")
if(GLOB.sac_mind)
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
else
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
if("eldergod")
if(!eldergod)
explanation = "Summon Nar-Sie. <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
SSticker.news_report = CULT_SUMMON
else
explanation = "Summon Nar-Sie. <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
SSticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
to_chat(world, text)
#undef CULT_SCALING_COEFFICIENT
+39 -31
View File
@@ -30,7 +30,7 @@
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
user.whisper(html_decode(message))
var/title = "Acolyte"
var/span = "cultitalic"
var/span = "cult italic"
if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
span = "cultlarge"
if(ishuman(user))
@@ -88,19 +88,21 @@
button_icon_state = "cultvote"
/datum/action/innate/cult/mastervote/IsAvailable()
if(GLOB.cult_vote_called || !ishuman(owner))
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
/datum/action/innate/cult/mastervote/Activate()
pollCultists(owner)
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
pollCultists(owner,C.cult_team)
/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
if(world.time < CULT_POLL_WAIT)
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
return
GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
@@ -108,39 +110,39 @@
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
sleep(100)
var/list/asked_cultists = list()
for(var/datum/mind/B in SSticker.mode.cult)
for(var/datum/mind/B in team.members)
if(B.current && B.current != Nominee && !B.current.incapacitated())
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
asked_cultists += B.current
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
if(QDELETED(Nominee) || Nominee.incapacitated())
GLOB.cult_vote_called = FALSE
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!</span>")
return FALSE
if(!Nominee.mind)
GLOB.cult_vote_called = FALSE
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone catatonic in the process of attempting to win the cult's support!</span>")
return FALSE
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
GLOB.cult_vote_called = FALSE
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.</span>")
return FALSE
GLOB.cult_mastered = TRUE
team.cult_mastered = TRUE
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
for(var/datum/mind/B in SSticker.mode.cult)
for(var/datum/mind/B in team.members)
if(B.current)
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
vote.Remove(B.current)
@@ -159,6 +161,9 @@
button_icon_state = "sintouch"
/datum/action/innate/cult/master/finalreck/Activate()
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -169,7 +174,7 @@
to_chat(owner, "<span class='warning'>You need more space to summon the cult!</span>")
return
if(do_after(owner, 30, target = owner))
for(var/datum/mind/B in SSticker.mode.cult)
for(var/datum/mind/B in antag.cult_team.members)
if(B.current && B.current.stat != DEAD)
var/turf/mobloc = get_turf(B.current)
switch(i)
@@ -194,7 +199,7 @@
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
else
return
GLOB.reckoning_complete = TRUE
antag.cult_team.reckoning_complete = TRUE
Remove(owner)
/mob/proc/reckon(turf/final)
@@ -269,34 +274,37 @@
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(target in view(7, get_turf(ranged_ability_user)))
GLOB.blood_target = target
C.cult_team.blood_target = target
var/area/A = get_area(target)
attached_action.cooldown = world.time + attached_action.base_cooldown
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
GLOB.blood_target_image.appearance_flags = RESET_COLOR
GLOB.blood_target_image.pixel_x = -target.pixel_x
GLOB.blood_target_image.pixel_y = -target.pixel_y
C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
C.cult_team.blood_target_image.pixel_x = -target.pixel_x
C.cult_team.blood_target_image.pixel_y = -target.pixel_y
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD && B.current.client)
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
B.current.client.images += GLOB.blood_target_image
B.current.client.images += C.cult_team.blood_target_image
attached_action.owner.update_action_buttons_icon()
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
GLOB.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_STOPPABLE)
C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), 900, TIMER_STOPPABLE)
return TRUE
return FALSE
/proc/reset_blood_target()
for(var/datum/mind/B in SSticker.mode.cult)
/proc/reset_blood_target(datum/team/cult/team)
for(var/datum/mind/B in team.members)
if(B.current && B.current.stat != DEAD && B.current.client)
if(GLOB.blood_target)
if(team.blood_target)
to_chat(B.current,"<span class='cultlarge'><b>The blood mark has expired!</b></span>")
B.current.client.images -= GLOB.blood_target_image
QDEL_NULL(GLOB.blood_target_image)
GLOB.blood_target = null
B.current.client.images -= team.blood_target_image
QDEL_NULL(team.blood_target_image)
team.blood_target = null
+16 -7
View File
@@ -179,6 +179,13 @@ This file contains the arcane tome files.
var/list/shields = list()
var/area/A = get_area(src)
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag)
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
if(!check_rune_turf(Turf, user))
return
entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in GLOB.rune_types
@@ -196,18 +203,20 @@ This file contains the arcane tome files.
A = get_area(src)
if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user))
return
//AAAAAAAAAAAAAAAH, i'm rewriting enough for now so TODO: remove this shit
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
if(!("eldergod" in SSticker.mode.cult_objectives))
if(!summon_objective)
to_chat(user, "<span class='warning'>Nar-Sie does not wish to be summoned!</span>")
return
if(!GLOB.sac_complete)
if(sac_objective && !sac_objective.check_completion())
to_chat(user, "<span class='warning'>The sacrifice is not complete. The portal would lack the power to open if you tried!</span>")
return
if(!SSticker.mode.eldergod)
if(summon_objective.check_completion())
to_chat(user, "<span class='cultlarge'>\"I am already here. There is no need to try to summon me now.\"</span>")
return
if(!(A in GLOB.summon_spots))
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!</span>")
if(!(A in summon_objective.summon_spots))
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
@@ -215,8 +224,8 @@ This file contains the arcane tome files.
return
Turf = get_turf(user)
A = get_area(src)
if(!(A in GLOB.summon_spots)) // Check again to make sure they didn't move
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!</span>")
if(!(A in summon_objective.summon_spots)) // Check again to make sure they didn't move
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/ai/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
+32 -30
View File
@@ -349,7 +349,11 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
var/is_convertable = is_convertable_to_cult(L)
var/mob/living/F = invokers[1]
var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/is_convertable = is_convertable_to_cult(L,C.cult_team)
if(L.stat != DEAD && (is_clock || is_convertable))
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
@@ -397,17 +401,27 @@ structure_check() searches for nearby cultist structures required for the invoca
return 1
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
var/mob/living/first_invoker = invokers[1]
if(!first_invoker)
return FALSE
var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C)
return
var/big_sac = FALSE
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "<span class='cultitalic'>[sacrificial] is too greatly linked to the world! You need three acolytes!</span>")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
return FALSE
if(sacrificial.mind)
GLOB.sacrificed += sacrificial.mind
if(is_sacrifice_target(sacrificial.mind))
GLOB.sac_complete = TRUE
big_sac = TRUE
for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
if(sac_objective.target == sacrificial.mind)
sac_objective.sacced = TRUE
sac_objective.update_explanation_text()
big_sac = TRUE
else
GLOB.sacrificed += sacrificial
@@ -481,7 +495,6 @@ structure_check() searches for nearby cultist structures required for the invoca
sleep(40)
if(src)
color = RUNE_COLOR_RED
SSticker.mode.eldergod = FALSE
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
@@ -497,10 +510,10 @@ structure_check() searches for nearby cultist structures required for the invoca
message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod")
..()
//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out.
//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people GLOB.sacrificed
/obj/effect/rune/raise_dead
cultist_name = "Revive Cultist"
cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life."
cultist_name = "Resurrect Cultist"
cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
@@ -521,11 +534,16 @@ structure_check() searches for nearby cultist structures required for the invoca
return
rune_in_use = TRUE
for(var/mob/living/M in T.contents)
if(iscultist(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
if(iscultist(M) && M.stat == DEAD)
potential_revive_mobs |= M
if(!potential_revive_mobs.len)
to_chat(user, "<span class='cultitalic'>There are no dead cultists on the rune!</span>")
log_game("Raise Dead rune failed - no cultists to revive")
log_game("Raise Dead rune failed - no corpses to revive")
fail_invoke()
rune_in_use = FALSE
return
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
to_chat(user, "<span class='warning'>You have sacrificed too few people to revive a cultist!</span>")
fail_invoke()
rune_in_use = FALSE
return
@@ -541,25 +559,9 @@ structure_check() searches for nearby cultist structures required for the invoca
else
invocation = initial(invocation)
..()
if(mob_to_revive.stat == DEAD)
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
to_chat(user, "<span class='warning'>Your cult must carry out another sacrifice before it can revive a cultist!</span>")
fail_invoke()
rune_in_use = FALSE
return
revives_used++
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
mob_to_revive.grab_ghost()
else if(!mob_to_revive.client || mob_to_revive.client.is_afk())
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", "[name]", null, "Blood Cultist", 50, mob_to_revive)
var/mob/dead/observer/theghost = null
if(candidates.len)
theghost = pick(candidates)
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
mob_to_revive.ghostize(0)
mob_to_revive.key = theghost.key
revives_used++
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
mob_to_revive.grab_ghost()
to_chat(mob_to_revive, "<span class='cultlarge'>\"PASNAR SAVRAE YAM'TOTH. Arise.\"</span>")
mob_to_revive.visible_message("<span class='warning'>[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes.</span>", \
"<span class='cultlarge'>You awaken suddenly from the void. You're alive!</span>")
-38
View File
@@ -3,32 +3,6 @@
var/list/datum/mind/devils = list()
var/devil_ascended = 0 // Number of arch devils on station
/datum/game_mode/proc/auto_declare_completion_sintouched()
var/text = ""
if(sintouched.len)
text += "<br><span class='big'><b>The sintouched were:</b></span>"
var/list/sintouchedUnique = uniqueList(sintouched)
for(var/S in sintouchedUnique)
var/datum/mind/sintouched_mind = S
text += printplayer(sintouched_mind)
text += printobjectives(sintouched_mind)
text += "<br>"
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/auto_declare_completion_devils()
/var/text = ""
if(devils.len)
text += "<br><span class='big'><b>The devils were:</b></span>"
for(var/D in devils)
var/datum/mind/devil = D
text += printplayer(devil)
text += printdevilinfo(devil.current)
text += printobjectives(devil)
text += "<br>"
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
for(var/i = 1 to quantity)
@@ -41,18 +15,6 @@
else
objective.find_target()
/datum/game_mode/proc/printdevilinfo(mob/living/ply)
var/datum/antagonist/devil/devilinfo = is_devil(ply)
if(!devilinfo)
return "Target is not a devil."
var/text = "</br>The devil's true name is: [devilinfo.truename]</br>"
text += "The devil's bans were:</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.ban]]</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.bane]]</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.banish]]</br></br>"
return text
/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL]
hud.join_hud(devil_mind.current)
+14 -80
View File
@@ -74,7 +74,6 @@
/datum/game_mode/proc/pre_setup()
return 1
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
@@ -242,55 +241,9 @@
return 0
/datum/game_mode/proc/declare_completion()
var/clients = 0
var/surviving_humans = 0
var/surviving_total = 0
var/ghosts = 0
var/escaped_humans = 0
var/escaped_total = 0
for(var/mob/M in GLOB.player_list)
if(M.client)
clients++
if(ishuman(M))
if(!M.stat)
surviving_humans++
if(M.z == ZLEVEL_CENTCOM)
escaped_humans++
if(!M.stat)
surviving_total++
if(M.z == ZLEVEL_CENTCOM)
escaped_total++
if(isobserver(M))
ghosts++
if(clients)
SSblackbox.record_feedback("nested tally", "round_end_stats", clients, list("clients"))
if(ghosts)
SSblackbox.record_feedback("nested tally", "round_end_stats", ghosts, list("ghosts"))
if(surviving_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_humans, list("survivors", "human"))
if(surviving_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_total, list("survivors", "total"))
if(escaped_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_humans, list("escapees", "human"))
if(escaped_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_total, list("escapees", "total"))
send2irc("Server", "Round just ended.")
if(cult.len && !istype(SSticker.mode, /datum/game_mode/cult))
datum_cult_completion()
return 0
/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
return 0
/datum/game_mode/proc/send_intercept()
var/intercepttext = "<b><i>Central Command Status Summary</i></b><hr>"
intercepttext += "<b>Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
@@ -452,34 +405,6 @@
for (var/C in GLOB.admins)
to_chat(C, msg)
/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
var/text = "<br><b>[ply.key]</b> was <b>[ply.name]</b> the <b>[ply.assigned_role]</b> and"
if(ply.current)
if(ply.current.stat == DEAD)
text += " <span class='boldannounce'>died</span>"
else
text += " <span class='greenannounce'>survived</span>"
if(fleecheck)
var/turf/T = get_turf(ply.current)
if(!T || !(T.z in GLOB.station_z_levels))
text += " while <span class='boldannounce'>fleeing the station</span>"
if(ply.current.real_name != ply.name)
text += " as <b>[ply.current.real_name]</b>"
else
text += " <span class='boldannounce'>had their body destroyed</span>"
return text
/datum/game_mode/proc/printobjectives(datum/mind/ply)
var/text = ""
var/count = 1
for(var/datum/objective/objective in ply.objectives)
if(objective.check_completion())
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='greenannounce'>Success!</span>"
else
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='boldannounce'>Fail.</span>"
count++
return text
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/game_mode/proc/age_check(client/C)
if(get_remaining_days(C) == 0)
@@ -519,11 +444,6 @@
station_goals += new picked
/datum/game_mode/proc/declare_station_goal_completion()
for(var/V in station_goals)
var/datum/station_goal/G = V
G.print_result()
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
return "Gamemode report for [name] not set. Contact a coder."
@@ -532,3 +452,17 @@
nuke_off_station = off_station
if(off_station < 2)
station_was_nuked = TRUE //Will end the round on next check.
//Additional report section in roundend report
/datum/game_mode/proc/special_report()
return
//Set result and news report here
/datum/game_mode/proc/set_round_result()
SSticker.mode_result = "undefined"
if(station_was_nuked)
SSticker.news_report = STATION_DESTROYED_NUKE
if(EMERGENCY_ESCAPED_OR_ENDGAMED)
SSticker.news_report = STATION_EVACUATED
if(SSshuttle.emergency.is_hijacked())
SSticker.news_report = SHUTTLE_HIJACK
+9 -10
View File
@@ -30,30 +30,29 @@
spawn_meteors(ramp_up_final, wavetype)
/datum/game_mode/meteor/declare_completion()
var/text
/datum/game_mode/meteor/special_report()
var/survivors = 0
var/list/survivor_list = list()
for(var/mob/living/player in GLOB.player_list)
if(player.stat != DEAD)
++survivors
if(player.onCentCom())
text += "<br><b><font size=2>[player.real_name] escaped to the safety of CentCom.</font></b>"
survivor_list += "<span class='greentext'>[player.real_name] escaped to the safety of CentCom.</span>"
else if(player.onSyndieBase())
text += "<br><b><font size=2>[player.real_name] escaped to the (relative) safety of Syndicate Space.</font></b>"
survivor_list += "<span class='greentext'>[player.real_name] escaped to the (relative) safety of Syndicate Space.</span>"
else
text += "<br><font size=1>[player.real_name] survived but is stranded without any hope of rescue.</font>"
survivor_list += "<span class='neutraltext'>[player.real_name] survived but is stranded without any hope of rescue.</span>"
if(survivors)
to_chat(world, "<span class='boldnotice'>The following survived the meteor storm</span>:[text]")
return "<span class='header'>The following survived the meteor storm:</span><br>[survivor_list.Join("<br>")]"
else
to_chat(world, "<span class='boldnotice'>Nobody survived the meteor storm!</span>")
return "<span class='redtext big'>Nobody survived the meteor storm!</span>"
SSticker.mode_result = "end - evacuation"
/datum/game_mode/meteor/set_round_result()
..()
return 1
SSticker.mode_result = "end - evacuation"
/datum/game_mode/meteor/generate_report()
return "[pick("Asteroids have", "Meteors have", "Large rocks have", "Stellar minerals have", "Space hail has", "Debris has")] been detected near your station, and a collision is possible, \
@@ -1,19 +1,5 @@
/datum/objective_team/abductor_team
member_name = "abductor"
var/list/objectives = list()
var/team_number
/datum/objective_team/abductor_team/is_solo()
return FALSE
/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
O.team = src
O.update_explanation_text()
objectives += O
/datum/game_mode
var/list/datum/mind/abductors = list()
var/list/datum/mind/abductees = list()
/datum/game_mode/abduction
name = "abduction"
@@ -24,7 +10,7 @@
required_players = 15
maximum_players = 50
var/max_teams = 4
var/list/datum/objective_team/abductor_team/abductor_teams = list()
var/list/datum/team/abductor_team/abductor_teams = list()
var/finished = FALSE
var/static/team_count = 0
@@ -51,7 +37,7 @@
if(team_number > max_teams)
return //or should it try to stuff them in anway ?
var/datum/objective_team/abductor_team/team = new
var/datum/team/abductor_team/team = new
team.team_number = team_number
team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
team.add_objective(new/datum/objective/experiment)
@@ -64,6 +50,7 @@
antag_candidates -= scientist
team.members |= scientist
scientist.assigned_role = "Abductor Scientist"
scientist.special_role = "Abductor Scientist"
log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
if(!agent)
@@ -71,18 +58,19 @@
antag_candidates -= agent
team.members |= agent
agent.assigned_role = "Abductor Agent"
agent.special_role = "Abductor Agent"
log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
abductor_teams += team
return team
/datum/game_mode/abduction/post_setup()
for(var/datum/objective_team/abductor_team/team in abductor_teams)
for(var/datum/team/abductor_team/team in abductor_teams)
post_setup_team(team)
return ..()
//Used for create antag buttons
/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
/datum/game_mode/abduction/proc/post_setup_team(datum/team/abductor_team/team)
for(var/datum/mind/M in team.members)
if(M.assigned_role == "Abductor Scientist")
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
@@ -91,7 +79,7 @@
/datum/game_mode/abduction/check_finished()
if(!finished)
for(var/datum/objective_team/abductor_team/team in abductor_teams)
for(var/datum/team/abductor_team/team in abductor_teams)
for(var/datum/objective/O in team.objectives)
if(O.check_completion())
SSshuttle.emergency.request(null, set_coefficient = 0.5)
@@ -99,35 +87,6 @@
return ..()
return ..()
/datum/game_mode/abduction/declare_completion()
for(var/datum/objective_team/abductor_team/team in abductor_teams)
var/won = TRUE
for(var/datum/objective/O in team.objectives)
if(!O.check_completion())
won = FALSE
if(won)
to_chat(world, "<span class='greenannounce'>[team.name] team fulfilled its mission!</span>")
else
to_chat(world, "<span class='boldannounce'>[team.name] team failed its mission.</span>")
..()
return TRUE
/datum/game_mode/proc/auto_declare_completion_abduction()
var/text = ""
if(abductors.len)
text += "<br><span class='big'><b>The abductors were:</b></span>"
for(var/datum/mind/abductor_mind in abductors)
text += printplayer(abductor_mind)
text += printobjectives(abductor_mind)
text += "<br>"
if(abductees.len)
text += "<br><span class='big'><b>The abductees were:</b></span>"
for(var/datum/mind/abductee_mind in abductees)
text += printplayer(abductee_mind)
text += printobjectives(abductee_mind)
text += "<br>"
to_chat(world, text)
// LANDMARKS
/obj/effect/landmark/abductor
var/team_number = 1
@@ -144,9 +103,9 @@
/datum/objective/experiment/check_completion()
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
if(!istype(team, /datum/objective_team/abductor_team))
if(!istype(team, /datum/team/abductor_team))
return FALSE
var/datum/objective_team/abductor_team/T = team
var/datum/team/abductor_team/T = team
if(E.team_number == T.team_number)
return E.points >= target_amount
return FALSE
@@ -151,13 +151,18 @@
var/mob/living/mob_occupant = occupant
if(mob_occupant.stat != DEAD)
if(href_list["experiment"])
flash = Experiment(occupant,href_list["experiment"])
flash = Experiment(occupant,href_list["experiment"],usr)
updateUsrDialog()
add_fingerprint(usr)
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type)
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
LAZYINITLIST(history)
var/mob/living/carbon/human/H = occupant
var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
if(!user_abductor)
return "<span class='bad'>Authorization failure. Contact mothership immidiately.</span>"
var/point_reward = 0
if(H in history)
return "<span class='bad'>Specimen already in database.</span>"
@@ -182,15 +187,8 @@
if(3)
to_chat(H, "<span class='warning'>You feel intensely watched.</span>")
sleep(5)
to_chat(H, "<span class='warning'><b>Your mind snaps!</b></span>")
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
to_chat(H, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
var/datum/objective/abductee/O = new objtype()
SSticker.mode.abductees += H.mind
H.mind.objectives += O
H.mind.announce_objectives()
SSticker.mode.update_abductor_icons_added(H.mind)
user_abductor.team.abductees += H.mind
H.mind.add_antag_datum(/datum/antagonist/abductee)
for(var/obj/item/organ/heart/gland/G in H.internal_organs)
G.Start()
@@ -105,13 +105,18 @@
monkey_mind.special_role = null
/datum/game_mode/monkey/declare_completion()
/datum/game_mode/monkey/set_round_result()
..()
if(check_monkey_victory())
SSticker.mode_result = "win - monkey win"
to_chat(world, "<span class='userdanger'>The monkeys have overthrown their captors! Eeek eeeek!!</span>")
else
SSticker.mode_result = "loss - staff stopped the monkeys"
to_chat(world, "<span class='userdanger'>The staff managed to contain the monkey infestation!</span>")
/datum/game_mode/monkey/special_report()
if(check_monkey_victory())
return "<span class='redtext big'>The monkeys have overthrown their captors! Eeek eeeek!!</span>"
else
return "<span class='redtext big'>The staff managed to contain the monkey infestation!</span>"
/datum/game_mode/monkey/generate_report()
return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom."
@@ -227,6 +227,7 @@
player_mind.assigned_role = "Morph"
player_mind.special_role = "Morph"
SSticker.mode.traitors |= player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
SEND_SOUND(S, sound('sound/magic/mutate.ogg'))
message_admins("[key_name_admin(S)] has been made into a morph by an event.")
@@ -87,6 +87,7 @@
mind.assigned_role = "revenant"
mind.special_role = "Revenant"
SSticker.mode.traitors |= mind //Necessary for announcing
mind.add_antag_datum(/datum/antagonist/auto_custom)
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
@@ -38,6 +38,7 @@
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = "Slaughter Demon"
SSticker.mode.traitors |= player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.</B>")
SEND_SOUND(S, 'sound/magic/demon_dies.ogg')
+7 -14
View File
@@ -17,7 +17,7 @@
var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer!
var/list/pre_nukeops = list()
var/datum/objective_team/nuclear/nuke_team
var/datum/team/nuclear/nuke_team
/datum/game_mode/nuclear/pre_setup()
var/n_agents = min(round(num_players() / 10), antag_candidates.len, agents_possible)
@@ -69,7 +69,8 @@
return FALSE //its a static var btw
..()
/datum/game_mode/nuclear/declare_completion()
/datum/game_mode/nuclear/set_round_result()
..()
var result = nuke_team.get_result()
switch(result)
if(NUKE_RESULT_FLUKE)
@@ -102,22 +103,12 @@
else
SSticker.mode_result = "halfwin - interrupted"
SSticker.news_report = OPERATIVE_SKIRMISH
return ..()
/datum/game_mode/nuclear/generate_report()
return "One of Central Command's trading routes was recently disrupted by a raid carried out by the Gorlex Marauders. They seemed to only be after one ship - a highly-sensitive \
transport containing a nuclear fission explosive, although it is useless without the proper code and authorization disk. While the code was likely found in minutes, the only disk that \
can activate this explosive is on your station. Ensure that it is protected at all times, and remain alert for possible intruders."
/datum/game_mode/proc/auto_declare_completion_nuclear()
var/list/nuke_teams = list()
for(var/datum/antagonist/nukeop/N in GLOB.antagonists) //collect all nuke teams
nuke_teams |= N.nuke_team
for(var/datum/objective_team/nuclear/nuke_team in nuke_teams)
nuke_team.roundend_display()
return TRUE
/proc/is_nuclear_operative(mob/M)
return M && istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/nukeop)
@@ -132,7 +123,8 @@
l_pocket = /obj/item/pinpointer/nuke/syndicate
id = /obj/item/card/id/syndicate
belt = /obj/item/gun/ballistic/automatic/pistol
backpack_contents = list(/obj/item/storage/box/syndie=1)
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/kitchen/knife/combat/survival)
var/tc = 25
var/command_radio = FALSE
@@ -177,4 +169,5 @@
r_hand = /obj/item/gun/ballistic/automatic/shotgun/bulldog
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/tank/jetpack/oxygen/harness=1,\
/obj/item/gun/ballistic/automatic/pistol=1)
/obj/item/gun/ballistic/automatic/pistol=1,\
/obj/item/kitchen/knife/combat/survival)
+12 -2
View File
@@ -3,6 +3,7 @@
var/list/datum/mind/members = list()
var/name = "team"
var/member_name = "member"
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
/datum/objective_team/New(starting_members)
. = ..()
@@ -12,7 +13,6 @@
add_member(M)
else
add_member(starting_members)
members += starting_members
/datum/objective_team/proc/is_solo()
return members.len == 1
@@ -21,4 +21,14 @@
members |= new_member
/datum/objective_team/proc/remove_member(datum/mind/member)
members -= member
members -= member
//Display members/victory/failure/objectives for the team
/datum/objective_team/proc/roundend_report()
var/list/report = list()
report += "<b>[name]:</b>"
report += "The [member_name]s were:"
report += printplayerlist(members)
return report.Join("<br>")
+10 -50
View File
@@ -26,7 +26,7 @@
var/finished = 0
var/check_counter = 0
var/max_headrevs = 3
var/datum/objective_team/revolution/revolution
var/datum/team/revolution/revolution
var/list/datum/mind/headrev_candidates = list()
///////////////////////////
@@ -169,62 +169,22 @@
return FALSE
return TRUE
//////////////////////////////////////////////////////////////////////
//Announces the end of the game with all relavent information stated//
//////////////////////////////////////////////////////////////////////
/datum/game_mode/revolution/declare_completion()
/datum/game_mode/revolution/set_round_result()
..()
if(finished == 1)
SSticker.mode_result = "win - heads killed"
to_chat(world, "<span class='redtext'>The heads of staff were killed or exiled! The revolutionaries win!</span>")
SSticker.news_report = REVS_WIN
else if(finished == 2)
SSticker.mode_result = "loss - rev heads killed"
to_chat(world, "<span class='redtext'>The heads of staff managed to stop the revolution!</span>")
SSticker.news_report = REVS_LOSE
..()
return TRUE
/datum/game_mode/proc/auto_declare_completion_revolution()
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/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)
to_chat(world, "[GLOB.TAB]Command's Approval Rating: <B>[100 - round((num_revs/num_survivors)*100, 0.1)]%</B>" )
var/text = "<br><font size=3><b>The head revolutionaries were:</b></font>"
for(var/datum/mind/headrev in headrevs)
text += printplayer(headrev, 1)
text += "<br>"
to_chat(world, text)
if(revs.len)
var/text = "<br><font size=3><b>The revolutionaries were:</b></font>"
for(var/datum/mind/rev in revs)
text += printplayer(rev, 1)
text += "<br>"
to_chat(world, text)
if(revs.len || headrevs.len)
var/text = "<br><font size=3><b>The heads of staff were:</b></font>"
var/list/heads = SSjob.get_all_heads()
for(var/datum/mind/head in heads)
var/target = (head in targets)
if(target)
text += "<span class='boldannounce'>Target</span>"
text += printplayer(head, 1)
text += "<br>"
to_chat(world, text)
//TODO What should be displayed for revs in non-rev rounds
/datum/game_mode/revolution/special_report()
if(finished == 1)
return "<span class='redtext big'>The heads of staff were killed or exiled! The revolutionaries win!</span>"
else if(finished == 2)
return "<span class='redtext big'>The heads of staff managed to stop the revolution!</span>"
/datum/game_mode/revolution/generate_report()
return "Employee unrest has spiked in recent weeks, with several attempted mutinies on heads of staff. Some crew have been observed using flashbulb devices to blind their colleagues, \
+2 -71
View File
@@ -27,6 +27,7 @@
var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
var/antag_datum = ANTAG_DATUM_TRAITOR //what type of antag to create
var/traitors_required = TRUE //Will allow no traitors
/datum/game_mode/traitor/pre_setup()
@@ -55,7 +56,7 @@
log_game("[traitor.key] (ckey) has been selected as a [traitor_name]")
antag_candidates.Remove(traitor)
return pre_traitors.len > 0
return !traitors_required || pre_traitors.len > 0
/datum/game_mode/traitor/post_setup()
@@ -85,80 +86,10 @@
new_antag.should_specialise = TRUE
character.add_antag_datum(new_antag)
/datum/game_mode/traitor/declare_completion()
..()
return//Traitors will be checked as part of check_extra_completion. Leaving this here as a reminder.
/datum/game_mode/proc/auto_declare_completion_traitor()
if(traitors.len)
var/text = "<br><font size=3><b>The [traitor_name]s were:</b></font>"
for(var/datum/mind/traitor in traitors)
var/traitorwin = TRUE
text += printplayer(traitor)
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 == traitor.key)
TC_uses += H.spent_telecrystals
uplink_true = TRUE
purchases += H.purchase_log.generate_render(FALSE)
var/objectives = ""
if(traitor.objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in traitor.objectives)
if(objective.check_completion())
objectives += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
else
objectives += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
traitorwin = FALSE
count++
if(uplink_true)
text += " (used [TC_uses] TC) [purchases]"
if(TC_uses==0 && traitorwin)
var/static/icon/badass = icon('icons/badass.dmi', "badass")
text += "<BIG>[icon2html(badass, world)]</BIG>"
text += objectives
var/special_role_text
if(traitor.special_role)
special_role_text = lowertext(traitor.special_role)
else
special_role_text = "antagonist"
if(traitorwin)
text += "<br><font color='green'><B>The [special_role_text] was successful!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "FAIL")
SEND_SOUND(traitor.current, 'sound/ambience/ambifailure.ogg')
text += "<br>"
text += "<br><b>The code phrases were:</b> <font color='red'>[GLOB.syndicate_code_phrase]</font><br>\
<b>The code responses were:</b> <font color='red'>[GLOB.syndicate_code_response]</font><br>"
to_chat(world, text)
return TRUE
/datum/game_mode/traitor/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind)
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
traitorhud.join_hud(traitor_mind.current)
+2 -2
View File
@@ -64,7 +64,6 @@
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your bretheren's soul.\"</span>")
return
add_logs(user, M, "captured [M.name]'s soul", src)
transfer_soul("VICTIM", M, user)
///////////////////Options for using captured souls///////////////////////////////////////
@@ -142,7 +141,8 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
if(is_sacrifice_target(T.mind))
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(C && C.cult_team.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
else
+5 -54
View File
@@ -58,65 +58,16 @@
return TRUE
/datum/game_mode/wizard/declare_completion()
/datum/game_mode/wizard/set_round_result()
..()
if(finished)
SSticker.mode_result = "loss - wizard killed"
to_chat(world, "<span class='userdanger'>The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!</span>")
SSticker.news_report = WIZARD_KILLED
..()
return 1
/datum/game_mode/wizard/special_report()
if(finished)
return "<span class='redtext big'>The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!</span>"
/datum/game_mode/proc/auto_declare_completion_wizard()
if(wizards.len)
var/text = "<br><font size=3><b>the wizards/witches were:</b></font>"
for(var/datum/mind/wizard in wizards)
text += "<br><b>[wizard.key]</b> was <b>[wizard.name]</b> ("
if(wizard.current)
if(wizard.current.stat == DEAD)
text += "died"
else
text += "survived"
if(wizard.current.real_name != wizard.name)
text += " as <b>[wizard.current.real_name]</b>"
else
text += "body destroyed"
text += ")"
var/count = 1
var/wizardwin = 1
for(var/datum/objective/objective in wizard.objectives)
if(objective.check_completion())
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
wizardwin = 0
count++
if(wizard.current && wizardwin)
text += "<br><font color='green'><B>The wizard was successful!</B></font>"
SSblackbox.record_feedback("tally", "wizard_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The wizard has failed!</B></font>"
SSblackbox.record_feedback("tally", "wizard_success", 1, "FAIL")
if(wizard.spell_list.len>0)
text += "<br><B>[wizard.name] used the following spells: </B>"
var/i = 1
for(var/obj/effect/proc_holder/spell/S in wizard.spell_list)
text += "[S.name]"
if(wizard.spell_list.len > i)
text += ", "
i++
text += "<br>"
to_chat(world, text)
return 1
//returns whether the mob is a wizard (or apprentice)
/proc/iswizard(mob/living/M)
return M.mind && M.mind.has_antag_datum(/datum/antagonist/wizard,TRUE)
+1 -1
View File
@@ -10,7 +10,7 @@
icon = 'icons/obj/machines/limbgrower.dmi'
icon_state = "limbgrower_idleoff"
density = TRUE
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
+1
View File
@@ -45,6 +45,7 @@
var/datum/objective/hijack/hijack = new
hijack.owner = user.mind
user.mind.objectives += hijack
user.mind.add_antag_datum(/datum/antagonist/auto_custom)
user.mind.announce_objectives()
+2 -2
View File
@@ -571,9 +571,9 @@
if(bumpsmash && occupant) //Need a pilot to push the PUNCH button.
if(nextsmash < world.time)
obstacle.mech_melee_attack(src)
if(!obstacle || !obstacle.density)
step(src,dir)
nextsmash = world.time + smashcooldown
if(!obstacle || obstacle.CanPass(src,get_step(src,dir)))
step(src,dir)
if(isobj(obstacle))
var/obj/O = obstacle
if(!O.anchored)
@@ -47,10 +47,8 @@
return
else
var/hotness = W.is_hot()
var/added_heat = (hotness / 100)
src.reagents.chem_temp = min(src.reagents.chem_temp + added_heat, hotness)
src.reagents.handle_reactions()
to_chat(user, "<span class='notice'>You heat [src] with [W]!</span>")
reagents.expose_temperature(hotness)
to_chat(user, "<span class='notice'>You heat [name] with [W]!</span>")
else
return ..()
@@ -62,8 +60,7 @@
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
if(reagents)
reagents.chem_temp += 30
reagents.handle_reactions()
reagents.expose_temperature(exposed_temperature)
..()
+2 -2
View File
@@ -102,7 +102,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = "cigoff"
throw_speed = 0.5
item_state = "cigoff"
container_type = INJECTABLE_1
container_type = INJECTABLE
w_class = WEIGHT_CLASS_TINY
body_parts_covered = null
grind_results = list()
@@ -660,7 +660,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
item_state = "[param_color]_vape"
/obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/reagent_containers) && (O.container_type & OPENCONTAINER_1))
if(O.is_drainable())
if(reagents.total_volume < chem_volume)
if(O.reagents.total_volume > 0)
O.reagents.trans_to(src,25)
+3 -4
View File
@@ -16,6 +16,7 @@
attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
dog_fashion = /datum/dog_fashion/back
resistance_flags = FIRE_PROOF
container_type = AMOUNT_VISIBLE
var/max_water = 50
var/last_use = 1
var/safety = TRUE
@@ -48,7 +49,6 @@
/obj/item/extinguisher/attack_self(mob/user)
safety = !safety
src.icon_state = "[sprite_name][!safety]"
src.desc = "The safety is [safety ? "on" : "off"]."
to_chat(user, "The safety is [safety ? "on" : "off"].")
return
@@ -67,11 +67,10 @@
/obj/item/extinguisher/examine(mob/user)
..()
to_chat(user, "The safety is [safety ? "on" : "off"].")
if(reagents.total_volume)
to_chat(user, "It contains [round(reagents.total_volume)] unit\s.")
to_chat(user, "<span class='notice'>Alt-click to empty it.</span>")
else
to_chat(user, "It is empty.")
/obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user)
if(istype(target, /obj/structure/reagent_dispensers/watertank) && target.Adjacent(user))
+28 -6
View File
@@ -7,6 +7,9 @@
/*
* Gifts
*/
GLOBAL_LIST_EMPTY(possible_gifts)
/obj/item/a_gift
name = "gift"
desc = "PRESENTS!!!! eek!"
@@ -30,6 +33,14 @@
to_chat(M, "<span class='warning'>You're supposed to be spreading gifts, not opening them yourself!</span>")
return
var/gift_type = get_gift_type()
qdel(src)
var/obj/item/I = new gift_type(M)
M.put_in_hands(I)
I.add_fingerprint(M)
/obj/item/a_gift/proc/get_gift_type()
var/gift_type_list = list(/obj/item/sord,
/obj/item/storage/wallet,
/obj/item/storage/photo_album,
@@ -72,10 +83,21 @@
var/gift_type = pick(gift_type_list)
if(!ispath(gift_type, /obj/item))
return
return gift_type
qdel(src)
var/obj/item/I = new gift_type(M)
M.put_in_hands(I)
I.add_fingerprint(M)
/obj/item/a_gift/anything
name = "christmas gift"
desc = "It could be anything!"
/obj/item/a_gift/anything/get_gift_type()
if(!GLOB.possible_gifts.len)
var/list/gift_types_list = subtypesof(/obj/item)
for(var/V in gift_types_list)
var/obj/item/I = V
if((!initial(I.icon_state)) || (!initial(I.item_state)) || (initial(I.flags_1) & ABSTRACT_1))
gift_types_list -= V
GLOB.possible_gifts = gift_types_list
var/gift_type = pick(GLOB.possible_gifts)
return gift_type
@@ -2,7 +2,7 @@
name = "chem implant"
desc = "Injects things."
icon_state = "reagents"
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
/obj/item/implant/chem/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
+1 -1
View File
@@ -419,7 +419,7 @@
name = "suspicious looking duffel bag"
desc = "A large duffel bag for holding extra tactical supplies."
icon_state = "duffel-syndie"
item_state = "duffel-syndie"
item_state = "duffel-syndieammo"
silent = 1
slowdown = 0
+2 -2
View File
@@ -114,7 +114,7 @@
possible_transfer_amounts = list(25,50,100)
volume = 500
flags_1 = NOBLUDGEON_1
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
slot_flags = 0
var/obj/item/watertank/tank
@@ -351,7 +351,7 @@
var/usage_ratio = 5 //5 unit added per 1 removed
var/injection_amount = 1
amount_per_transfer_from_this = 5
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
spillable = FALSE
possible_transfer_amounts = list(5,10,15)
+2 -2
View File
@@ -120,7 +120,7 @@
/obj/item/weldingtool/afterattack(atom/O, mob/user, proximity)
if(!proximity)
return
if(!status && istype(O, /obj/item/reagent_containers) && O.is_open_container())
if(!status && O.is_refillable())
reagents.trans_to(O, reagents.total_volume)
to_chat(user, "<span class='notice'>You empty [src]'s fuel tank into [O].</span>")
update_icon()
@@ -241,7 +241,7 @@
container_type = NONE
else
to_chat(user, "<span class='notice'>[src] can now be attached, modified, and refuelled.</span>")
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
add_fingerprint(user)
/obj/item/weldingtool/proc/flamethrower_rods(obj/item/I, mob/user)
+15 -3
View File
@@ -36,9 +36,6 @@
else
return ..()
/obj/structure/flora/tree/pine
name = "pine tree"
desc = "A coniferous pine tree."
@@ -53,6 +50,21 @@
name = "xmas tree"
desc = "A wondrous decorated Christmas tree."
icon_state = "pine_c"
var/gifts_under_tree = FALSE
var/list/ckeys_that_took = list()
/obj/structure/flora/tree/pine/xmas/attack_hand(mob/living/user)
if(!gifts_under_tree)
return
if(!user.ckey)
return
if(ckeys_that_took[user.ckey])
to_chat(user, "<span class='warning'>You already took your gift.</span>")
return
to_chat(user, "<span class='warning'>After a bit of rummaging, you locate a gift with your name on it!</span>")
ckeys_that_took[user.ckey] = TRUE
var/obj/item/a_gift/anything/A = new
user.put_in_hands(A)
/obj/structure/flora/tree/pine/xmas/Initialize()
. = ..()
+1 -1
View File
@@ -5,7 +5,7 @@
icon_state = "cart"
anchored = FALSE
density = TRUE
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
//copypaste sorry
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
var/obj/item/storage/bag/trash/mybag = null
+1 -1
View File
@@ -89,7 +89,7 @@
name = "magic mirror"
desc = "Turn and face the strange... face."
icon_state = "magic_mirror"
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombie")
var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombies")
var/list/choosable_races = list()
/obj/structure/mirror/magic/New()
+23 -23
View File
@@ -1,24 +1,24 @@
/obj/structure/mopbucket
name = "mop bucket"
desc = "Fill it with water, but don't forget a mop!"
icon = 'icons/obj/janitor.dmi'
icon_state = "mopbucket"
/obj/structure/mopbucket
name = "mop bucket"
desc = "Fill it with water, but don't forget a mop!"
icon = 'icons/obj/janitor.dmi'
icon_state = "mopbucket"
density = TRUE
container_type = OPENCONTAINER_1
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
/obj/structure/mopbucket/New()
create_reagents(100)
..()
/obj/structure/mopbucket/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/mop))
if(reagents.total_volume < 1)
to_chat(user, "[src] is out of water!</span>")
else
reagents.trans_to(I, 5)
to_chat(user, "<span class='notice'>You wet [I] in [src].</span>")
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
else
return ..()
container_type = OPENCONTAINER
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
/obj/structure/mopbucket/New()
create_reagents(100)
..()
/obj/structure/mopbucket/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/mop))
if(reagents.total_volume < 1)
to_chat(user, "[src] is out of water!</span>")
else
reagents.trans_to(I, 5)
to_chat(user, "<span class='notice'>You wet [I] in [src].</span>")
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
else
return ..()
+3 -3
View File
@@ -483,9 +483,9 @@
if(istype(O, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RG = O
if(RG.container_type & OPENCONTAINER_1)
if(RG.is_refillable())
if(!RG.reagents.holder_full())
RG.reagents.add_reagent("[dispensedreagent]", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
RG.reagents.add_reagent(dispensedreagent, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
to_chat(user, "<span class='notice'>You fill [RG] from [src].</span>")
return TRUE
to_chat(user, "<span class='notice'>\The [RG] is full.</span>")
@@ -533,7 +533,7 @@
O.clean_blood()
O.acid_level = 0
create_reagents(5)
reagents.add_reagent("[dispensedreagent]", 5)
reagents.add_reagent(dispensedreagent, 5)
reagents.reaction(O, TOUCH)
user.visible_message("<span class='notice'>[user] washes [O] using [src].</span>", \
"<span class='notice'>You wash [O] using [src].</span>")
+4 -2
View File
@@ -139,9 +139,11 @@
if(isliving(A))
var/mob/living/L = A
if(L.pulling)
var/atom/movable/AM = L.pulling
if(AM)
var/turf/T = get_step(L.loc,turn(A.dir, 180))
L.pulling.forceMove(T)
AM.forceMove(T)
L.start_pulling(AM)
//now we're on the new z_level, proceed the space drifting
stoplag()//Let a diagonal move finish, if necessary
+5 -3
View File
@@ -705,15 +705,17 @@
/datum/admins/proc/output_all_devil_info()
var/devil_number = 0
for(var/D in SSticker.mode.devils)
for(var/datum/mind/D in SSticker.mode.devils)
devil_number++
to_chat(usr, "Devil #[devil_number]:<br><br>" + SSticker.mode.printdevilinfo(D))
var/datum/antagonist/devil/devil = D.has_antag_datum(/datum/antagonist/devil)
to_chat(usr, "Devil #[devil_number]:<br><br>" + devil.printdevilinfo())
if(!devil_number)
to_chat(usr, "<b>No Devils located</b>" )
/datum/admins/proc/output_devil_info(mob/living/M)
if(is_devil(M))
to_chat(usr, SSticker.mode.printdevilinfo(M))
var/datum/antagonist/devil/devil = M.mind.has_antag_datum(/datum/antagonist/devil)
to_chat(usr, devil.printdevilinfo())
else
to_chat(usr, "<b>[M] is not a devil.")
+1
View File
@@ -94,6 +94,7 @@ GLOBAL_LIST(round_end_notifiees)
return "Unable to run query, another admin proc call is in progress. Try again later."
GLOB.AdminProcCaller = "CHAT_[sender]" //_ won't show up in ckeys so it'll never match with a real admin
var/list/results = world.SDQL2_query(params, GLOB.AdminProcCaller, GLOB.AdminProcCaller)
GLOB.AdminProcCaller = null
if(!results)
return "Query produced no output"
var/list/text_res = results.Copy(1, 3)
+1 -1
View File
@@ -524,7 +524,7 @@
if(SSticker.mode.brother_teams.len > 0)
dat += "<br><table cellspacing=5><tr><td><B>Brothers</B></td><td></td><td></td></tr>"
for(var/datum/objective_team/brother_team/team in SSticker.mode.brother_teams)
for(var/datum/team/brother_team/team in SSticker.mode.brother_teams)
for(var/datum/mind/brother in team.members)
var/mob/M = brother.current
if(M)
+11 -3
View File
@@ -240,14 +240,13 @@
//Let's find the spawn locations
var/leader_chosen = FALSE
var/datum/objective_team/nuclear/nuke_team
var/datum/team/nuclear/nuke_team
for(var/mob/c in chosen)
var/mob/living/carbon/human/new_character=makeBody(c)
if(!leader_chosen)
leader_chosen = TRUE
var/datum/antagonist/nukeop/N = new_character.mind.add_antag_datum(/datum/antagonist/nukeop/leader)
nuke_team = N.nuke_team
nuke_team = N.nuke_team
else
new_character.mind.add_antag_datum(/datum/antagonist/nukeop,nuke_team)
return 1
@@ -309,12 +308,15 @@
//Assign antag status and the mission
SSticker.mode.traitors += Commando.mind
Commando.mind.special_role = "deathsquad"
var/datum/objective/missionobj = new
missionobj.owner = Commando.mind
missionobj.explanation_text = mission
missionobj.completed = 1
Commando.mind.objectives += missionobj
Commando.mind.add_antag_datum(/datum/antagonist/auto_custom)
//Greet the commando
to_chat(Commando, "<B><font size=3 color=red>You are the [numagents==1?"Deathsquad Officer":"Death Commando"].</font></B>")
var/missiondesc = "Your squad is being sent on a mission to [station_name()] by Nanotrasen's Security Division."
@@ -361,12 +363,15 @@
//Assign antag status and the mission
SSticker.mode.traitors += newmob.mind
newmob.mind.special_role = "official"
var/datum/objective/missionobj = new
missionobj.owner = newmob.mind
missionobj.explanation_text = mission
missionobj.completed = 1
newmob.mind.objectives += missionobj
newmob.mind.add_antag_datum(/datum/antagonist/auto_custom)
if(CONFIG_GET(flag/enforce_human_authority))
newmob.set_species(/datum/species/human)
@@ -466,12 +471,15 @@
//Assign antag status and the mission
SSticker.mode.traitors += ERTOperative.mind
ERTOperative.mind.special_role = "ERT"
var/datum/objective/missionobj = new
missionobj.owner = ERTOperative.mind
missionobj.explanation_text = mission
missionobj.completed = 1
ERTOperative.mind.objectives += missionobj
ERTOperative.mind.add_antag_datum(/datum/antagonist/auto_custom)
//Greet the commando
to_chat(ERTOperative, "<B><font size=3 color=red>You are [numagents==1?"the Emergency Response Team Commander":"an Emergency Response Officer"].</font></B>")
var/missiondesc = "Your squad is being sent on a Code [alert] mission to [station_name()] by Nanotrasen's Security Division."
+3
View File
@@ -28,6 +28,7 @@ GLOBAL_VAR_INIT(highlander, FALSE)
/mob/living/carbon/human/proc/make_scottish()
SSticker.mode.traitors += mind
mind.special_role = "highlander"
dna.species.species_traits |= NOGUNS //nice try jackass
var/datum/objective/steal/steal_objective = new
@@ -40,6 +41,8 @@ GLOBAL_VAR_INIT(highlander, FALSE)
hijack_objective.owner = mind
mind.objectives += hijack_objective
mind.add_antag_datum(/datum/antagonist/auto_custom)
mind.announce_objectives()
for(var/obj/item/I in get_equipped_items())
+7 -1
View File
@@ -1207,7 +1207,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
if(!holder)
return
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL)
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1229,6 +1229,12 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
bluespace_artillery(target)
if(ADMIN_PUNISHMENT_FIREBALL)
new /obj/effect/temp_visual/target(get_turf(target))
if(ADMIN_PUNISHMENT_ROD)
var/turf/T = get_turf(target)
var/startside = pick(GLOB.cardinals)
var/turf/startT = spaceDebrisStartLoc(startside, T.z)
var/turf/endT = spaceDebrisFinishLoc(startside, T.z)
new /obj/effect/immovablerod(startT, endT,target)
var/msg = "[key_name_admin(usr)] punished [key_name_admin(target)] with [punishment]."
message_admins(msg)
@@ -115,9 +115,11 @@
to_chat(user, "The Wish Granter punishes you for your wickedness, claiming your soul and warping your body to match the darkness in your heart.")
SSticker.mode.traitors += user.mind
user.mind.special_role = "traitor"
var/datum/objective/hijack/hijack = new
hijack.owner = user.mind
user.mind.objectives += hijack
user.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(user, "<B>Your inhibitions are swept away, the bonds of loyalty broken, you are free to murder as you please!</B>")
user.mind.announce_objectives()
user.set_species(/datum/species/shadow)
+3
View File
@@ -68,3 +68,6 @@
var/datum/chatOutput/chatOutput
var/list/credits //lazy list of all credit object bound to this client
var/datum/player_details/player_details //these persist between logins/logouts during the same round.
+7
View File
@@ -227,6 +227,13 @@ GLOBAL_LIST(external_rsc_urls)
message_admins("<font color='red'><B>Notice: </B><font color='blue'>[key_name_admin(src)] has the same [matches] as [key_name_admin(C)] (no longer logged in). </font>")
log_access("Notice: [key_name(src)] has the same [matches] as [key_name(C)] (no longer logged in).")
if(GLOB.player_details[ckey])
player_details = GLOB.player_details[ckey]
else
player_details = new
GLOB.player_details[ckey] = player_details
. = ..() //calls mob.Login()
chatOutput.start() // Starts the chat
+2
View File
@@ -0,0 +1,2 @@
/datum/player_details
var/list/player_actions = list()
+1 -1
View File
@@ -135,7 +135,7 @@
"<span class='notice'>You pin \the [src] on [M]'s chest.</span>")
if(input)
SSblackbox.record_feedback("associative", "commendation", 1, list("commender" = "[user.real_name]", "commendee" = "[M.real_name]", "medal" = "[src]", "reason" = input))
GLOB.commendations += "[user.real_name] awarded <b>[M.real_name]</b> the <font color='blue'>[name]</font>! \n- [input]"
GLOB.commendations += "[user.real_name] awarded <b>[M.real_name]</b> the <span class='medaltext'>[name]</span>! \n- [input]"
commended = TRUE
log_game("<b>[key_name(M)]</b> was given the following commendation by <b>[key_name(user)]</b>: [input]")
message_admins("<b>[key_name(M)]</b> was given the following commendation by <b>[key_name(user)]</b>: [input]")
+1 -1
View File
@@ -98,7 +98,7 @@
else
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
if(RC.container_type & OPENCONTAINER_1)
if(RC.is_drainable())
for(var/datum/reagent/A in RC.reagents.reagent_list)
.[A.type] += A.volume
.[I.type] += 1
@@ -13,7 +13,7 @@
icon = 'icons/obj/toy.dmi'
icon_state = "rag"
flags_1 = NOBLUDGEON_1
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
amount_per_transfer_from_this = 5
possible_transfer_amounts = list()
volume = 5
+7
View File
@@ -45,19 +45,26 @@
to_chat(L, "<span class='warning'><B>You didn't get a date! They're all having fun without you! you'll show them though...</B></span>")
var/datum/objective/martyr/normiesgetout = new
normiesgetout.owner = L.mind
L.mind.special_role = "heartbreaker"
SSticker.mode.traitors |= L.mind
L.mind.objectives += normiesgetout
L.mind.add_antag_datum(/datum/antagonist/auto_custom)
/proc/forge_valentines_objective(mob/living/lover,mob/living/date)
SSticker.mode.traitors |= lover.mind
lover.mind.special_role = "valentine"
var/datum/objective/protect/protect_objective = new /datum/objective/protect
protect_objective.owner = lover.mind
protect_objective.target = date.mind
protect_objective.explanation_text = "Protect [date.real_name], your date."
lover.mind.objectives += protect_objective
lover.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(lover, "<span class='warning'><B>You're on a date with [date]! Protect them at all costs. This takes priority over all other loyalties.</B></span>")
+4 -21
View File
@@ -1,19 +1,3 @@
/datum/round_event_control/treevenge
name = "Treevenge (Christmas)"
holidayID = CHRISTMAS
typepath = /datum/round_event/treevenge
max_occurrences = 1
weight = 20
/datum/round_event/treevenge/start()
for(var/obj/structure/flora/tree/pine/xmas in world)
var/mob/living/simple_animal/hostile/tree/evil_tree = new /mob/living/simple_animal/hostile/tree(xmas.loc)
evil_tree.icon_state = xmas.icon_state
evil_tree.icon_living = evil_tree.icon_state
evil_tree.icon_dead = evil_tree.icon_state
evil_tree.icon_gib = evil_tree.icon_state
qdel(xmas) //b-but I don't want to delete xmas...
//this is an example of a possible round-start event
/datum/round_event_control/presents
name = "Presents under Trees (Christmas)"
@@ -24,12 +8,11 @@
earliest_start = 0
/datum/round_event/presents/start()
for(var/obj/structure/flora/tree/pine/xmas in world)
for(var/obj/structure/flora/tree/pine/xmas/xmas in world)
if(!(xmas.z in GLOB.station_z_levels))
continue
for(var/turf/open/floor/T in orange(1,xmas))
for(var/i=1,i<=rand(1,5),i++)
new /obj/item/a_gift(T)
xmas.icon_state = "pinepresents"
xmas.gifts_under_tree = TRUE
for(var/mob/living/simple_animal/pet/dog/corgi/Ian/Ian in GLOB.mob_living_list)
Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
for(var/obj/machinery/computer/security/telescreen/entertainment/Monitor in GLOB.machines)
@@ -98,7 +81,7 @@
name = "Santa is coming to town! (Christmas)"
holidayID = CHRISTMAS
typepath = /datum/round_event/santa
weight = 150
weight = 20
max_occurrences = 1
earliest_start = 20000
+37 -4
View File
@@ -12,6 +12,16 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
typepath = /datum/round_event/immovable_rod
min_players = 15
max_occurrences = 5
var/atom/special_target
/datum/round_event_control/immovable_rod/admin_setup()
if(!check_rights(R_FUN))
return
var/aimed = alert("Aimed at current location?","Sniperod", "Yes", "No")
if(aimed == "Yes")
special_target = get_turf(usr)
/datum/round_event/immovable_rod
announceWhen = 5
@@ -20,10 +30,11 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
priority_announce("What the fuck was that?!", "General Alert")
/datum/round_event/immovable_rod/start()
var/datum/round_event_control/immovable_rod/C = control
var/startside = pick(GLOB.cardinals)
var/turf/startT = spaceDebrisStartLoc(startside, ZLEVEL_STATION_PRIMARY)
var/turf/endT = spaceDebrisFinishLoc(startside, ZLEVEL_STATION_PRIMARY)
new /obj/effect/immovablerod(startT, endT)
new /obj/effect/immovablerod(startT, endT, C.special_target)
/obj/effect/immovablerod
name = "immovable rod"
@@ -36,18 +47,28 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
var/z_original = 0
var/destination
var/notify = TRUE
var/atom/special_target
/obj/effect/immovablerod/New(atom/start, atom/end)
/obj/effect/immovablerod/New(atom/start, atom/end, aimed_at)
..()
SSaugury.register_doom(src, 2000)
z_original = z
destination = end
special_target = aimed_at
if(notify)
notify_ghosts("\A [src] is inbound!",
enter_link="<a href=?src=[REF(src)];orbit=1>(Click to orbit)</a>",
source=src, action=NOTIFY_ORBIT)
GLOB.poi_list += src
if(end && end.z==z_original)
var/special_target_valid = FALSE
if(special_target)
var/turf/T = get_turf(special_target)
if(T.z == z_original)
special_target_valid = TRUE
if(special_target_valid)
walk_towards(src, special_target, 1)
else if(end && end.z==z_original)
walk_towards(src, destination, 1)
/obj/effect/immovablerod/Topic(href, href_list)
@@ -60,11 +81,20 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
GLOB.poi_list -= src
. = ..()
/obj/effect/immovablerod/Move()
/obj/effect/immovablerod/Moved()
if((z != z_original) || (loc == destination))
qdel(src)
if(special_target && loc == get_turf(special_target))
complete_trajectory()
return ..()
/obj/effect/immovablerod/proc/complete_trajectory()
//We hit what we wanted to hit, time to go
special_target = null
destination = get_edge_target_turf(src, dir)
walk(src,0)
walk_towards(src, destination, 1)
/obj/effect/immovablerod/ex_act(severity, target)
return 0
@@ -83,6 +113,9 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
x = clong.x
y = clong.y
if(special_target && clong == special_target)
complete_trajectory()
if(isturf(clong) || isobj(clong))
if(clong.density)
clong.ex_act(EXPLODE_HEAVY)
+1
View File
@@ -35,6 +35,7 @@
player_mind.assigned_role = "Nightmare"
player_mind.special_role = "Nightmare"
SSticker.mode.traitors += player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
S.set_species(/datum/species/shadow/nightmare)
playsound(S, 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
message_admins("[key_name_admin(S)] has been made into a Nightmare by an event.")
@@ -44,6 +44,7 @@
citizens += H
SSticker.mode.traitors += M
M.special_role = "separatist"
M.add_antag_datum(/datum/antagonist/auto_custom)
H.log_message("<font color='red'>Was made into a separatist, long live [nation]!</font>", INDIVIDUAL_ATTACK_LOG)
to_chat(H, "<B>You are a separatist! [nation] forever! Protect the sovereignty of your newfound land with your comrades in arms!</B>")
if(citizens.len)
+1
View File
@@ -67,6 +67,7 @@
O.completed = 1 //YES!
O.owner = new_holder.mind
new_holder.mind.objectives += O
new_holder.mind.add_antag_datum(/datum/antagonist/auto_custom)
new_holder.log_message("<font color='green'>Won with greentext!!!</font>", INDIVIDUAL_ATTACK_LOG)
color_altered_mobs -= new_holder
resistance_flags |= ON_FIRE
+31 -30
View File
@@ -8,7 +8,7 @@
icon_state = null
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
var/gulp_size = 5 //This is now officially broken ... need to think of a nice way to fix it.
possible_transfer_amounts = list(5,10,15,20,25,30,50)
volume = 50
@@ -30,7 +30,7 @@
if(!canconsume(M, user))
return 0
if (!is_open_container())
if (!is_drainable())
to_chat(user, "<span class='warning'>[src]'s lid hasn't been opened!</span>")
return 0
@@ -44,7 +44,7 @@
if(!reagents || !reagents.total_volume)
return // The drink might be empty after the delay, such as by spam-feeding
M.visible_message("<span class='danger'>[user] feeds the contents of [src] to [M].</span>", "<span class='userdanger'>[user] feeds the contents of [src] to [M].</span>")
add_logs(user, M, "fed", reagentlist(src))
add_logs(user, M, "fed", reagents.log_list())
var/fraction = min(gulp_size/reagents.total_volume, 1)
checkLiked(fraction, M)
@@ -56,31 +56,16 @@
/obj/item/reagent_containers/food/drinks/afterattack(obj/target, mob/user , proximity)
if(!proximity)
return
if(istype(target, /obj/structure/reagent_dispensers)) //A dispenser. Transfer FROM it TO us.
if (!is_open_container())
to_chat(user, "<span class='warning'>[target]'s tab isn't open!</span>")
return
if(!target.reagents.total_volume)
to_chat(user, "<span class='warning'>[target] is empty.</span>")
return
if(reagents.total_volume >= reagents.maximum_volume)
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
to_chat(user, "<span class='notice'>You fill [src] with [trans] units of the contents of [target].</span>")
else if(target.is_open_container()) //Something like a glass. Player probably wants to transfer TO it.
if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "<span class='warning'>[src] is empty.</span>")
return
if(target.reagents.total_volume >= target.reagents.maximum_volume)
if(target.reagents.holder_full())
to_chat(user, "<span class='warning'>[target] is full.</span>")
return
var/refill = reagents.get_master_reagent_id()
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, "<span class='notice'>You transfer [trans] units of the solution to [target].</span>")
@@ -90,13 +75,29 @@
bro.cell.use(30)
addtimer(CALLBACK(reagents, /datum/reagents.proc/add_reagent, refill, trans), 600)
else if(target.is_drainable()) //A dispenser. Transfer FROM it TO us.
if (!is_refillable())
to_chat(user, "<span class='warning'>[src]'s tab isn't open!</span>")
return
if(!target.reagents.total_volume)
to_chat(user, "<span class='warning'>[target] is empty.</span>")
return
if(reagents.holder_full())
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
var/trans = target.reagents.trans_to(src, amount_per_transfer_from_this)
to_chat(user, "<span class='notice'>You fill [src] with [trans] units of the contents of [target].</span>")
else
/obj/item/reagent_containers/food/drinks/attackby(obj/item/I, mob/user, params)
if(I.is_hot())
var/added_heat = (I.is_hot() / 100) //ishot returns a temperature
if(reagents)
reagents.chem_temp += added_heat
to_chat(user, "<span class='notice'>You heat [src] with [I].</span>")
reagents.handle_reactions()
var/hotness = I.is_hot()
if(hotness && reagents)
reagents.expose_temperature(hotness)
to_chat(user, "<span class='notice'>You heat [name] with [I]!</span>")
..()
/obj/item/reagent_containers/food/drinks/throw_impact(atom/target, mob/thrower)
@@ -142,7 +143,7 @@
possible_transfer_amounts = list()
volume = 5
flags_1 = CONDUCT_1
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
spillable = TRUE
resistance_flags = FIRE_PROOF
isGlass = FALSE
@@ -406,9 +407,9 @@
/obj/item/reagent_containers/food/drinks/soda_cans/attack_self(mob/user)
if(!is_open_container())
if(!is_drainable())
to_chat(user, "You pull back the tab of \the [src] with a satisfying pop.") //Ahhhhhhhh
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
playsound(src, "can_open", 50, 1)
spillable = TRUE
return

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