Initial commit
This commit is contained in:
439
scripting/fartsys_clockwork_chaos.sp
Normal file
439
scripting/fartsys_clockwork_chaos.sp
Normal file
@@ -0,0 +1,439 @@
|
||||
// Clockwork Castletown v1.0.0 by Professor Fartsalot for the FireHost Redux Community
|
||||
#include <clientprefs>
|
||||
#include <fcc_helper>
|
||||
#include <morecolors>
|
||||
#include <regex>
|
||||
#include <sdktools>
|
||||
#include <sourcemod>
|
||||
#include <tf2_stocks>
|
||||
#pragma newdecls required
|
||||
#pragma semicolon 1
|
||||
static char PLUGIN_VERSION[8] = "1.0.5";
|
||||
|
||||
public Plugin myinfo = {
|
||||
name = "Fartsy's Clockwork Chaos - Framework",
|
||||
author = "Fartsy",
|
||||
description = "Framework for Fartsy's Clockwork Chaos (PL Mods)",
|
||||
version = PLUGIN_VERSION,
|
||||
url = "https://forums.firehostredux.com"
|
||||
};
|
||||
|
||||
public void OnPluginStart() {
|
||||
FccLogger(1, "####### STARTUP SEQUENCE INITIATED... PREPARE FOR THE END TIMES #######");
|
||||
RegisterAndPrecacheAllFiles();
|
||||
RegisterAllCommands();
|
||||
SetupCoreData();
|
||||
CPrintToChatAll("{darkred}Plugin Reloaded. If you do not hear music, please do !sounds and configure your preferences.");
|
||||
// cvarSNDDefault = CreateConVar("sm_fartsyscc_sound", "3", "Default sound for new users, 3 = Everything, 2 = Sounds Only, 1 = Music Only, 0 = Nothing");
|
||||
// SetCookieMenuItem(FartsysSNDSelected, 0, "Fartsys Clockwork Chaos Sound Preferences");
|
||||
Format(LoggerInfo, sizeof(LoggerInfo), "####### STARTUP COMPLETE (v%s) #######", PLUGIN_VERSION);
|
||||
FccLogger(1, LoggerInfo);
|
||||
}
|
||||
|
||||
// Music system, see FartsysAss.sp:46
|
||||
public void OnGameFrame() {
|
||||
/* if (core.tickMusic) {
|
||||
core.ticksMusic++;
|
||||
if (core.ticksMusic >= core.refireTime) {
|
||||
if (core.shouldStopMusic) {
|
||||
for (int i = 1; i <= MaxClients; i++) {
|
||||
StopSound(i, core.SNDCHAN, core.cachedPath);
|
||||
core.shouldStopMusic = false;
|
||||
}
|
||||
}
|
||||
core.songName = BGMArray[core.BGMINDEX].songName;
|
||||
core.refireTime = BGMArray[core.BGMINDEX].refireTime;
|
||||
core.ticksMusic = (core.tickOffset ? BGMArray[core.BGMINDEX].ticksOffset : 0);
|
||||
CustomSoundEmitter(BGMArray[core.BGMINDEX].realPath, BGMArray[core.BGMINDEX].SNDLVL, true, 1, 1.0, 100);
|
||||
CreateTimer(1.0, SyncMusic);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
// Restart music for the new client
|
||||
public Action RefireMusicForClient(Handle timer, int client) {
|
||||
if (IsValidClient(client)) {
|
||||
// if (GetClientTeam(client) == 0) CreateTimer(1.0, RefireMusicForClient, client);
|
||||
// else if (GetClientTeam(client) == 2) CSEClient(client, BGMArray[core.BGMINDEX].realPath, BGMArray[core.BGMINDEX].SNDLVL, true, 1, 1.0, 100);
|
||||
}
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
// Queue music for new clients, also track their health.
|
||||
public void OnClientPostAdminCheck(int client) {
|
||||
// if (!IsFakeClient(client) && core.bgmPlaying) CreateTimer(1.0, RefireMusicForClient, client);
|
||||
int steamID = GetSteamAccountID(client);
|
||||
if (!steamID || steamID <= 10000) return;
|
||||
// if (!core.bgmPlaying) SetupMusic(GetRandomInt(1, 4)); //Change these variables, I have no idea how this should work at the moment.
|
||||
}
|
||||
|
||||
// Now that command definitions are done, lets make some things happen.
|
||||
public void OnMapStart() {
|
||||
// CreateTimer(1.0, SelectAdminTimer);
|
||||
// FastFire("OnUser1 rain:Alpha:0:0.0:1");
|
||||
// sudo(1002);
|
||||
}
|
||||
|
||||
// Adverts for round information
|
||||
public Action PerformMatchAdverts(Handle timer) {
|
||||
// if (core.isMatch) {
|
||||
char buffer[16];
|
||||
char tbuffer[16];
|
||||
char HintText[256];
|
||||
// int sPos = RoundToFloor(core.ticksMusic / 66.6666666666);
|
||||
// int tPos = RoundToFloor(core.refireTime / 66.6666666666);
|
||||
// Format(buffer, 16, "%02d:%02d", sPos / 60, sPos % 60);
|
||||
// Format(tbuffer, 16, "%02d:%02d", tPos / 60, tPos % 60);
|
||||
// Format(HintText, sizeof(HintText), (bombState[0].isMoving ? "Payload: MOVING (%i/%i) | !sacpoints: %i/%i \n Music: %s (%s/%s)" : bombState[0].isReady ? "Payload: READY (%i/%i) | !sacpoints: %i/%i \n Music: %s (%s/%s)" : "Payload: PREPARING (%i/%i) | !sacpoints: %i/%i \n Music: %s (%s/%s)"), bombState[0].state, bombState[0].stateMax, core.sacPoints, core.sacPointsMax, core.songName, buffer, tbuffer);
|
||||
// CreateTimer(2.5, PerformMatchAdverts);
|
||||
for (int i = 1; i <= MaxClients; i++) {
|
||||
if (IsValidClient(i)) {
|
||||
PrintHintText(i, HintText);
|
||||
StopSound(i, SNDCHAN_STATIC, "UI/hint.wav");
|
||||
}
|
||||
}
|
||||
//}
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
// Command: Get current song
|
||||
public Action Command_GetCurrentSong(int client, int args) {
|
||||
/*char buffer[16];
|
||||
char tbuffer[16];
|
||||
int sPos = RoundToFloor(core.ticksMusic / 66.6666666666);
|
||||
int tPos = RoundToFloor(core.refireTime / 66.6666666666);
|
||||
Format(buffer, 16, "%02d:%02d", sPos / 60, sPos % 60);
|
||||
Format(tbuffer, 16, "%02d:%02d", tPos / 60, tPos % 60);
|
||||
CPrintToChat(client, "The current song is: {limegreen}%s {orange}(%s / %s)", core.songName, buffer, tbuffer);*/
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Command: Return the client to spawn
|
||||
public Action Command_Return(int client, int args) {
|
||||
if (!IsPlayerAlive(client)) {
|
||||
CPrintToChat(client, "{red}[Core] You must be alive to use this command...");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
char name[128];
|
||||
GetClientName(client, name, sizeof(name));
|
||||
CPrintToChatAll("{darkviolet}[{forestgreen}CORE{darkviolet}] {white}Client {red}%s {white}began casting {darkviolet}/return{white}.", name);
|
||||
// CustomSoundEmitter(SFXArray[41], 65, false, 0, 1.0, 100);
|
||||
CreateTimer(5.0, ReturnClient, client);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Return the client to spawn
|
||||
public Action ReturnClient(Handle timer, int clientID) {
|
||||
// TeleportEntity(clientID, Return, NULL_VECTOR, NULL_VECTOR);
|
||||
// CSEClient(clientID, SFXArray[42], 65, false, 0, 1.0, 100);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Join us on Discord!
|
||||
public Action Command_Discord(int client, int args) {
|
||||
CPrintToChat(client, "{darkviolet}[{forestgreen}CORE{darkviolet}] {white}Our Discord server URL is {darkviolet}https://discord.com/invite/HjQsDy6e2H{white}.");
|
||||
ShowMOTDPanel(client, "FireHostRedux Discord", "https://discord.com/invite/HjQsDy6e2H", MOTDPANEL_TYPE_URL);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Check who died by what and announce it to chat.
|
||||
/*
|
||||
public Action EventDeath(Event Spawn_Event, const char[] Spawn_Name, bool Spawn_Broadcast) {
|
||||
int client = GetClientOfUserId(Spawn_Event.GetInt("userid"));
|
||||
int attacker = GetClientOfUserId(Spawn_Event.GetInt("attacker"));
|
||||
char name[64];
|
||||
char weapon[32];
|
||||
Format(name, sizeof(name), attacker == 0 ? "[INTENTIONAL GAME DESIGN]" : "%N", IsValidClient(attacker) ? client : attacker);
|
||||
Spawn_Event.GetString("weapon", weapon, sizeof(weapon));
|
||||
if (0 < client <= MaxClients && IsClientInGame(client)) {
|
||||
int damagebits = Spawn_Event.GetInt("damagebits");
|
||||
if (IsValidClient(attacker) && core.sacrificedByClient) SacrificeClient(client, attacker, core.bombReset);
|
||||
if (!attacker) {
|
||||
switch (damagebits){
|
||||
case 1:{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (attacker != client) {
|
||||
if (!FB_Database) return Plugin_Handled;
|
||||
char query[256];
|
||||
int steamID = (IsValidClient(attacker) ? GetSteamAccountID(attacker) : GetSteamAccountID(client));
|
||||
Format(query, sizeof(query), IsValidClient(attacker) && !StrEqual(weapon, "world") ? "UPDATE ass_activity SET kills = kills +1, killssession = killssession + 1, lastkilledname = '%s', lastweaponused = '%s' WHERE steamid = %i;" : !StrEqual(weapon, "world") && !IsValidClient(attacker) ? "UPDATE ass_activity SET deaths = deaths + 1, deathssession = deathssession + 1, killedbyname = '%s', killedbyweapon = '%s' WHERE steamid = %i;" : "RETURN", name, weapon, steamID);
|
||||
if (StrEqual(query, "RETURN")) return Plugin_Handled;
|
||||
FB_Database.Query(Database_FastQuery, query);
|
||||
}
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}*/
|
||||
|
||||
// Create a temp entity and fire an input - ADVANCED Mode
|
||||
public Action FastFire(char[] input) {
|
||||
int entity = CreateEntityByName("info_target");
|
||||
if (!IsValidEdict(entity)) return Plugin_Handled;
|
||||
DispatchSpawn(entity);
|
||||
ActivateEntity(entity);
|
||||
SetVariantString(input);
|
||||
AcceptEntityInput(entity, "AddOutput");
|
||||
AcceptEntityInput(entity, "FireUser1");
|
||||
CreateTimer(0.0, DeleteEdict, entity);
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
// Custom sound emitter, I don't know how many fucking times I've rewritten this! See potato.sp
|
||||
// int flags:
|
||||
// SND_NOFLAGS= 0, /**< Nothing */
|
||||
// SND_CHANGEVOL = 1, /**< Change sound volume */
|
||||
// SND_CHANGEPITCH = 2, /**< Change sound pitch */
|
||||
// SND_STOP = 3, /**< Stop the sound */
|
||||
// SND_SPAWNING = 4, /**< Used in some cases for ambients */
|
||||
// SND_DELAY = 5, /**< Sound has an initial delay */
|
||||
// SND_STOPLOOPING = 6, /**< Stop looping all sounds on the entity */
|
||||
// SND_SPEAKER = 7, /**< Being played by a mic through a speaker */
|
||||
// SND_SHOULDPAUSE = 8 /**< Pause if game is paused */
|
||||
void CustomSoundEmitter(char[] sndName, int TSNDLVL, bool isBGM, int flags, float vol, int pitch) {
|
||||
for (int i = 1; i <= MaxClients; i++) {
|
||||
if (!IsValidClient(i)) continue;
|
||||
// if (isBGM && (soundPreference[i] == 1 || soundPreference[i] == 3) || !isBGM && soundPreference[i] >= 2) EmitSoundToClient(i, sndName, _, core.SNDCHAN, TSNDLVL, flags, vol, pitch, _, _, _, _, _);
|
||||
}
|
||||
}
|
||||
// Play sound to client. Ripped straight from potato. Allows us to play sounds directly to people when they join.
|
||||
void CSEClient(int client, char[] sndName, int TSNDLVL, bool isBGM, int flags, float vol, int pitch) {
|
||||
if (!IsValidClient(client)) return;
|
||||
// if (isBGM && (soundPreference[client] == 1 || soundPreference[client] == 3) || !isBGM && soundPreference[client] >= 2) EmitSoundToClient(client, sndName, _, core.SNDCHAN, TSNDLVL, flags, vol, pitch, _, _, _, _, _);
|
||||
}
|
||||
|
||||
// Remove edict allocated by temp entity
|
||||
public Action DeleteEdict(Handle timer, any entity) {
|
||||
if (IsValidEdict(entity)) RemoveEdict(entity);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
// Log debug info
|
||||
void FccLogger(int logLevel, char[] logData) {
|
||||
switch (logLevel) {
|
||||
case 0: {
|
||||
LogMessage("[DEBUG]: %s", logData);
|
||||
}
|
||||
case 1: {
|
||||
LogMessage("[INFO]: %s", logData);
|
||||
}
|
||||
case 2: {
|
||||
LogMessage("[WARN]: %s", logData);
|
||||
}
|
||||
case 3: {
|
||||
LogMessage("[ERROR]: %s", logData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Operator, core of the entire map
|
||||
public Action Command_Operator(int args) {
|
||||
char arg1[16];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
int x = StringToInt(arg1);
|
||||
PrintToServer("Directly calling sudo with %i", args);
|
||||
sudo(x);
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
void sudo(int task) {
|
||||
Format(LoggerDbg, sizeof(LoggerDbg), "Calling sudo with %i", task);
|
||||
FccLogger(0, LoggerDbg);
|
||||
switch (task) {
|
||||
// Match End, pick winning team based on distance
|
||||
case 0: {
|
||||
FastFire(PLR > PLB ? "OnUser1 WinRed:RoundWin::0.0:1" : PLR < PLB ? "OnUser1 WinBlu:RoundWin::0.0:1" : "OnUser1 WinStalemate:RoundWin::0.0:1");
|
||||
return;
|
||||
}
|
||||
// Setup Begin
|
||||
case 1: {
|
||||
FccLogger(0, "Setup beginning....");
|
||||
FastFire("OnUser1 PL1.TrackTrain:Stop::0.5:1");
|
||||
FastFire("OnUser1 UI.PLCore:SwitchOverlay:1::0.0:1");
|
||||
FastFire("OnUser1 UI.PLBlue00:SwitchOverlay:1::0.0:1");
|
||||
FastFire("OnUser1 UI.PLBlue01:SwitchOverlay:1::0.0:1");
|
||||
FastFire("OnUser1 UI.PLBlue02:SwitchOverlay:1::0.0:1");
|
||||
if(RecedeTimer != INVALID_HANDLE) KillTimer(RecedeTimer);
|
||||
isMatch = true;
|
||||
PLB = 0;
|
||||
PLL = 0;
|
||||
PLM = false;
|
||||
PLR = 0;
|
||||
PLT = "N/A";
|
||||
PLRL = 20;
|
||||
BLC = false;
|
||||
REC = false;
|
||||
RECEDE = false;
|
||||
CreateTimer(0.5, PayloadUpdateTimer);
|
||||
CPrintToChatAll("{darkgreen} Clockwork Castletown ({lime}v%s{darkgreen}) - Escort the crystal the longest distance to win!", PLUGIN_VERSION);
|
||||
return;
|
||||
}
|
||||
// Setup End / round start
|
||||
case 2: {
|
||||
FccLogger(1, "Match started!");
|
||||
return;
|
||||
}
|
||||
case 3: {
|
||||
// Payload started moving by blue
|
||||
PLT = "BLU";
|
||||
PLM = true;
|
||||
FastFire("OnUser1 PL1.TrackTrain:StartForward::0.0:1");
|
||||
KillTimer(RecedeTimer);
|
||||
RecedeTimer = INVALID_HANDLE;
|
||||
RECEDE = false;
|
||||
return;
|
||||
}
|
||||
// Payload started moving by red
|
||||
case 4: {
|
||||
PLT = "RED";
|
||||
PLM = true;
|
||||
FastFire("OnUser1 PL1.TrackTrain:StartBackward::0.0:1");
|
||||
KillTimer(RecedeTimer);
|
||||
RecedeTimer = INVALID_HANDLE;
|
||||
RECEDE = false;
|
||||
return;
|
||||
}
|
||||
// Payload stopped moving
|
||||
case 5: {
|
||||
PLT = "NEUTRAL";
|
||||
PLM = false;
|
||||
FastFire("OnUser1 PL1.TrackTrain:Stop::0.0:1");
|
||||
RecedeTimer = CreateTimer(45.0, BeginRecede, PLL);
|
||||
return;
|
||||
}
|
||||
// Payload on blue side of map
|
||||
case 6: {
|
||||
PLL = 2;
|
||||
return;
|
||||
}
|
||||
// Payload red side of map
|
||||
case 7: {
|
||||
PLL = 1;
|
||||
return;
|
||||
}
|
||||
// Point 1 capture (this would be 75% capture from blue's perspective)
|
||||
case 8: {
|
||||
FastFire("OnUser1 PL4.CP:SetOwner:3:0.0:1"); //Change this to instead enable a capture area, stop the payload and disable capture area while the CP is capturing.. Re enable it after 15s. Check if blue is pushing and not receding.
|
||||
return;
|
||||
}
|
||||
// Point -1 capture (this would be 75% capture from red's perspective)
|
||||
case 9: {
|
||||
FastFire("OnUser1 PL2.CP:SetOwner:2:0.0:1"); // see case 8
|
||||
return;
|
||||
}
|
||||
// Op codes for payload progression
|
||||
case 10: {
|
||||
PrintToServer("Got 10, PLL %i", PLL);
|
||||
switch(PLL){
|
||||
case 1:{
|
||||
PrintToChatAll("DEBUG: Checking if RECEDE: %b STREQUAL PLT RED: %b, PLB %i < PLPOS %i PLRL: %i...", RECEDE, StrEqual(PLT, "RED"), PLB, PLPOS[PLRL], PLRL);
|
||||
if(RECEDE || StrEqual(PLT, "RED")) PLRL--; //If it's receding back to mid or being pushed by red back to mid... This is occuring on red's side of the map.
|
||||
else PLRL++;//It's moving forward by blue to red.
|
||||
if(PLB < PLPOS[PLRL]){
|
||||
PLB+=5;
|
||||
FastFire("OnUser1 test:scorebluepoints::0.0:1");
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 2:{
|
||||
PrintToChatAll("DEBUG: Checking if RECEDE: %b STREQUAL PLT BLU: %b, PLR %i < PLPOS %i PLRL: %i...", RECEDE, StrEqual(PLT, "BLU"), PLR, PLPOS[PLRL], PLRL);
|
||||
if(RECEDE || StrEqual(PLT, "BLU")) PLRL++; //If it's receding back to mid or being pushed by blu back to mid... this is occuring on blu's side of the map.
|
||||
else PLRL--; //It's moving forward by red to blue.
|
||||
if(PLR < PLPOS[PLRL]){
|
||||
PLR+=5;
|
||||
FastFire("OnUser1 test:scoreredpoints::0.0:1");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// PrintToChatAll("BLU %i% RED %i%, PLM: %b, PLL: %i, PLT: %s", PLB, PLR, PLM, PLL, PLT);
|
||||
return;
|
||||
}
|
||||
//Blu reached end of track (FF)
|
||||
case 11: {
|
||||
//FastFire("OnUser1 WinBlu:RoundWin::0.0:1"); //Change this to instead enable a capture area, stop the payload, and disable payload capture area while the CP is capturing... Victory after 15s (onCapTeam2)
|
||||
}
|
||||
//Red reached end of track (00)
|
||||
case 12:{
|
||||
//FastFire("OnUser1 WinRed:RoundWin::0.0:1"); //Change this, see case 11...
|
||||
}
|
||||
//Payload reached neutral point
|
||||
case 13:{
|
||||
PLT = "N/A";
|
||||
PLL = 0;
|
||||
PLM = false;
|
||||
RECEDE = false;
|
||||
PLRL = 20;
|
||||
FastFire("OnUser1 PL1.TrackTrain:Stop::0.0:1");
|
||||
}
|
||||
//Debug
|
||||
case 42:{
|
||||
PLR+=5;
|
||||
return;
|
||||
}
|
||||
case 69:{
|
||||
PLB +=5;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recede payload after 45 seconds
|
||||
public Action BeginRecede(Handle timer, int side) {
|
||||
if (side > 0) FastFire(side == 1 ? "OnUser1 PL1.TrackTrain:StartBackward::0.0:1" : "OnUser1 PL1.TrackTrain:StartForward::0.0:1");
|
||||
RECEDE = true;
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
// Show payload state
|
||||
public Action PayloadUpdateTimer(Handle timer){
|
||||
if(!isMatch) return Plugin_Stop;
|
||||
CCH[30].BLU = BLC ? "hud/cconflict/cc_blu0B" : "hud/cconflict/cc_blu0A";
|
||||
CCH[10].RED = REC ? "hud/cconflict/cc_red20" : "hud/cconflict/cc_red1F";
|
||||
char state[64];
|
||||
Format(state, sizeof(state), StrEqual(PLT, "BLU") ? CCH[PLRL].BLU : StrEqual(PLT, "RED") ? CCH[PLRL].RED : RECEDE ? CCH[PLRL].NEUTRAL : CCH[PLRL].IDLE);
|
||||
ShowOverlayAll(state);
|
||||
PrintToServer(state);
|
||||
CreateTimer(0.5, PayloadUpdateTimer);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
// Recede payload after 45 seconds
|
||||
public Action BeginRecede(Handle timer, int side) {
|
||||
if (side > 0) FastFire(side == 1 ? "OnUser1 PL1.TrackTrain:StartBackward::0.0:1" : "OnUser1 PL1.TrackTrain:StartForward::0.0:1");
|
||||
RECEDE = true;
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
// Show payload state
|
||||
public Action PayloadUpdateTimer(Handle timer){
|
||||
if(!isMatch) return Plugin_Stop;
|
||||
CCH[30].BLU = BLC ? "hud/cconflict/cc_blu0B" : "hud/cconflict/cc_blu0A";
|
||||
CCH[10].RED = REC ? "hud/cconflict/cc_red20" : "hud/cconflict/cc_red1F";
|
||||
char state[64];
|
||||
Format(state, sizeof(state), StrEqual(PLT, "BLU") ? CCH[PLRL].BLU : StrEqual(PLT, "RED") ? CCH[PLRL].RED : RECEDE ? CCH[PLRL].NEUTRAL : CCH[PLRL].IDLE);
|
||||
ShowOverlayAll(state);
|
||||
PrintToServer(state);
|
||||
CreateTimer(0.5, PayloadUpdateTimer);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
//Finish adding idle huds
|
||||
//Add real spawn points and collisions
|
||||
|
||||
//Fix payload not going to final blue point...
|
||||
|
||||
//Finish adding map collisions, use Invisible for areas that are blocked by mesh...
|
||||
//Finish fixing up clipping flag models and investigate clipping fence at spawns
|
||||
|
||||
//Music system and mini status hud
|
||||
//Add back the %score% variable to hud. Make sure to use the actual score entry from base playerdestruction...
|
||||
//Add capture point logic, each point taking 30 seconds to cap
|
||||
//Add map easter eggs and other hazards...
|
||||
|
||||
//Brainstorming...
|
||||
/* Crystal: MOVING (Team) //or Crystal: RECEDING (in 45s)?
|
||||
* Song: FFXIV - Locus (XX:XX/XX:XX)
|
||||
*/
|
Reference in New Issue
Block a user