diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index b485a5fa29..c58e111f26 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -57,6 +57,10 @@ #define ADMIN_SET_SD_CODE "(SETCODE)" #define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)] [ADMIN_INDIVIDUALLOG(user)] [ADMIN_SMITE(user)]" #define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]" +//ambition start +#define ADMIN_TPMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_JMP(user)] [ADMIN_FLW(user)]" +#define ADMIN_TPMONTY(user) "[key_name_admin(user)] [ADMIN_TPMONTY_NONAME(user)]" +//ambition end #define ADMIN_JMP(src) "(JMP)" #define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]" #define AREACOORD(src) "[src ? "[get_area_name(src, TRUE)] ([src.x], [src.y], [src.z])" : "nonexistent location"]" diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 9a778aafc7..df84c63157 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -111,3 +111,9 @@ GLOBAL_LIST_EMPTY(living_heart_cache) //A list of all living hearts in existance #define BLOB_SPREAD_COST 4 #define BLOB_ATTACK_REFUND 2 //blob refunds this much if it attacks and doesn't spread #define BLOB_REFLECTOR_COST 15 + +//Objectives-Ambitions Panel +#define REQUEST_NEW_OBJECTIVE "new_objective" +#define REQUEST_DEL_OBJECTIVE "del_objective" +#define REQUEST_WIN_OBJECTIVE "win_objective" +#define REQUEST_LOSE_OBJECTIVE "lose_objective" diff --git a/code/__DEFINES/cooldowns.dm b/code/__DEFINES/cooldowns.dm index 92231d3998..b783678c86 100644 --- a/code/__DEFINES/cooldowns.dm +++ b/code/__DEFINES/cooldowns.dm @@ -27,6 +27,9 @@ //INDEXES #define COOLDOWN_EMPLOYMENT_CABINET "employment cabinet" +#define COOLDOWN_AMBITION "ambition" +#define COOLDOWN_OBJECTIVES "objectives" +#define COOLDOWN_OBJ_ADMIN_PING "obj_admin_ping" //car cooldowns #define COOLDOWN_CAR_HONK "car_honk" diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index d04004c659..b711837232 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -86,6 +86,9 @@ #define EMOTE_OMNI 4 //Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam +//ambition start +#define MAX_AMBITION_LEN 1024 +//ambition end #define MAX_MESSAGE_LEN 4096 //Citadel edit: What's the WORST that could happen? #define MAX_FLAVOR_LEN 4096 #define MAX_TASTE_LEN 40 //lick... vore... ew... diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 70793d7a1d..eec47ffc99 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -13,6 +13,9 @@ #define UNSETEMPTY(L) if (L && !length(L)) L = null #define LAZYCOPY(L) (L ? L.Copy() : list() ) #define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } } +//ambition start +#define LAZYCUT(L, S, E) if((length(L) >= S) && (E == 0 || length(L) >= (E - 1))) { L.Cut(S, E); if(!length(L)) { L = null; } } +//ambition end #define LAZYADD(L, I) if(!L) { L = list(); } L += I; #define LAZYOR(L, I) if(!L) { L = list(); } L |= I; #define LAZYFIND(L, V) (L ? L.Find(V) : 0) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index edc9541abf..21e41584a2 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -624,6 +624,10 @@ currrent_category = A.roundend_category previous_category = A result += A.roundend_report() +//ambition start + for(var/count in 1 to LAZYLEN(A.owner.ambitions)) + result += "
Ambition #[count]: [A.owner.ambitions[count]]" +//ambition end result += "

