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
@@ -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)
@@ -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
+237
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
+5
View File
@@ -165,6 +165,11 @@
if ("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.()
/client/proc/handle_spam_prevention(var/message, var/mute_type)