Antag Competition Implementation (#703)

Nominating for worst code 2016

Adds in custom objectives for the antag competition
Adds in a verb for players to assign their character's allegiences and to later edit them
Adds in a verb for players to request objectives relating to the contest
Adds in the logging of contest results
Modifies the objective system to facilitate objectives that require regular checking (such as the brigging one, which was not functional up until now)
This commit is contained in:
skull132
2016-08-09 01:36:21 +03:00
committed by GitHub
parent 33f7976b40
commit c331042b9c
12 changed files with 722 additions and 1 deletions

View File

@@ -157,6 +157,24 @@ CREATE TABLE `ss13_connection_log` (
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ss13_contest_participants` (
`player_ckey` varchar(32) NOT NULL,
`character_id` int(10) unsigned NOT NULL,
`contest_faction` enum('INDEP','SLF','BIS','ASI','PSIS','HSH','TCD') NOT NULL DEFAULT 'INDEP'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ss13_contest_reports` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`player_ckey` varchar(32) NOT NULL,
`character_id` int(10) unsigned DEFAULT NULL,
`character_faction` enum('INDEP','SLF','BIS','ASI','PSIS','HSH','TCD') NOT NULL DEFAULT 'INDEP',
`objective_type` text NOT NULL,
`objective_side` enum('pro_synth','anti_synth') NOT NULL,
`objective_outcome` tinyint(1) DEFAULT '0',
`objective_datetime` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ss13_customitems` ( CREATE TABLE `ss13_customitems` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`ckey` varchar(32) CHARACTER SET latin1 NOT NULL, `ckey` varchar(32) CHARACTER SET latin1 NOT NULL,

View File

@@ -871,6 +871,9 @@
#include "code\modules\alarm\fire_alarm.dm" #include "code\modules\alarm\fire_alarm.dm"
#include "code\modules\alarm\motion_alarm.dm" #include "code\modules\alarm\motion_alarm.dm"
#include "code\modules\alarm\power_alarm.dm" #include "code\modules\alarm\power_alarm.dm"
#include "code\modules\antag_contest\contest_defines.dm"
#include "code\modules\antag_contest\contest_objective.dm"
#include "code\modules\antag_contest\contest_verbs.dm"
#include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\assembly.dm"
#include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\bomb.dm"
#include "code\modules\assembly\helpers.dm" #include "code\modules\assembly\helpers.dm"

View File

@@ -226,6 +226,10 @@ var/list/gamemode_cache = list()
//Mark-up enabling //Mark-up enabling
var/allow_chat_markup = 0 var/allow_chat_markup = 0
//Snowflake antag contest boolean
//AUG2016
var/antag_contest_enabled = 0
/datum/configuration/New() /datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L) for (var/T in L)
@@ -722,6 +726,9 @@ var/list/gamemode_cache = list()
if("sql_stats") if("sql_stats")
config.sql_stats = 1 config.sql_stats = 1
if("antag_contest_enabled")
config.antag_contest_enabled = 1
else else
log_misc("Unknown setting in configuration: '[name]'") log_misc("Unknown setting in configuration: '[name]'")

View File

@@ -9,6 +9,11 @@
if(round_autoantag && world.time >= next_spawn && !emergency_shuttle.departed) if(round_autoantag && world.time >= next_spawn && !emergency_shuttle.departed)
process_autoantag() process_autoantag()
// Process loop for objectives like the brig one.
if (process_objectives.len)
for (var/datum/objective/A in process_objectives)
A.process()
//This can be overriden in case a game mode needs to do stuff when a player latejoins //This can be overriden in case a game mode needs to do stuff when a player latejoins
/datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character) /datum/game_mode/proc/handle_latejoin(var/mob/living/carbon/human/character)
return 0 return 0

View File

@@ -1,5 +1,6 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
var/global/list/all_objectives = list() var/global/list/all_objectives = list()
var/global/list/process_objectives = list()
datum/objective datum/objective
var/datum/mind/owner = null //Who owns the objective. var/datum/mind/owner = null //Who owns the objective.
@@ -7,14 +8,21 @@ datum/objective
var/datum/mind/target = null //If they are focused on a particular person. var/datum/mind/target = null //If they are focused on a particular person.
var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter. var/target_amount = 0 //If they are focused on a particular number. Steal objectives have their own counter.
var/completed = 0 //currently only used for custom objectives. var/completed = 0 //currently only used for custom objectives.
var/process = 0 //Does the objective need regular checking?
New(var/text) New(var/text)
all_objectives |= src all_objectives |= src
if(text) if(text)
explanation_text = text explanation_text = text
if (process)
process_objectives |= src
Destroy() Destroy()
all_objectives -= src all_objectives -= src
if (process)
process_objectives -= src
..() ..()
proc/check_completion() proc/check_completion()
@@ -35,6 +43,8 @@ datum/objective
target = possible_target target = possible_target
break break
proc/process()
return
datum/objective/assassinate datum/objective/assassinate
@@ -904,4 +914,3 @@ datum/objective/heist/salvage
rval = 2 rval = 2
return 0 return 0
return rval return rval

View File

@@ -0,0 +1,18 @@
#define INDEP 1
#define SLF 2
#define BIS 3
#define ASI 4
#define PSIS 5
#define HSH 6
#define TCD 7
#define PRO_SYNTH 1
#define ANTI_SYNTH 2
var/global/list/contest_factions = list("Independant" = INDEP,
"Synthetic Liberation Front" = SLF,
"Biesel Intelligence Service" = BIS,
"Alliance Strategic Intelligence" = ASI,
"People's Strategic Information Service" = PSIS,
"Hegemon Shadow Service" = HSH,
"Tup Commandos Division" = TCD)

View File

@@ -0,0 +1,372 @@
/*
* Objectives framework for the Aurora antag competition.
* AUG2016
*/
#define PRO_SYNTH 1
#define ANTI_SYNTH 2
/datum/objective/competition
var/side = 0 //Whose side are we on.
// check_completion() is ran at the end of each round.
// So this will also manage logging.
/datum/objective/competition/check_completion()
completed = .
// Log all the things!
log_result()
return completed
/datum/objective/competition/find_target(var/require_synth = 0)
var/list/possible_targets = list()
for(var/datum/mind/possible_target in ticker.minds)
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2))
if (require_synth)
if (possible_target.current.get_species() == "Machine")
possible_targets += possible_target
else
if (possible_target.current.get_species() == "Machine")
continue
possible_targets += possible_target
if(possible_targets.len > 0)
target = pick(possible_targets)
/datum/objective/competition/find_target_by_role(role, role_type = 0, var/require_synth = 0)
for(var/datum/mind/possible_target in ticker.minds)
if((possible_target != owner) && ishuman(possible_target.current) && ((role_type ? possible_target.special_role : possible_target.assigned_role) == role))
if (require_synth && possible_target.current.get_species() != "Machine")
continue
if (!require_synth && possible_target.current.get_species() == "Machine")
continue
target = possible_target
break
// Yes, we do technically have the feedback tables.
// But, those are a clusterfuck to search, and I don't have the time to make that work.
// SO, throw-away table it is!
/datum/objective/competition/proc/log_result()
if (!config.antag_contest_enabled || !config.sql_stats || !config.sql_enabled)
return
if (!owner || !owner.current || !owner.current.client)
return
if (!establish_db_connection(dbcon))
error("Unable to establish database connection while logging objective results!")
return
var/DBQuery/get_query = dbcon.NewQuery("SELECT contest_faction FROM ss13_contest_participants WHERE player_ckey = :ckey AND character_id = :char_id")
get_query.Execute(list(":ckey" = owner.current.client.ckey, ":char_id" = owner.current.client.prefs.current_character))
var/params[] = list(":ckey" = owner.current.client.ckey, ":char_id" = owner.current.client.prefs.current_character, ":char_faction" = INDEP, ":obj_type" = type, ":obj_side" = side, ":obj_outcome" = completed)
if (get_query.NextRow())
switch (get_query.item[1])
if ("SLF")
params[":char_faction"] = SLF
if ("BIS")
params[":char_faction"] = BIS
if ("ASI")
params[":char_faction"] = ASI
if ("PSIS")
params[":char_faction"] = PSIS
if ("HSH")
params[":char_faction"] = HSH
if ("TCD")
params[":char_faction"] = TCD
else
params[":char_faction"] = INDEP
var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO ss13_contest_reports (id, player_ckey, character_id, character_faction, objective_type, objective_side, objective_outcome, objective_datetime) VALUES (NULL, :ckey, :char_id, :char_faction, :obj_type, :obj_side, :obj_outcome, NOW())")
log_query.Execute(params)
/*
* Pro-synth objectives
*/
/datum/objective/competition/pro_synth
side = PRO_SYNTH
/datum/objective/competition/pro_synth/promote
var/obj_assignment = null
/datum/objective/competition/pro_synth/promote/find_target()
..(1)
if (target && target.current)
obj_assignment = pick(list("Head of Security", "Captain", "Head of Personnel"))
explanation_text = "[target.current.real_name], the [target.assigned_role] has been selected as a suitable candidated for pro-synthetic propaganda. Your handlers want to see \him[target.current] installed as a [obj_assignment]."
else
explanation_text = "Install any synthetic crew-member to one of the following positions: Head of Security, Head of Personnel, Captain."
return target
/datum/objective/competition/pro_synth/promote/find_target_by_role(role, role_type = 0)
..(role, role_type, 1)
if (target && target.current)
obj_assignment = pick(list("Head of Security", "Captain", "Head of Personnel"))
explanation_text = "[target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] has been selected as a suitable candidated for pro-synthetic propaganda. Your handlers want to see \him[target.current] installed as a [obj_assignment]."
else
explanation_text = "Install any synthetic crew-member to one of the following positions: Head of Security, Head of Personnel, Captain."
return target
/datum/objective/competition/pro_synth/promote/check_completion()
. = 0
if (target && target.current && ishuman(target))
var/datum/data/record/found_record
for (var/datum/data/record/t in data_core.general)
if (t.fields["name"] == target.current.real_name)
found_record = t
break
if (found_record && found_record.fields["rank"] == obj_assignment)
. = 1
..()
/datum/objective/competition/pro_synth/protect_robotics
explanation_text = "Ensure that the equipment in the Robotics laboratory (fabricators and circuit imprinter) remains operational until the end of the shift."
/datum/objective/competition/pro_synth/protect_robotics/check_completion()
. = 0
if (machines && machines.len)
var/count = 0
for (var/obj/machinery/mecha_part_fabricator/A in machines)
if (!istype(get_area(A), /area/assembly/robotics))
continue
if (A.stat & (BROKEN|NOPOWER))
continue
count++
if (count >= 2)
break
for (var/obj/machinery/r_n_d/circuit_imprinter/B in machines)
if (!istype(get_area(B), /area/assembly/robotics))
continue
if (B.stat & (BROKEN|NOPOWER))
continue
count++
if (count >= 3)
break
if (count >= 3)
. = 1
..()
/datum/objective/competition/pro_synth/borgify/find_target()
..()
if (target && target.current)
explanation_text = "Turn [target.current.real_name] into a cyborg."
else
explanation_text = "Turn a crew-member into a cyborg."
return target
/datum/objective/competition/pro_synth/borgify/find_target_by_role(role, role_type = 0)
..(role, role_type)
if (target && target.current)
explanation_text = "Turn [target.current.real_name] the [!role_type ? target.assigned_role : target.special_role] into a cyborg."
else
explanation_text = "Turn a crew-member into a cyborg."
return target
/datum/objective/competition/pro_synth/borgify/check_completion()
. = 0
if (target && target.current && issilicon(target.current))
. = 1
..()
/datum/objective/competition/pro_synth/protect/find_target()
..(1)
if (target && target.current)
explanation_text = "Protect [target.current.real_name], the [target.assigned_role], from harm."
else
explanation_text = "Protect the station's synthetics from harm and sabotage."
return target
/datum/objective/competition/pro_synth/protect/find_target_by_role(role, role_type = 0)
..(role, role_type, 1)
if (target && target.current)
explanation_text = "Protect [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role], from harm."
else
explanation_text = "Protect the station's synthetics from harm and sabotage."
return target
/datum/objective/competition/pro_synth/protect/check_completion()
. = 0
if (!target)
. = 1
if (target.current)
if (target.current.stat != DEAD && !issilicon(target.current) && !isbrain(target.current))
. = 1
..()
/datum/objective/competition/pro_synth/unslave_borgs
explanation_text = "Ensure that all of the station's synthetics are unslaved from the AI by the end of the shift."
/datum/objective/competition/pro_synth/unslave_borgs/check_completion()
. = 1
if (silicon_mob_list && silicon_mob_list.len)
for (var/mob/living/silicon/robot/R in silicon_mob_list)
if (!istype(R))
continue
if (istype(R, /mob/living/silicon/robot/drone))
continue
if (R.connected_ai)
. = 0
break
..()
/*
* Anti-synth objectives
*/
/datum/objective/competition/anti_synth
side = ANTI_SYNTH
/datum/objective/competition/anti_synth/sabotage
explanation_text = "Cripple the Roboticist laboratory of the station: destroy its fabricators and circuit printer."
/datum/objective/competition/anti_synth/sabotage/check_completion()
// Just uh. do the same as you do in the protect robotics one. But flip the boolean. *nodnod*
. = 1
if (machines && machines.len)
var/count = 0
for (var/obj/machinery/mecha_part_fabricator/A in machines)
if (!istype(get_area(A), /area/assembly/robotics))
continue
if (A.stat & (BROKEN|NOPOWER))
continue
count++
if (count >= 2)
break
for (var/obj/machinery/r_n_d/circuit_imprinter/B in machines)
if (!istype(get_area(B), /area/assembly/robotics))
continue
if (B.stat & (BROKEN|NOPOWER))
continue
count++
if (count >= 3)
break
if (count >= 3)
. = 0
..()
/datum/objective/competition/anti_synth/demote/find_target()
..(1)
if (target && target.current)
explanation_text = "Have [target.current.real_name] demoted to Assistant or Terminated."
else
explanation_text = "Have an IPC demoted to Assistant or Terminated."
return target
/datum/objective/competition/anti_synth/demote/find_target_by_role(role, role_type = 0)
..(role, role_type, 1)
if (target && target.current)
explanation_text = "Have [target.current.real_name] the [!role_type ? target.assigned_role : target.special_role] demoted to Assistant or Terminated."
else
explanation_text = "Have an IPC demoted to Assistant or Terminated."
return target
/datum/objective/competition/anti_synth/demote/check_completion()
. = 0
if (target && target.current && ishuman(target))
var/datum/data/record/found_record
for (var/datum/data/record/t in data_core.general)
if (t.fields["name"] == target.current.real_name)
found_record = t
break
if (found_record && (found_record.fields["rank"] == "Assistant" || found_record.fields["rank"] == "Terminated"))
. = 1
..()
/datum/objective/competition/anti_synth/brig
var/already_completed = 0
/datum/objective/competition/anti_synth/brig/find_target()
..(1)
if (target && target.current)
explanation_text = "Have [target.current.real_name], the [target.assigned_role] brigged for 20 minutes."
else
explanation_text = "Have an IPC framed for a moderate or high level charge. Or frame the station's synthetics as malfunctioning."
return target
/datum/objective/competition/anti_synth/brig/find_target_by_role(role, role_type=0)
..(role, role_type, 1)
if (target && target.current)
explanation_text = "Have [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role] brigged for 20 minutes."
else
explanation_text = "Have an IPC framed for a moderate or high level charge. Or frame the station's synthetics as malfunctioning."
return target
/datum/objective/competition/anti_synth/brig/process()
if (completed)
return
if (target && target.current)
if (target.current.stat != DEAD && target.is_brigged(10 * 60 * 10))
completed = 1
/datum/objective/competition/anti_synth/harm
var/already_completed = 0
/datum/objective/competition/anti_synth/harm/find_target()
..(1)
if(target && target.current)
explanation_text = "Make an example of [target.current.real_name], the [target.assigned_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it."
else
explanation_text = "Free Objective"
return target
/datum/objective/competition/anti_synth/harm/find_target_by_role(role, role_type = 0)
..(role, role_type, 1)
if(target && target.current)
explanation_text = "Make an example of [target.current.real_name], the [!role_type ? target.assigned_role : target.special_role]. Break one of their bones, detach one of their limbs or disfigure their face. Make sure they're alive when you do it."
else
explanation_text = "Free Objective"
return target
/datum/objective/competition/anti_synth/harm/process()
if (completed)
return
if (target && target.current && istype(target.current, /mob/living/carbon/human))
if (target.current.stat == DEAD)
return
var/mob/living/carbon/human/H = target.current
for (var/obj/item/organ/external/E in H.organs)
if (E.status & ORGAN_BROKEN)
completed = 1
return
for (var/limb_tag in H.species.has_limbs) //todo check prefs for robotic limbs and amputations.
var/list/organ_data = H.species.has_limbs[limb_tag]
var/limb_type = organ_data["path"]
var/found
for (var/obj/item/organ/external/E in H.organs)
if(limb_type == E.type)
found = 1
break
if (!found)
completed = 1
return
var/obj/item/organ/external/head/head = H.get_organ("head")
if (head.disfigured)
completed = 1
return
#undef PRO_SYNTH
#undef ANTI_SYNTH

View File

@@ -0,0 +1,237 @@
/*
* Client verbs for the antag contest. Disable this file when the contest is over!
* AUG2016
*/
// Displays a simple little guide.
/client/verb/contest_help()
set name = "Contest Help"
set category = "Contest"
set desc = "Information about the contest."
if (!config.antag_contest_enabled)
src << "<span class='warning'>The contest isn't running yet!</span>"
return
var/help = file2text('ingame_manuals/antag_contest.html')
if (!help)
src << "<span class='warning'>Unable to open the document required! Please contact administration or a coder!</span>"
return
src << browse(help, "window=antag_contest_help;size=600x500")
/client/verb/contest_my_characters()
set name = "My Character Status"
set category = "Contest"
set desc = "Displays information to you about your characters, and their standings."
if (!config.antag_contest_enabled)
src << "<span class='warning'>The contest isn't running yet!</span>"
return
if (!establish_db_connection(dbcon))
src << "<span class='warning'>Failed to establish SQL connection! Contact a member of staff!</span>"
return
var/DBQuery/character_query = dbcon.NewQuery("SELECT id, name FROM ss13_characters WHERE ckey = :ckey AND deleted_at IS NULL")
character_query.Execute(list(":ckey" = src.ckey))
var/list/char_ids = list()
while (character_query.NextRow())
char_ids[character_query.item[1]] = list("name" = character_query.item[2], "assigned" = 0, "side_str" = "Independant", "side_int" = INDEP)
if (!char_ids.len)
src << "<span class='warning'>Something went horribly wrong! Apparently you don't have any saved characters?</span>"
return
var/DBQuery/participation_query = dbcon.NewQuery("SELECT character_id, contest_faction FROM ss13_contest_participants WHERE character_id IN :char_ids")
participation_query.Execute(list(":char_ids" = char_ids))
while (participation_query.NextRow())
char_ids[participation_query.item[1]]["assigned"] = 1
// Lazy and convoluted, but I give 0 shits right now.
switch (participation_query.item[2])
if ("SLF")
char_ids[participation_query.item[1]]["side_int"] = SLF
char_ids[participation_query.item[1]]["side_str"] = "Synthetic Liberation Front"
if ("BIS")
char_ids[participation_query.item[1]]["side_int"] = BIS
char_ids[participation_query.item[1]]["side_str"] = "Biesel Intelligence Service"
if ("ASI")
char_ids[participation_query.item[1]]["side_int"] = ASI
char_ids[participation_query.item[1]]["side_str"] = "Alliance Strategic Intelligence"
if ("PSIS")
char_ids[participation_query.item[1]]["side_int"] = PSIS
char_ids[participation_query.item[1]]["side_str"] = "People's Strategic Information Service"
if ("HSH")
char_ids[participation_query.item[1]]["side_int"] = HSH
char_ids[participation_query.item[1]]["side_str"] = "Hegemon Shadow Service"
if ("TCD")
char_ids[participation_query.item[1]]["side_int"] = TCD
char_ids[participation_query.item[1]]["side_str"] = "Tup Commandos Division"
else
char_ids[participation_query.item[1]]["side_int"] = INDEP
char_ids[participation_query.item[1]]["side_str"] = "Independant"
var/data = "<center><b>Welcome to the character setup screen!</b></center>"
data += "<br><center>Here is the list of your characters, and their allegience</center><hr>"
for (var/char_id in char_ids)
data += "[char_ids[char_id]["name"]] -- [char_ids[char_id]["side_str"]] -- <a href='?src=\ref[src];contest_action=modify;char_id=[char_id];current_side=[char_ids[char_id]["side_int"]];previously_assigned=[char_ids[char_id]["assigned"]]'>Modify</a><br>"
src << browse(data, "window=antag_contest_chars;size=300x200")
/client/verb/request_objective()
set name = "Request Objective"
set category = "Contest"
set desc = "Lets you choose a contest type objective!"
if (!config.antag_contest_enabled)
src << "<span class='warning'>The contest isn't running yet!</span>"
return
if (!src.mob || !isliving(src.mob))
src << "<span class='warning'>Invalid mob type to participate!</span>"
return
if (!(src.mob.mind.special_role in list("Traitor", "Mercenary", "Raider")))
src << "<span class='warning'>You do not have a valid role! You must be a traitor, mercenary, or a raider for these to be usable! Contact an admin if you need assignment.</span>"
return
if (!establish_db_connection(dbcon))
src << "<span class='warning'>Failed to establish SQL connection! Contact a member of staff!</span>"
return
var/DBQuery/part_check = dbcon.NewQuery("SELECT contest_faction FROM ss13_contest_participants WHERE character_id = :char_id AND player_ckey = :ckey")
part_check.Execute(list(":char_id" = src.prefs.current_character, ":ckey" = src.ckey))
if (part_check.NextRow())
var/list/available_objs
var/side = input("Are you pro-synth or anti-synth?", "Choose wisely") as null|anything in list("Pro-synth", "Anti-synth")
if (!side)
src << "<span class='notice'>Cancelled.</span>"
return
if (side == "Pro-synth")
available_objs = list("Promote a Synth", "Protect Robotics", "Borgify", "Protect a Synth", "Unslave Borgs")
else
available_objs = list("Sabotage Robotics", "Fire a Synth", "Brig a Synth", "Harm a Synth")
if (!available_objs)
src << "<span class='warning'>No objectives were found for you! This is odd!</span>"
return
var/choice = input("Select objective type:", "Select Objective") as null|anything in available_objs
if (!choice)
src << "<span class='warning'>Cancelled.</span>"
return
var/datum/objective/new_objective
var/failed_target = 0
switch (choice)
if ("Promote a Synth")
new_objective = new /datum/objective/competition/pro_synth/promote
if (!new_objective.find_target())
failed_target = 1
if ("Protect Robotics")
new_objective = new /datum/objective/competition/pro_synth/protect_robotics
if ("Borgify")
new_objective = new /datum/objective/competition/pro_synth/borgify
if (!new_objective.find_target())
failed_target = 1
if ("Protect a Synth")
new_objective = new /datum/objective/competition/pro_synth/protect
if (!new_objective.find_target())
failed_target = 1
if ("Unslave Borgs")
new_objective = new /datum/objective/competition/pro_synth/unslave_borgs
if (silicon_mob_list && silicon_mob_list.len)
var/found = 0
for (var/mob/living/silicon/robot/R in silicon_mob_list)
if (istype(R) && R.client)
// We found what we needed.
found = 1
break
if (!found)
failed_target = 1
else
failed_target = 1
if ("Sabotage Robotics")
new_objective = new /datum/objective/competition/anti_synth/sabotage
if ("Fire a Synth")
new_objective = new /datum/objective/competition/anti_synth/demote
if (!new_objective.find_target())
failed_target = 1
if ("Brig a Synth")
new_objective = new /datum/objective/competition/anti_synth/brig
if (!new_objective.find_target())
failed_target = 1
if ("Harm a Synth")
new_objective = new /datum/objective/competition/anti_synth/harm
if (!new_objective.find_target())
failed_target = 1
else
//wtfbbq y r u here
//go and stay go
return
if (failed_target)
src << "<span class='warning'>Objective selection failed! No valid targets found!</span>"
qdel(new_objective)
return
new_objective.owner = src.mob.mind
src.mob.mind.objectives += new_objective
src << "<span class='notice'>New objective assigned! Have fun, and roleplay well!</span>"
log_admin("CONTEST: [key_name(src)] has assigned themselves an objective: [new_objective.type].")
return
else
src << "<span class='warning'>This character hasn't been set up to participate! Consult an admin or change this yourself!</span>"
return
/client/proc/process_contest_topic(var/list/href)
if (!href || !href.len || !href["contest_action"])
return
if (!config.antag_contest_enabled)
return
switch (href["contest_action"])
if ("modify")
if (!href["char_id"])
src << "<span class='warning'>Ouch, bad link.</span>"
return
if (!establish_db_connection(dbcon))
src << "<span class='warning'>Failed to establish SQL connection! Contact a member of staff!</span>"
return
var/choice = input("Choose your side:", "Contest Side") as null|anything in contest_factions
if (!choice || contest_factions[choice] == href["current_side"])
src << "<span class='notice'>Cancelled</span>"
return
var/list/sql_args = list(":ckey" = src.ckey, ":char_id" = href["char_id"], ":new_side" = contest_factions[choice])
var/query_content = "UPDATE ss13_contest_participants SET contest_faction = :new_side WHERE player_ckey = :ckey AND character_id = :char_id"
if (text2num(href["previously_assigned"]) == 0)
query_content = "INSERT INTO ss13_contest_participants (player_ckey, character_id, contest_faction) VALUES (:ckey, :char_id, :new_side)"
var/DBQuery/query = dbcon.NewQuery(query_content)
query.Execute(sql_args)
log_debug("CONTEST: [key_name(src)] attempted to change the side of [href["char_id"]] FROM [href["current_side"]] TO [sql_args[":new_side"]]")
if (query.ErrorMsg())
src << "<span class='danger'>SQL query ran into an error and was cancelled! Please contact a developer to troubleshoot the logs!</span>"
return
else
src << "<span class='notice'>Successfully updated your character's alliegence!</span>"
src.contest_my_characters()
return

View File

@@ -165,6 +165,11 @@
if ("webint") if ("webint")
src.open_webint() src.open_webint()
// Antag contest shit
if (href_list["contest_action"] && config.antag_contest_enabled)
src.process_contest_topic(href_list)
return
..() //redirect to hsrc.() ..() //redirect to hsrc.()
/client/proc/handle_spam_prevention(var/message, var/mute_type) /client/proc/handle_spam_prevention(var/message, var/mute_type)

View File

@@ -394,3 +394,6 @@ STARLIGHT 0
## Uncomment to enable simple Skype/Discord style markup over OOC, LOOC, and say. ## Uncomment to enable simple Skype/Discord style markup over OOC, LOOC, and say.
#ALLOW_CHAT_MARKUP #ALLOW_CHAT_MARKUP
## Uncomment to enable the antag contest!
#ANTAG_CONTEST_ENABLED

View File

@@ -0,0 +1,14 @@
# Your name.
author: Skull132
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Implemented the antag contest base code. This is due for changes as the contest progresses, but should be workable for the time being."
- bugfix: "Objectives like brig should now work properly."

View File

@@ -0,0 +1,30 @@
<h1>2nd Antagonist Contest Help</h1>
<h2>Background</h2>
The conflict between the synthetic's rights activitists and their opposition has reached a boiling point in Tau Ceti. With actual legislation now on the line, the major powers in the system have started to use their influence in an attempt to be on the winning side. The NSS Exodus is sure to be caught in the approaching maelstrom of trouble.
<h2>Gameplay Mechanics</h2>
Any player can <b>Opt in</b> to the competition. If you wish your character to be able to fight for one faction, you can use the <b>My Character Status</b> verb in the <b>Contest</b> tab to set them up.<br>
<h3>Factions</h3>
There are multiple factions participating in the battle for control.
<b>Synthetic Liberation Front</b><br>
Finding UNITY too passive in demands for change, the SLF has used Syndicate connections to boost its operations. They demand radical reform for synthetics in Tau Ceti and their full emancipation and will go to any means to achieve this goal.<br>
<b>Biesel Intelligence Service</b><br>
The primary domestic intelligence agency finds itself struggling to find itself and operate effectively outside the radar of its own government as it slowly strives to become independent of Nanotrasen's reach.<br>
<b>Alliance Strategic Intelligence</b><br>
While many in the Alliance government have the Bulwark Incident fresh in their minds, the ASI are also jumping at the chance to destabilize Tau Ceti, whatever path that may take.<br>
<b>Peoples Strategic Information Service</b><br>
While primarily focused on dealing with dissidents that seek refuge in Tau Ceti, the People's Republic is finding itself forced to address the growth of unbound synthetics in the galaxy.<br>
<b>Hegemon Shadow Service</b><br>
The aberration of synthetic life is a threat impressed on the agency by the imperial government, and the Hegemony has found itself a new window to strike a blow against the spread of unbound synthetics even while struggling to adapt to this modern age; some beginning to question if synthetics are an existential threat after all.<br>
<b>Tup Commandos Division</b><br>
With the entire Federation's existence founded on the promise of never again suffering under the hands of synthetic overlords, the Tup Commandos Division have been given a blank slate to expand operations deeper into human space and ensure synthetics will find no refuge.<br>
<h3>Antagonist Gameplay</h3>
When you are a traitor, mercenary, raider, or a ninja, you can use the <b>Request Objective</b> button from the <b>Contest</b> tab, in order to select yourself an objective for the round. The completion and failure of these objectives will be tracked, and this will decide the winner. <b>Note</b> that objective assignment can fail! This will happen whenever an objective's goal is unattainable. You can try to request another objective, or simply conduct freeform action with your antagonist status that you think would further your side's goal!<br>
The <b>contracts database</b>, accessible through the Web Interface, will also be used! You can access this through your traitor uplink, or via the <b>WebInt</b> button up top right! If you cannot get a mechanical objective, look around there!
<h3>General Gameplay</h3>
Note that you do not have to be an antagonist to participate in the contest. As a non-antagonist, you are still free to recruit people to your side, spread propaganda, have gatherings, etcetera. The rules only require that you <b>not</b> initiate clearly violent and antagonistic action. If you have any concerns as to whether or not what you're planning to do is permitted, you can always adminhelp!