Files
Bubberstation/code/modules/capture_the_flag/ctf_controller.dm
SkyratBot b557e89855 [MIRROR] More standardization for ghost notifications (READY) [MDB IGNORE] (#25104)
* More standardization for ghost notifications (READY) (#79596)

## About The Pull Request
I'm still not satisfied with how ghost notifications work. This gives
every notification with a source (99% of all notifications, in other
words) a link to jump/orbit. Currently, notifications with "play"
interactions would only get the interact link, so jumping to the source
was pretty annoying.

It removes posting the entire message in the alert tooltip, as some got
pretty lengthy and it didn't seem to fit. To replace this, they will
always use headers

After:

![image](https://github.com/tgstation/tgstation/assets/42397676/debfce52-3627-4a43-8663-33d61d893161)

![image](https://github.com/tgstation/tgstation/assets/42397676/01f299ae-dc6a-45f8-a97a-cb2c815088b2)

![image](https://github.com/tgstation/tgstation/assets/42397676/99567376-063e-458e-af2a-2dd4306747cc)

NOTIFY_JUMP and NOTIFY_ORBIT have been merged, since the only difference
seems to be whether it's a turf. The result shaves off some redundant
lines of code, since most-every usage of notify_ghosts uses
NOTIFY_ORBIT.
## Why It's Good For The Game
More standardization for the ghost notification system. Adds a few alert
headers that never had them. All in all, makes it easier for creators to
throw alerts at ghosts
## Changelog
🆑
qol: Nearly every ghost alert should now feature a "VIEW" button, even
those with click interaction.
del: Ghost alerts no longer show the entire message in the tooltip,
instead have been replaced with titles.
/🆑

* More standardization for ghost notifications (READY)

* Modular

* Update outpost_of_cogs.dm

---------

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
2023-11-19 11:25:32 -05:00

243 lines
10 KiB
Plaintext

#define CTF_DEFAULT_RESPAWN 15 SECONDS
#define CTF_INSTAGIB_RESPAWN 5 SECONDS
///The CTF controller acts as a manager for an individual CTF game, each CTF game should have its own, the controller should handle all game-wide functionality.
/datum/ctf_controller
///The ID associated with this CTF game.
var/game_id = CTF_GHOST_CTF_GAME_ID
///Whether or not this CTF game is running.
var/ctf_enabled = FALSE
///List of all team_datums participating in this game.
var/list/datum/ctf_team/teams = list()
///List of all control points used by the game, if they exist.
var/list/obj/machinery/ctf/control_point/control_points = list()
///List of all barricades that have been destroyed during this CTF game.
var/list/obj/effect/ctf/dead_barricade/barricades = list()
///How long till players who die can respawn.
var/respawn_cooldown = CTF_DEFAULT_RESPAWN
///How many points a team needs to win.
var/points_to_win = 3
///The text shown once this CTF match ends.
var/victory_rejoin_text = "Teams have been cleared. Click on the machines to vote to begin another round."
///When this CTF match ends should it automatically restart.
var/auto_restart = FALSE
///Weather or not instagib mode has been enabled.
var/instagib_mode = FALSE
/datum/ctf_controller/New(game_id)
. = ..()
src.game_id = game_id
GLOB.ctf_games[game_id] = src
/datum/ctf_controller/Destroy(force, ...)
GLOB.ctf_games[game_id] = null
return ..()
/datum/ctf_controller/proc/toggle_ctf()
if(!ctf_enabled)
start_ctf()
return TRUE
else
stop_ctf()
return FALSE
/datum/ctf_controller/proc/start_ctf()
if(ctf_enabled)
return //CTF is already running, don't notify ghosts again
ctf_enabled = TRUE
for(var/team in teams)
var/obj/machinery/ctf/spawner/spawner = teams[team].spawner
notify_ghosts(
"[spawner.name] has been activated!",
source = spawner,
header = "CTF has been activated",
)
/datum/ctf_controller/proc/stop_ctf()
ctf_enabled = FALSE
clear_control_points()
respawn_barricades()
for(var/team in teams)
teams[team].reset_team()
///Unloading CTF removes the map entirely and allows for a new map to be loaded in its place.
/datum/ctf_controller/proc/unload_ctf()
if(game_id != CTF_GHOST_CTF_GAME_ID)
return //At present we only support unloading standard centcom ctf, if we intend to support ctf unloading elsewhere then this proc will need to be ammended.
stop_ctf()
new /obj/effect/landmark/ctf(get_turf(GLOB.ctf_spawner))
///Some CTF maps may require alternate rulesets, this proc is called by the medisim spawners and CTF maploading.
/datum/ctf_controller/proc/setup_rules(
points_to_win = 3,
victory_rejoin_text = "Teams have been cleared. Click on the machines to vote to begin another round.",
auto_restart = FALSE,
)
src.points_to_win = points_to_win
src.victory_rejoin_text = victory_rejoin_text
src.auto_restart = auto_restart
///Add an additional team to the current CTF game.
/datum/ctf_controller/proc/add_team(obj/machinery/ctf/spawner/spawner)
if(!isnull(teams[spawner.team]))
return //CTF currently only supports one spawn point per team, if you want to add a map that uses more you'll need to modify add_team/remove_team and turn the spawner var on the team itself into a list
teams[spawner.team] = new /datum/ctf_team(spawner)
///Called when a spawner is deleted, removes the team from this datum.
/datum/ctf_controller/proc/remove_team(team_color)
if(isnull(teams[team_color]))
return //Cannot delete a team that doesn't exist
QDEL_NULL(teams[team_color])
teams -= team_color
///Adds a player and a reference to their player component to the corresponding team.
/datum/ctf_controller/proc/add_player(team_color, ckey, datum/component/ctf_player/new_team_member)
teams[team_color].team_members[ckey] = new_team_member
///Returns a reference to a players component (if it exists) when provided with a player's ckey
/datum/ctf_controller/proc/get_player_component(team_color, ckey)
return teams[team_color].team_members[ckey]
///Returns a list of all players in the provided team.
/datum/ctf_controller/proc/get_players(team_color)
return teams[team_color].team_members
///Returns a list of all players in all teams.
/datum/ctf_controller/proc/get_all_players()
var/list/players = list()
for(var/team in teams)
players += get_players(team)
return players
///Identifies if the provided team is a valid team to join for the provided player.
/datum/ctf_controller/proc/team_valid_to_join(team_color, mob/user)
var/list/friendly_team_members = get_players(team_color)
for(var/team in teams)
if(team == team_color)
continue
var/list/enemy_team_members = get_players(team)
if(user.ckey in enemy_team_members)
to_chat(user, span_warning("No switching teams while the round is going!"))
return FALSE
else if(friendly_team_members.len > enemy_team_members.len)
to_chat(user, span_warning("[team_color] has more team members than [team]! Try joining [team] team to even things up."))
return FALSE
return TRUE
///Called when a flag is captured by the provided team. Messages players telling them who scored a point and if points are high enough declares victory.
/datum/ctf_controller/proc/capture_flag(team_color, mob/living/user, team_span, obj/item/ctf_flag/flag)
teams[team_color].score_points(flag.flag_value)
message_all_teams("<span class='userdanger [team_span]'>[user.real_name] has captured \the [flag], scoring a point for [team_color] team! They now have [get_points(team_color)]/[points_to_win] points!</span>")
if(get_points(team_color) >= points_to_win)
victory(team_color)
///Called when points are scored at a control point. Messages players telling them when a team is half way to winning and if points are high enough declares victory.
/datum/ctf_controller/proc/control_point_scoring(team_color, points)
teams[team_color].score_points(points)
if(get_points(team_color) == points_to_win/2)
message_all_teams("<span class='userdanger [teams[team_color].team_span]'>[team_color] is half way to winning! they only need [points_to_win/2] more points to win!</span>")
if(get_points(team_color) >= points_to_win)
victory(team_color)
///Returns the current amount of points the provided team has.
/datum/ctf_controller/proc/get_points(team_color)
return teams[team_color].points
///Ends the current CTF game and informs all players which team won. Restarts CTF if auto_restart is enabled.
/datum/ctf_controller/proc/victory(winning_team)
ctf_enabled = FALSE
clear_control_points()
respawn_barricades()
var/datum/ctf_team/winning_ctf_team = teams[winning_team]
for(var/team in teams)
var/datum/ctf_team/ctf_team = teams[team]
ctf_team.message_team("<span class='narsie [winning_ctf_team.team_span]'>[winning_team] team wins!</span>")
ctf_team.message_team(span_userdanger(victory_rejoin_text))
ctf_team.reset_team()
if(auto_restart)
toggle_id_ctf(null, game_id, TRUE)
///Marks all control points as neutral, called when a CTF match ends.
/datum/ctf_controller/proc/clear_control_points()
for(var/obj/machinery/ctf/control_point/control_point in control_points)
control_point.clear_point()
///Respawns all barricades destroyed during the current CTF game, called when the match ends.
/datum/ctf_controller/proc/respawn_barricades()
for(var/obj/effect/ctf/dead_barricade/barricade in barricades)
barricade.respawn()
barricades = list()
///Sends a message to all players in all CTF teams in this game.
/datum/ctf_controller/proc/message_all_teams(message)
for(var/team in teams)
teams[team].message_team(message)
///Enables and disables instagib mode in this game. During instagib mode respawns are faster, players are faster and people die faster (instant).
/datum/ctf_controller/proc/toggle_instagib_mode()
if(!instagib_mode) // Normal > Instagib
for(var/team in teams)
var/datum/ctf_team/ctf_team = teams[team]
ctf_team.spawner.ctf_gear = ctf_team.spawner.instagib_gear
respawn_cooldown = CTF_INSTAGIB_RESPAWN
else //Instagib > Normal
for(var/team in teams)
var/datum/ctf_team/ctf_team = teams[team]
ctf_team.spawner.ctf_gear = ctf_team.spawner.default_gear
respawn_cooldown = CTF_DEFAULT_RESPAWN
instagib_mode = !instagib_mode
///A datum that holds details about individual CTF teams, any team specific CTF functionality should be implimented here.
/datum/ctf_team
///Reference to the spawn point that this team uses.
var/obj/machinery/ctf/spawner/spawner
///What color this team is, also acts as a team name.
var/team_color
///Total score that this team currently has.
var/points = 0
///Assoc list containing a list of team members ckeys and the associated ctf_player components.
var/list/team_members = list()
///Span used for messages sent to this team.
var/team_span = ""
/datum/ctf_team/New(obj/machinery/ctf/spawner/spawner)
. = ..()
src.spawner = spawner
team_color = spawner.team
team_span = spawner.team_span
///If the team is destroyed all players in that team need their componenet removed.
/datum/ctf_team/Destroy(force, ...)
for(var/player in team_members)
var/datum/component/ctf_player/ctf_player = team_members[player]
ctf_player.end_game()
return ..()
///Increases this teams number of points by the provided amount.
/datum/ctf_team/proc/score_points(points_scored)
points += points_scored
///Resets this teams score and clears its member list. All members will be dusted and have their player componenet removed.
/datum/ctf_team/proc/reset_team()
points = 0
for(var/player in team_members)
var/datum/component/ctf_player/ctf_player = team_members[player]
ctf_player.end_game()
team_members = list()
///Sends a message to all players in this team.
/datum/ctf_team/proc/message_team(message)
for(var/player in team_members)
var/datum/component/ctf_player/ctf_player = team_members[player]
ctf_player.send_message(message)
///Creates a CTF game with the provided teeam ID then returns a reference to the new controller. If a controller already exists provides a reference to it.
/proc/create_ctf_game(game_id)
if(GLOB.ctf_games[game_id])
return GLOB.ctf_games[game_id]
var/datum/ctf_controller/CTF = new(game_id)
return CTF
#undef CTF_DEFAULT_RESPAWN
#undef CTF_INSTAGIB_RESPAWN