" CHECK_TICK diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 57c933edc5..fad9879af9 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -347,3 +347,8 @@ default = FALSE /datum/config_entry/flag/dynamic_config_enabled + +//ambition end + config_entry_value = 5 +/datum/config_entry/number/max_ambitions // Maximum number of ambitions a mind can store. +//ambition start diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 164cda63e0..bfcda0bab8 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -235,6 +235,7 @@ else return returned + /** * Callback called by a timer to end an associative-list-indexed cooldown. * diff --git a/code/datums/mind.dm b/code/datums/mind.dm index fe4aa3d46a..13be022a84 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -29,6 +29,12 @@ */ +//ambition start +#define AMBITION_COOLDOWN_TIME (5 SECONDS) +#define OBJECTIVES_COOLDOWN_TIME (2 SECONDS) +#define ADMIN_PING_COOLDOWN_TIME (10 MINUTES) +//ambition end + /datum/mind var/key var/name //replaces mob/var/original_name @@ -68,6 +74,11 @@ /// Our skill holder. var/datum/skill_holder/skill_holder +//ambition start + /// Lazy list for antagonists to set goals they wish to achieve, to be shown at the round-end report. + var/list/ambitions +//ambition end + ///What character we spawned in as- either at roundstart or latejoin, so we know for persistent scars if we ended as the same person or not var/mob/original_character @@ -175,7 +186,9 @@ qdel(A) return A.owner = src - LAZYADD(antag_datums, A) +//ambition start + do_add_antag_datum(A) +//ambition end A.create_team(team) var/datum/team/antag_team = A.get_team() if(antag_team) @@ -183,6 +196,14 @@ A.on_gain() return A +//ambition start +/datum/mind/proc/do_add_antag_datum(instanced_datum) + . = LAZYLEN(antag_datums) + LAZYADD(antag_datums, instanced_datum) + if(!.) + current.verbs += /mob/proc/edit_objectives_and_ambitions +//ambition end + /datum/mind/proc/remove_antag_datum(datum_type) if(!datum_type) return @@ -191,6 +212,14 @@ A.on_removal() return TRUE +//ambition start +/datum/mind/proc/do_remove_antag_datum(instanced_datum) + . = LAZYLEN(antag_datums) + LAZYREMOVE(antag_datums, instanced_datum) + if(. && !LAZYLEN(antag_datums)) + ambitions = null + current.verbs -= /mob/proc/edit_objectives_and_ambitions +//ambition end /datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us. for(var/a in antag_datums) @@ -376,10 +405,10 @@ message_admins("[ADMIN_LOOKUPFLW(current)] has been created by [ADMIN_LOOKUPFLW(creator)], an antagonist.") to_chat(current, "Despite your creators current allegiances, your true master remains [creator.real_name]. If their loyalties change, so do yours. This will never change unless your creator's body is destroyed.") -/datum/mind/proc/show_memory(mob/recipient, window=1) - if(!recipient) - recipient = current - var/output = "[current.real_name]'s Memories:
" +//ambition start +/datum/mind/proc/show_memory() + var/list/output = list("[current.real_name]'s Memories:
") +//ambition end output += memory @@ -400,16 +429,910 @@ output += "
  • Conspirator: [M.name]
  • " output += "" - if(window) - recipient << browse(output,"window=memory") - else if(all_objectives.len || memory) - to_chat(recipient, "[output]") +//ambition port start + if(LAZYLEN(ambitions)) + for(var/count in 1 to LAZYLEN(ambitions)) + output += "
    Ambition #[count]: [ambitions[count]]" + + if(!memory && !length(all_objectives) && !LAZYLEN(ambitions)) + output += "" + + return output.Join() + + +/datum/mind/proc/show_editable_objectives_and_ambitions() + var/is_admin = check_rights(R_ADMIN, FALSE) + var/self_mind = usr == current + if(!is_admin && !self_mind) + return "" + var/list/output = list() + for(var/a in antag_datums) + var/datum/antagonist/antag_datum = a + output += "Objectives:" + if(is_admin) + output += " Add Objective" + output += "" + if(is_admin) + output += "Announce objectives
    " + output += "
    Requested Objective Changes:" + if(self_mind) + output += " Request objective" + output += "
    " + else + for(var/uid in antag_datum.requested_objective_changes) + var/list/objectives_info = antag_datum.requested_objective_changes[uid] + var/obj_request = objectives_info["request"] + switch(obj_request) + if(REQUEST_NEW_OBJECTIVE) + var/datum/objective/type_cast_objective = objectives_info["target"] + var/objective_text = objectives_info["text"] + output += "
  • Request #[uid]: ADD [initial(type_cast_objective.name)] - [objective_text]" + if(self_mind) + output += " Cancel Request" + if(is_admin) + output += " Accept Edit Deny" + if(REQUEST_DEL_OBJECTIVE) + var/datum/objective/objective_ref = locate(objectives_info["target"]) in antag_datum.objectives + if(QDELETED(objective_ref)) + stack_trace("Objective request found with deleted reference. UID: [uid] | Antag: [antag_datum] | Mind: [src] | User: [usr]") + antag_datum.remove_objective_change(uid) + continue + output += "
  • Request #[uid]: DEL [objective_ref.name] - [objective_ref.explanation_text] - [objectives_info["text"]]" + if(self_mind) + output += " Cancel Request" + if(is_admin) + output += " Accept Deny" + if(REQUEST_WIN_OBJECTIVE, REQUEST_LOSE_OBJECTIVE) + var/datum/objective/objective_ref = locate(objectives_info["target"]) in antag_datum.objectives + if(QDELETED(objective_ref)) + stack_trace("Objective request found with deleted reference. UID: [uid] | Antag: [antag_datum] | Mind: [src] | User: [usr]") + antag_datum.remove_objective_change(uid) + continue + output += "
  • Request #[uid]: [obj_request == REQUEST_WIN_OBJECTIVE ? "WIN" : "LOSE"] [objective_ref.name] - [objective_ref.explanation_text] - [objectives_info["text"]]" + if(self_mind) + output += " Cancel Request" + if(is_admin) + output += " Accept Deny" + else + stack_trace("Objective request found with no request index. UID: [uid] | Antag: [antag_datum] | Mind: [src] | User: [usr]") + continue + output += "
    " + if(self_mind) + output += "Ping the admins
    " + if(is_admin) + output += "Clear ping cooldown
    " + output += "
    [current.real_name]'s Ambitions:" + if(LAZYLEN(ambitions) < CONFIG_GET(number/max_ambitions)) + output += " Add Ambition" + output += "
    (Refresh)" + return output.Join() + + +/mob/proc/edit_objectives_and_ambitions() + set name = "Objectives and Ambitions" + set category = "IC" + set desc = "View and edit your character's objectives and ambitions." + mind.do_edit_objectives_ambitions() + + +/datum/mind/proc/do_edit_objectives_ambitions() + var/datum/browser/popup = new(usr, "objectives and ambitions", "Objectives and Ambitions") + popup.set_content(show_editable_objectives_and_ambitions()) + popup.open() + + +GLOBAL_VAR_INIT(requested_objective_uid, 0) + + +GLOBAL_LIST(objective_player_choices) + +/proc/populate_objective_player_choices() + GLOB.objective_player_choices = list() + var/list/allowed_types = list( + /datum/objective/custom, + /datum/objective/assassinate/once, + /datum/objective/protect, + /datum/objective/escape, + /datum/objective/survive, + /datum/objective/martyr, + /datum/objective/steal, + /datum/objective/download, + ) + + for(var/t in allowed_types) + var/datum/objective/type_cast = t + GLOB.objective_player_choices[initial(type_cast.name)] = t + + +GLOBAL_LIST(objective_choices) + +/proc/populate_objective_choices() + GLOB.objective_choices = list() + var/list/allowed_types = list( + /datum/objective/custom, + /datum/objective/assassinate, + /datum/objective/assassinate/once, + /datum/objective/maroon, + /datum/objective/debrain, + /datum/objective/protect, + /datum/objective/destroy, + /datum/objective/hijack, + /datum/objective/escape, + /datum/objective/survive, + /datum/objective/martyr, + /datum/objective/steal, + /datum/objective/download, + /datum/objective/nuclear, + /datum/objective/absorb, + ) + + for(var/t in allowed_types) + var/datum/objective/type_cast = t + GLOB.objective_choices[initial(type_cast.name)] = t + + +/datum/mind/proc/on_objectives_request_cd_end(datum/source) + UnregisterSignal(src, list(COMSIG_CD_STOP(COOLDOWN_OBJ_ADMIN_PING), COMSIG_CD_RESET(COOLDOWN_OBJ_ADMIN_PING))) + if(!antag_datums) + return + to_chat(current, "You are now again able to ping the admins objective changes review requests.") + for(var/a in antag_datums) + var/datum/antagonist/antag_datum = a + if(!antag_datum.requested_objective_changes) + continue + to_chat(current, "You seem to have unanswered change requests. If there are online admins another gentle reminder might be in order.") + break +//ambition port end /datum/mind/Topic(href, href_list) +//ambition start + + if (href_list["refresh_obj_amb"]) + do_edit_objectives_ambitions() + return + + else if (href_list["add_ambition"]) + if(!check_rights(R_ADMIN, FALSE)) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_AMBITION)) + to_chat(usr, "You must wait [AMBITION_COOLDOWN_TIME * 0.1] seconds between changes.") + return + if(!isliving(current)) + return + if(!antag_datums) + return + var/max_ambitions = CONFIG_GET(number/max_ambitions) + if(LAZYLEN(ambitions) >= max_ambitions) + to_chat(usr, "There's a limit of [max_ambitions] ambitions. Edit or remove some to accomodate for your new additions.") + do_edit_objectives_ambitions() + return + var/new_ambition = stripped_multiline_input(usr, "Write new ambition", "Ambition", "", MAX_AMBITION_LEN) + if(isnull(new_ambition)) + return + if(!check_rights(R_ADMIN, FALSE)) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_AMBITION)) + to_chat(usr, "You must wait [AMBITION_COOLDOWN_TIME * 0.1] seconds between changes.") + return + if(!isliving(current)) + to_chat(usr, "The mind holder is no longer a living creature.") + return + if(!antag_datums) + to_chat(usr, "The mind holder is no longer an antagonist.") + return + if(LAZYLEN(ambitions) >= max_ambitions) + to_chat(usr, "There's a limit of [max_ambitions] ambitions. Edit or remove some to accomodate for your new additions.") + do_edit_objectives_ambitions() + return + TIMER_COOLDOWN_START(src, COOLDOWN_AMBITION, AMBITION_COOLDOWN_TIME) + LAZYADD(ambitions, new_ambition) + if(usr == current) + log_game("[key_name(usr)] has created their ambition of index [LAZYLEN(ambitions)].\nNEW AMBITION:\n[new_ambition]") + else + log_game("[key_name(usr)] has created [key_name(current)]'s ambition of index [LAZYLEN(ambitions)].\nNEW AMBITION:\n[new_ambition]") + message_admins("[ADMIN_TPMONTY(usr)] has created [ADMIN_TPMONTY(current)]'s ambition of index [LAZYLEN(ambitions)].") + do_edit_objectives_ambitions() + return + + else if (href_list["edit_ambition"]) + if(!check_rights(R_ADMIN, FALSE)) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_AMBITION)) + to_chat(usr, "You must wait [AMBITION_COOLDOWN_TIME * 0.1] seconds between changes.") + return + if(!isliving(current)) + return + if(!antag_datums) + return + var/ambition_index = text2num(href_list["edit_ambition"]) + if(!isnum(ambition_index) || ambition_index < 0 || ambition_index % 1) + log_admin_private("[key_name(usr)] attempted to edit their ambitions with and invalid ambition_index ([ambition_index]) at [AREACOORD(usr.loc)].") + message_admins("[ADMIN_TPMONTY(usr)] attempted to edit their ambitions with and invalid ambition_index ([ambition_index]). Possible HREF exploit.") + return + if(ambition_index > LAZYLEN(ambitions)) + return + var/old_ambition = ambitions[ambition_index] + var/new_ambition = stripped_multiline_input(usr, "Write new ambition", "Ambition", ambitions[ambition_index], MAX_AMBITION_LEN) + if(isnull(new_ambition)) + return + if(!check_rights(R_ADMIN, FALSE)) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_AMBITION)) + to_chat(usr, "You must wait [AMBITION_COOLDOWN_TIME * 0.1] seconds between changes.") + return + if(!isliving(current)) + to_chat(usr, "The mind holder is no longer a living creature.") + return + if(!antag_datums) + to_chat(usr, "The mind holder is no longer an antagonist.") + return + if(ambition_index > LAZYLEN(ambitions)) + to_chat(usr, "The ambition we were editing was deleted before we finished. Aborting.") + do_edit_objectives_ambitions() + return + if(old_ambition != ambitions[ambition_index]) + to_chat(usr, "The ambition has changed since we started editing it. Aborting to prevent data loss.") + do_edit_objectives_ambitions() + return + TIMER_COOLDOWN_START(src, COOLDOWN_AMBITION, AMBITION_COOLDOWN_TIME) + ambitions[ambition_index] = new_ambition + if(usr == current) + log_game("[key_name(usr)] has edited their ambition of index [ambition_index].\nOLD AMBITION:\n[old_ambition]\nNEW AMBITION:\n[new_ambition]") + else + log_game("[key_name(usr)] has edited [key_name(current)]'s ambition of index [ambition_index].\nOLD AMBITION:\n[old_ambition]\nNEW AMBITION:\n[new_ambition]") + message_admins("[ADMIN_TPMONTY(usr)] has edited [ADMIN_TPMONTY(current)]'s ambition of index [ambition_index].") + do_edit_objectives_ambitions() + return + + else if (href_list["remove_ambition"]) + if(!check_rights(R_ADMIN, FALSE)) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_AMBITION)) + to_chat(usr, "You must wait [AMBITION_COOLDOWN_TIME * 0.1] seconds between changes.") + return + if(!isliving(current)) + return + if(!antag_datums) + return + var/ambition_index = text2num(href_list["remove_ambition"]) + if(ambition_index > LAZYLEN(ambitions)) + do_edit_objectives_ambitions() + return + if(!isnum(ambition_index) || ambition_index < 0 || ambition_index % 1) + log_admin_private("[key_name(usr)] attempted to remove an ambition with and invalid ambition_index ([ambition_index]) at [AREACOORD(usr.loc)].") + message_admins("[ADMIN_TPMONTY(usr)] attempted to remove an ambition with and invalid ambition_index ([ambition_index]). Possible HREF exploit.") + return + var/old_ambition = ambitions[ambition_index] + if(alert(usr, "Are you sure you want to delete this ambition?", "Delete ambition", "Yes", "No") != "Yes") + return + if(!check_rights(R_ADMIN, FALSE)) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_AMBITION)) + to_chat(usr, "You must wait [AMBITION_COOLDOWN_TIME * 0.1] seconds between changes.") + return + if(!isliving(current)) + to_chat(usr, "The mind holder is no longer a living creature. The ambition we were deleting should no longer exist already.") + return + if(!antag_datums) + to_chat(usr, "The mind holder is no longer an antagonist. The ambition we were deleting should no longer exist already.") + return + if(ambition_index > LAZYLEN(ambitions)) + to_chat(usr, "The ambition we were deleting was deleted before we finished. No need to continue.") + do_edit_objectives_ambitions() + return + if(old_ambition != ambitions[ambition_index]) + to_chat(usr, "The ambition has changed since we started considering its deletion. Aborting to prevent conflicts.") + do_edit_objectives_ambitions() + return + TIMER_COOLDOWN_START(src, COOLDOWN_AMBITION, AMBITION_COOLDOWN_TIME) + LAZYCUT(ambitions, ambition_index, ambition_index + 1) + if(usr == current) + log_game("[key_name(usr)] has deleted their ambition of index [ambition_index].\nDELETED AMBITION:\n[old_ambition]") + else + log_game("[key_name(usr)] has deleted [key_name(current)]'s ambition of index [ambition_index].\nDELETED AMBITION:\n[old_ambition]") + message_admins("[ADMIN_TPMONTY(usr)] has deleted [ADMIN_TPMONTY(current)]'s ambition of index [ambition_index].") + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_ping"]) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJ_ADMIN_PING)) + to_chat(usr, "You must wait [S_TIMER_COOLDOWN_TIMELEFT(src, COOLDOWN_OBJ_ADMIN_PING) * 0.1] seconds before your next admin ping.") + do_edit_objectives_ambitions() + return + if(!antag_datums) + return + var/pending_request = FALSE + for(var/a in antag_datums) + var/datum/antagonist/antag_datum = a + if(antag_datum.requested_objective_changes) + pending_request = TRUE + break + if(!pending_request) + to_chat(usr, "You have no pending requests to warn the admins about. Request changes for them to review before poking them.") + do_edit_objectives_ambitions() + return + var/justification = stripped_multiline_input(usr, + "Send a message to the admins requesting a review of your objective change requests.\ + There's a [ADMIN_PING_COOLDOWN_TIME * 0.1] seconds cooldown between requests, so try to think it through before sending it. Cancelling this does not trigger the cooldown.", + "Request Admin Review", max_length = MAX_MESSAGE_LEN) + if(isnull(justification)) + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJ_ADMIN_PING)) + to_chat(usr, "You must wait [S_TIMER_COOLDOWN_TIMELEFT(src, COOLDOWN_OBJ_ADMIN_PING) * 0.1] seconds before your next admin ping.") + do_edit_objectives_ambitions() + return + if(!antag_datums) + return + pending_request = FALSE + for(var/a in antag_datums) + var/datum/antagonist/antag_datum = a + if(antag_datum.requested_objective_changes) + pending_request = TRUE + break + if(!pending_request) + return + if(!length(GLOB.admins)) + to_chat(usr, "No admins currently connected, failed to notify them. Wait for one to connect before trying to ping them again.") + do_edit_objectives_ambitions() + return + S_TIMER_COOLDOWN_START(src, COOLDOWN_OBJ_ADMIN_PING, ADMIN_PING_COOLDOWN_TIME) + RegisterSignal(src, list(COMSIG_CD_STOP(COOLDOWN_OBJ_ADMIN_PING), COMSIG_CD_RESET(COOLDOWN_OBJ_ADMIN_PING)), .proc/on_objectives_request_cd_end) + log_admin("Objectives review request - [key_name(usr)] has requested a review of their objective changes, pinging the admins.") + for(var/a in GLOB.admins) + var/client/admin_client = a + if(admin_client.prefs.toggles & SOUND_ADMINHELP) + SEND_SOUND(admin_client, sound('sound/effects/adminhelp.ogg')) + window_flash(admin_client) + message_admins("[ADMIN_TPMONTY(usr)] has requested a review of their objective changes. (RPLY)") + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_add"]) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + do_edit_objectives_ambitions() + return + var/datum/antagonist/target_antag = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(target_antag)) + to_chat(usr, "No antagonist found for this objective.") + do_edit_objectives_ambitions() + return + if(!GLOB.objective_player_choices) + populate_objective_player_choices() + var/choice = input("Select desired objective type:", "Objective type") as null|anything in GLOB.objective_player_choices + var/selected_type = GLOB.objective_player_choices[choice] + if(!selected_type) + return + var/new_objective = stripped_multiline_input(usr,\ + selected_type == /datum/objective/custom\ + ? "Write the custom objective you'd like to request the admins to grant you. Remember they can edit or deny your request at their own discretion."\ + : "Justify your request for a new objective to the admins. Add the required clarifations, if you have a specific targets in mind and the likes.",\ + "New Objective", max_length = MAX_MESSAGE_LEN) + if(isnull(new_objective)) + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME] minutes between request changes.") + return + if(QDELETED(target_antag)) + return + TIMER_COOLDOWN_START(src, COOLDOWN_OBJECTIVES, OBJECTIVES_COOLDOWN_TIME) + var/uid = "[GLOB.requested_objective_uid++]" + target_antag.add_objective_change(uid, list("request" = REQUEST_NEW_OBJECTIVE, "target" = selected_type, "text" = new_objective)) + log_admin("Objectives request [uid] - [key_name(usr)] has requested a [choice] objective: [new_objective]") + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_cancel"]) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + var/datum/antagonist/target_antag = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(target_antag)) + to_chat(usr, "No antagonist found for this objective.") + do_edit_objectives_ambitions() + return + var/uid = href_list["req_obj_cancel"] + if(!LAZYACCESS(target_antag.requested_objective_changes, uid)) + to_chat(usr, "No requested objective change found. Perhaps it was deleted already?") + do_edit_objectives_ambitions() + return + if(alert(usr, "Are you sure you want to delete this change request?", "Delete change request", "Yes", "No") != "Yes") + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + if(QDELETED(target_antag)) + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(target_antag.requested_objective_changes, uid)) + do_edit_objectives_ambitions() + return + TIMER_COOLDOWN_START(src, COOLDOWN_OBJECTIVES, OBJECTIVES_COOLDOWN_TIME) + log_admin("Objectives request deletion - [key_name(usr)] has deleted the objective change request of UID [uid].") + target_antag.remove_objective_change(uid) + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_delete"]) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + var/datum/antagonist/target_antag = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(target_antag)) + to_chat(usr, "No antagonist found for this objective.") + do_edit_objectives_ambitions() + return + var/objective_reference = href_list["req_obj_delete"] + var/datum/objective/objective_to_delete = locate(objective_reference) in target_antag.objectives + if(!istype(objective_to_delete) || QDELETED(objective_to_delete)) + to_chat(usr, "No objective found. Perhaps it was already deleted?") + do_edit_objectives_ambitions() + return + var/justification = stripped_multiline_input(usr, + "Justify your request for a deleting this objective to the admins.", + "Objective Deletion", max_length = MAX_MESSAGE_LEN) + if(isnull(justification)) + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + if(QDELETED(objective_to_delete) || QDELETED(target_antag)) + do_edit_objectives_ambitions() + return + var/matching_request = FALSE + for(var/index in target_antag.requested_objective_changes) + var/list/change_request = target_antag.requested_objective_changes[index] + if(change_request["target"] != objective_reference) + continue + matching_request = TRUE + break + if(matching_request) + if(alert(usr, "There is already a change request tied to this objective waiting to be processed. Adding this request will delete the old ones.", "Delete matching objective requests?", "Yes", "No") != "Yes") + do_edit_objectives_ambitions() + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + if(QDELETED(objective_to_delete) || QDELETED(target_antag)) + do_edit_objectives_ambitions() + return + for(var/index in target_antag.requested_objective_changes) + var/list/change_request = target_antag.requested_objective_changes[index] + if(change_request["target"] != objective_reference) + continue + target_antag.remove_objective_change(index) + TIMER_COOLDOWN_START(src, COOLDOWN_OBJECTIVES, OBJECTIVES_COOLDOWN_TIME) + var/uid = "[GLOB.requested_objective_uid++]" + target_antag.add_objective_change(uid, list("request" = REQUEST_DEL_OBJECTIVE, "target" = objective_reference, "text" = justification)) + log_admin("Objectives request [uid] - [key_name(usr)] has requested the deletion of the following objective: [objective_to_delete.explanation_text].\nTheir justification is as follows: [justification]") + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_completed"]) + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + var/datum/antagonist/target_antag = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(target_antag)) + to_chat(usr, "No antagonist found for this objective.") + do_edit_objectives_ambitions() + return + var/objective_reference = href_list["req_obj_completed"] + var/datum/objective/objective_to_complete = locate(objective_reference) in target_antag.objectives + if(!istype(objective_to_complete) || QDELETED(objective_to_complete)) + to_chat(usr, "No objective found. Perhaps it was deleted?") + do_edit_objectives_ambitions() + return + var/justification = stripped_multiline_input(usr, + "Justify to the admins your request to mark this objective as [objective_to_complete.completed ? "incomplete" : "completed"].", + "Objective [objective_to_complete.completed ? "Incompletion" : "Completion"]", max_length = MAX_MESSAGE_LEN) + if(isnull(justification)) + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + if(QDELETED(objective_to_complete) || QDELETED(target_antag)) + do_edit_objectives_ambitions() + return + var/matching_request = FALSE + for(var/index in target_antag.requested_objective_changes) + var/list/change_request = target_antag.requested_objective_changes[index] + if(change_request["target"] != objective_reference) + continue + matching_request = TRUE + break + if(matching_request) + if(alert(usr, "There is already a change request tied to this objective waiting to be processed. Adding this request will delete the old ones.", "Delete matching objective requests?", "Yes", "No") != "Yes") + return + if(usr != current) + return + if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJECTIVES)) + to_chat(usr, "You must wait [OBJECTIVES_COOLDOWN_TIME * 0.1] seconds between request changes.") + return + if(QDELETED(objective_to_complete) || QDELETED(target_antag)) + do_edit_objectives_ambitions() + return + for(var/index in target_antag.requested_objective_changes) + var/list/change_request = target_antag.requested_objective_changes[index] + if(change_request["target"] != objective_reference) + continue + target_antag.remove_objective_change(index) + TIMER_COOLDOWN_START(src, COOLDOWN_OBJECTIVES, OBJECTIVES_COOLDOWN_TIME) + var/uid = "[GLOB.requested_objective_uid++]" + target_antag.add_objective_change(uid, list("request" = (objective_to_complete.completed ? REQUEST_LOSE_OBJECTIVE : REQUEST_WIN_OBJECTIVE), "target" = objective_reference, "text" = justification)) + log_admin("Objectives request [uid] - [key_name(usr)] has requested the [objective_to_complete.completed ? "incompletion" : "completion"] of the following objective: [objective_to_complete.explanation_text].\nTheir justification is as follows: [justification]") + do_edit_objectives_ambitions() + return if(!check_rights(R_ADMIN)) return var/self_antagging = usr == current + if(href_list["edit_ambitions_panel"]) + do_edit_objectives_ambitions() + return + + else if(href_list["req_obj_ping_cd_clear"]) + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJ_ADMIN_PING)) + to_chat(usr, "Mind is not under a cooldown.") + do_edit_objectives_ambitions() + return + if(alert(usr, "Are you sure you want reset this cooldown, letting the user ping the admins again?", "Clear ping cooldown", "Yes", "No") != "Yes") + do_edit_objectives_ambitions() + return + if(!check_rights(R_ADMIN)) + return + if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_OBJ_ADMIN_PING)) + do_edit_objectives_ambitions() + return + S_TIMER_COOLDOWN_RESET(src, COOLDOWN_OBJ_ADMIN_PING) + do_edit_objectives_ambitions() + return + + else if(href_list["refresh_antag_panel"]) + traitor_panel() + return + + else if (href_list["req_obj_edit"]) + var/datum/antagonist/antag_datum = locate(href_list["req_obj_edit"]) in antag_datums + if(QDELETED(antag_datum)) + do_edit_objectives_ambitions() + to_chat(usr, "No antag found.") + return + if(antag_datum.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid antag reference.") + return + var/uid = href_list["req_obj_id"] + var/list/requested_obj_change = LAZYACCESS(antag_datum.requested_objective_changes, uid) + if(!requested_obj_change) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid requested objective reference.") + return + if(requested_obj_change["request"] != REQUEST_NEW_OBJECTIVE) + do_edit_objectives_ambitions() + to_chat(usr, "This is not an editable request. How did you even got here?") + return + switch(alert(usr, "Do you want to edit the requested objective type or text?", "Edit requested objective", "Type", "Text", "Cancel")) + if("Type") + if(!check_rights(R_ADMIN)) + return + if(QDELETED(antag_datum)) + to_chat(usr, "No antag found.") + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(antag_datum.requested_objective_changes, uid)) + to_chat(usr, "Invalid requested objective change reference.") + do_edit_objectives_ambitions() + return + var/datum/objective/type_cast = requested_obj_change["target"] + var/selected_type = input("Select new requested objective type:", "Requested Objective type", initial(type_cast.name)) as null|anything in GLOB.objective_choices + selected_type = GLOB.objective_choices[selected_type] + if(!selected_type) + return + if(!check_rights(R_ADMIN)) + return + if(QDELETED(antag_datum)) + to_chat(usr, "No antag found.") + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(antag_datum.requested_objective_changes, uid)) + to_chat(usr, "Invalid requested objective change reference.") + do_edit_objectives_ambitions() + return + log_admin("[key_name(usr)] has edited the requested objective type for [current], of UID [uid], from [requested_obj_change["target"]] to [selected_type]") + message_admins("[key_name_admin(usr)] has edited the requested objective type for [current], of UID [uid], from [requested_obj_change["target"]] to [selected_type]") + requested_obj_change["target"] = selected_type + if("Text") + if(!check_rights(R_ADMIN)) + return + if(QDELETED(antag_datum)) + to_chat(usr, "No antag found.") + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(antag_datum.requested_objective_changes, uid)) + to_chat(usr, "Invalid requested objective change reference.") + do_edit_objectives_ambitions() + return + var/new_text = stripped_multiline_input(usr, "Input new requested objective text", "Requested Objective Text", requested_obj_change["text"], MAX_MESSAGE_LEN) + if (isnull(new_text)) + return + if(!check_rights(R_ADMIN)) + return + if(QDELETED(antag_datum)) + to_chat(usr, "No antag found.") + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(antag_datum.requested_objective_changes, uid)) + to_chat(usr, "Invalid requested objective change reference.") + do_edit_objectives_ambitions() + return + log_admin("[key_name(usr)] has edited the requested objective text for [current], of UID [uid], from [requested_obj_change["text"]] to [new_text]") + message_admins("[key_name_admin(usr)] has edited the requested objective text for [current], of UID [uid], from [requested_obj_change["text"]] to [new_text]") + requested_obj_change["text"] = new_text + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_accept"]) + var/datum/antagonist/antag_datum = locate(href_list["req_obj_accept"]) in antag_datums + if(QDELETED(antag_datum)) + do_edit_objectives_ambitions() + to_chat(usr, "No antag found.") + return + if(antag_datum.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid antag reference.") + return + var/uid = href_list["req_obj_id"] + var/list/requested_obj_change = LAZYACCESS(antag_datum.requested_objective_changes, uid) + if(!requested_obj_change) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid requested objective reference.") + return + + var/datum/objective/request_target + var/request_type = requested_obj_change["request"] + switch(request_type) + if(REQUEST_NEW_OBJECTIVE) + request_target = requested_obj_change["target"] + if(!ispath(request_target, /datum/objective)) + to_chat(usr, "Invalid requested objective target path.") + return + if(REQUEST_DEL_OBJECTIVE, REQUEST_WIN_OBJECTIVE, REQUEST_LOSE_OBJECTIVE) + request_target = locate(requested_obj_change["target"]) in antag_datum.objectives + if(QDELETED(request_target)) + to_chat(usr, "Invalid requested objective target reference.") + return + else + to_chat(usr, "Invalid request type.") + return + if(alert(usr, "Are you sure you want to approve this objective change?", "Approve objective change", "Yes", "No") != "Yes") + return + if(!check_rights(R_ADMIN)) + return + if(QDELETED(antag_datum)) + to_chat(usr, "No antag found.") + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(antag_datum.requested_objective_changes, uid)) + to_chat(usr, "Invalid requested objective change reference.") + do_edit_objectives_ambitions() + return + switch(request_type) //Last checks + if(REQUEST_NEW_OBJECTIVE) + if(!ispath(request_target, /datum/objective)) + stack_trace("Invalid target on objective change request: [request_target]") + do_edit_objectives_ambitions() + return + if(REQUEST_DEL_OBJECTIVE, REQUEST_WIN_OBJECTIVE, REQUEST_LOSE_OBJECTIVE) + if(QDELETED(request_target)) + to_chat(usr, "Invalid requested objective target reference.") + return + else + to_chat(usr, "Invalid request type.") + return + antag_datum.remove_objective_change(uid) + switch(request_type) //All is clear, let get things done. + if(REQUEST_NEW_OBJECTIVE) + request_target = new request_target() + request_target.owner = src + if(istype(request_target, /datum/objective/custom)) + request_target.explanation_text = requested_obj_change["text"] + else + request_target.admin_edit(usr) + antag_datum.objectives += request_target + message_admins("[key_name_admin(usr)] approved a requested objective from [current]: [request_target.explanation_text]") + log_admin("[key_name(usr)] approved a requested objective from [current]: [request_target.explanation_text]") + if(REQUEST_DEL_OBJECTIVE) + message_admins("[key_name_admin(usr)] approved the request to delete an objective from [current]: [request_target.explanation_text]") + log_admin("[key_name(usr)] approved the request to delete an objective from [current]: [request_target.explanation_text]") + qdel(request_target) + if(REQUEST_WIN_OBJECTIVE) + message_admins("[key_name_admin(usr)] approved the victory request for an objective from [current]: [request_target.explanation_text]") + log_admin("[key_name(usr)] approved the victory request for an objective from [current]: [request_target.explanation_text]") + request_target.completed = TRUE + if(REQUEST_LOSE_OBJECTIVE) + message_admins("[key_name_admin(usr)] approved the defeat request for an objective from [current]: [request_target.explanation_text]") + log_admin("[key_name(usr)] approved the defeat request for an objective from [current]: [request_target.explanation_text]") + request_target.completed = FALSE + to_chat(current, "Your objective change request has been approved.") + do_edit_objectives_ambitions() + return + + else if (href_list["req_obj_deny"]) + var/datum/antagonist/antag_datum = locate(href_list["req_obj_deny"]) in antag_datums + if(QDELETED(antag_datum)) + do_edit_objectives_ambitions() + to_chat(usr, "No antag found.") + return + if(antag_datum.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid antag reference.") + return + var/uid = href_list["req_obj_id"] + var/list/requested_obj_change = LAZYACCESS(antag_datum.requested_objective_changes, uid) + if(!requested_obj_change) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid requested objective change reference.") + return + var/justification = stripped_multiline_input(usr, "Justify why you are denying this objective request change.", "Deny", memory, MAX_MESSAGE_LEN) + if(isnull(justification)) + return + if(!check_rights(R_ADMIN)) + return + if(QDELETED(antag_datum)) + to_chat(usr, "No antag found.") + do_edit_objectives_ambitions() + return + if(!LAZYACCESS(antag_datum.requested_objective_changes, uid)) + to_chat(usr, "Invalid requested objective change reference.") + do_edit_objectives_ambitions() + return + var/datum/objective/type_cast = requested_obj_change["target"] + var/objective_name = initial(type_cast.name) + message_admins("[key_name_admin(usr)] denied a requested [objective_name] objective from [current]: [requested_obj_change["text"]]") + log_admin("[key_name(usr)] denied a requested [objective_name] objective from [current]: [requested_obj_change["text"]]") + to_chat(current, "Your objective request has been denied for the following reason: [justification]") + antag_datum.remove_objective_change(uid) + do_edit_objectives_ambitions() + return + + else if (href_list["obj_panel_complete_toggle"]) + var/datum/antagonist/antag_datum = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(antag_datum)) + do_edit_objectives_ambitions() + to_chat(usr, "No antag found.") + return + if(antag_datum.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid antag reference.") + return + var/datum/objective/objective_to_toggle = locate(href_list["obj_panel_complete_toggle"]) in antag_datum.objectives + if(QDELETED(objective_to_toggle)) + to_chat(usr, "No objective found. Perhaps it was already deleted?") + do_edit_objectives_ambitions() + return + if(objective_to_toggle.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid objective reference.") + return + objective_to_toggle.completed = !objective_to_toggle.completed + message_admins("[key_name_admin(usr)] toggled the win state for [current]'s objective: [objective_to_toggle.explanation_text]") + log_admin("[key_name(usr)] toggled the win state for [current]'s objective: [objective_to_toggle.explanation_text]") + if(alert(usr, "Would you like to alert the player of the change?", "Deny objective", "Yes", "No") == "Yes") + to_chat(current, "[objective_to_toggle.completed ? "" : ""]Your objective status has changed!") + do_edit_objectives_ambitions() + return + + else if (href_list["obj_panel_delete"]) + var/datum/antagonist/antag_datum = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(antag_datum)) + do_edit_objectives_ambitions() + to_chat(usr, "No antag found.") + return + if(antag_datum.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid antag reference.") + return + var/datum/objective/objective_to_delete = locate(href_list["obj_panel_delete"]) in antag_datum.objectives + if(QDELETED(objective_to_delete)) + to_chat(usr, "No objective found. Perhaps it was already deleted?") + do_edit_objectives_ambitions() + return + if(objective_to_delete.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid objective reference.") + return + if(alert(usr, "Are you sure you want to delete this objective?", "Delete objective", "Yes", "No") != "Yes") + return + if(!check_rights(R_ADMIN)) + return + if(QDELETED(objective_to_delete)) + return + message_admins("[key_name_admin(usr)] removed an objective from [current]: [objective_to_delete.explanation_text]") + log_admin("[key_name(usr)] removed an objective from [current]: [objective_to_delete.explanation_text]") + qdel(objective_to_delete) + do_edit_objectives_ambitions() + return + + else if (href_list["obj_panel_edit"]) + var/datum/antagonist/antag_datum = locate(href_list["target_antag"]) in antag_datums + if(QDELETED(antag_datum)) + do_edit_objectives_ambitions() + to_chat(usr, "No antag found.") + return + if(antag_datum.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid antag reference.") + return + var/datum/objective/objective_to_edit = locate(href_list["obj_panel_edit"]) in antag_datum.objectives + if(QDELETED(objective_to_edit)) + to_chat(usr, "No objective found. Perhaps it was already deleted?") + do_edit_objectives_ambitions() + return + if(objective_to_edit.owner != src) + do_edit_objectives_ambitions() + to_chat(usr, "Invalid objective reference.") + return + var/explanation_before = objective_to_edit.explanation_text + objective_to_edit.admin_edit(usr) + if(QDELETED(objective_to_edit)) + return + message_admins("[key_name_admin(usr)] edited an objective from [current]:\ + Before: [explanation_before]\ + After: [objective_to_edit.explanation_text]") + log_admin("[key_name(usr)] edited an objective from [current]:\ + Before: [explanation_before]\ + After: [objective_to_edit.explanation_text]") + do_edit_objectives_ambitions() + return +//ambition end if(href_list["add_antag"]) add_antag_wrapper(text2path(href_list["add_antag"]),usr) @@ -470,38 +1393,16 @@ else target_antag = target - var/static/list/choices - if(!choices) - choices = list() +//ambition start + if(!GLOB.objective_choices) + populate_objective_choices() - var/list/allowed_types = list( - /datum/objective/assassinate, - /datum/objective/assassinate/once, - /datum/objective/maroon, - /datum/objective/debrain, - /datum/objective/protect, - /datum/objective/destroy, - /datum/objective/hijack, - /datum/objective/escape, - /datum/objective/survive, - /datum/objective/martyr, - /datum/objective/steal, - /datum/objective/download, - /datum/objective/nuclear, - /datum/objective/absorb, - /datum/objective/custom - ) + if(old_objective && GLOB.objective_choices[old_objective.name]) + def_value = old_objective.name - for(var/T in allowed_types) - var/datum/objective/X = T - choices[initial(X.name)] = T - - if(old_objective) - if(old_objective.name in choices) - def_value = old_objective.name - - var/selected_type = input("Select objective type:", "Objective type", def_value) as null|anything in choices - selected_type = choices[selected_type] + var/selected_type = input("Select objective type:", "Objective type", def_value) as null|anything in GLOB.objective_choices + selected_type = GLOB.objective_choices[selected_type] +//ambition end if (!selected_type) return @@ -529,6 +1430,12 @@ 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]") +//ambition start + if(href_list["ambition_panel"]) + do_edit_objectives_ambitions() + return +//ambition end + else if(href_list["traitor_class"]) var/static/list/choices if(!choices) @@ -613,6 +1520,11 @@ else if (href_list["obj_announce"]) announce_objectives() +//ambition start + if(href_list["ambition_panel"]) + do_edit_objectives_ambitions() + return +//ambition end //Something in here might have changed your mob if(self_antagging && (!usr || !usr.client) && current.client) @@ -816,3 +1728,7 @@ ..() mind.assigned_role = ROLE_PAI mind.special_role = "" + +//ambition start +#undef AMBITION_COOLDOWN_TIME +//ambition end diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index d56e78c9fb..d3dfe3d10e 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -25,7 +25,9 @@ to_chat(usr, "You seem to be selecting a mob that doesn't exist anymore.", confidential = TRUE) return - var/body = "Options for [M.key]" +//ambition start + var/list/body = list("Options for [M.key]") +//ambition end body += "Options panel for [M]" if(M.client) body += " played by [M.client] " @@ -125,6 +127,10 @@ body += "Subtle message | " // body += "Play sound to | " body += "Language Menu" +//ambition start + if(M.mind) + body += " | Objective-Ambition Menu" +//ambition end if (M.client) if(!isnewplayer(M)) @@ -206,7 +212,11 @@ body += "
    " body += "" - usr << browse(body, "window=adminplayeropts-[REF(M)];size=550x515") +//ambition start + var/datum/browser/popup = new(usr, "adminplayeropts-[REF(M)]", "Player Panel", nwidth = 550, nheight = 515) + popup.set_content(body.Join()) + popup.open() +//ambition end SSblackbox.record_feedback("tally", "admin_verb", 1, "Player Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index a8a7e51611..39377a1fe9 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2031,6 +2031,18 @@ var/mob/M = locate(href_list["HeadsetMessage"]) usr.client.admin_headset_message(M) +//ambition start + else if(href_list["ObjectiveRequest"]) + if(!check_rights(R_ADMIN)) + return + var/datum/mind/requesting_mind = locate(href_list["ObjectiveRequest"]) + if(!istype(requesting_mind) || QDELETED(requesting_mind)) + to_chat(usr, "This mind reference is no longer valid. It has probably since been destroyed.") + return + requesting_mind.do_edit_objectives_ambitions() + return +//ambition end + else if(href_list["reject_custom_name"]) if(!check_rights(R_ADMIN)) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index f232142902..6bbee74be9 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -25,6 +25,10 @@ GLOBAL_LIST_EMPTY(antagonists) var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default. var/threat = 0 // Amount of threat this antag poses, for dynamic mode +//ambition start + /// Lazy list for antagonists to request the admins objectives. + var/list/requested_objective_changes +//ambition end var/show_to_ghosts = FALSE // Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors var/list/skill_modifiers @@ -35,8 +39,9 @@ GLOBAL_LIST_EMPTY(antagonists) /datum/antagonist/Destroy() GLOB.antagonists -= src - if(owner) - LAZYREMOVE(owner.antag_datums, src) +//ambition start + owner?.do_remove_antag_datum(src) +//ambition end owner = null return ..() @@ -146,7 +151,9 @@ GLOBAL_LIST_EMPTY(antagonists) remove_innate_effects() clear_antag_moodies() if(owner) - LAZYREMOVE(owner.antag_datums, src) +//ambition start + owner.do_remove_antag_datum(src) +//ambition end for(var/A in skill_modifiers) owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type)) if(!LAZYLEN(owner.antag_datums)) @@ -308,3 +315,33 @@ GLOBAL_LIST_EMPTY(antagonists) else return ..() + +///Clears change requests from deleted objectives to avoid broken references. +/datum/antagonist/proc/clean_request_from_del_objective(datum/objective/source, force) + var/objective_reference = REF(source) + for(var/uid in requested_objective_changes) + var/list/change_request = requested_objective_changes[uid] + if(change_request["target"] != objective_reference) + continue + LAZYREMOVE(requested_objective_changes, uid) + + +/datum/antagonist/proc/add_objective_change(uid, list/additions) + LAZYADD(requested_objective_changes, uid) + var/datum/objective/request_target = additions["target"] + if(!ispath(request_target)) + request_target = locate(request_target) in objectives + if(istype(request_target)) + RegisterSignal(request_target, COMSIG_PARENT_QDELETING, .proc/clean_request_from_del_objective) + requested_objective_changes[uid] = additions + + +/datum/antagonist/proc/remove_objective_change(uid) + if(!LAZYACCESS(requested_objective_changes, uid)) + return + var/datum/objective/request_target = requested_objective_changes[uid]["target"] + if(!ispath(request_target)) + request_target = locate(request_target) in objectives + if(istype(request_target)) + UnregisterSignal(request_target, COMSIG_PARENT_QDELETING) + LAZYREMOVE(requested_objective_changes, uid) diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 208fefee70..4e68e27583 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -65,7 +65,9 @@ user.copy_languages(target, LANGUAGE_ABSORB) if(target.mind && user.mind)//if the victim and user have minds - target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes. +//ambition start + to_chat(user, "[target.mind.show_memory()]") //I can read your mind, kekeke. Output all their notes. +//ambition end //Some of target's recent speech, so the changeling can attempt to imitate them better. //Recent as opposed to all because rounds tend to have a LOT of text. diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index a18523069e..4fffbe1f2e 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -49,7 +49,10 @@ cult_team = new_team /datum/antagonist/cult/proc/add_objectives() - objectives |= cult_team?.objectives +//ambition start + if(cult_team) + objectives |= cult_team.objectives +//ambition end /datum/antagonist/cult/Destroy() QDEL_NULL(communion) diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index 2b1c2de17a..e9bf3c5d49 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -2,7 +2,10 @@ ..() //Mind updates sync_mind() - mind.show_memory(src, 0) +//ambition start + if(mind.memory || mind.antag_datums) + to_chat(src, "[mind.show_memory()]") +//ambition end //Round specific stuff if(SSticker.mode) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 8a71bb72c4..b92afc3516 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -440,7 +440,11 @@ set category = "IC" set desc = "View your character's notes memory." if(mind) - mind.show_memory(src) +//ambition start + var/datum/browser/popup = new(src, "memory", "Memory and Notes") + popup.set_content(mind.show_memory()) + popup.open() +//ambition end else to_chat(src, "You don't have a mind datum for some reason, so you can't look at your notes, if you had any.")