mirror of
https://github.com/ChocoTaco1/TacoServer.git
synced 2026-03-06 05:00:21 +00:00
Corrected file structure
This commit is contained in:
parent
2fe441f421
commit
2097008ccb
30 changed files with 6 additions and 1700 deletions
1989
Classic/scripts/CTFGame.cs
Normal file
1989
Classic/scripts/CTFGame.cs
Normal file
File diff suppressed because it is too large
Load diff
2298
Classic/scripts/LakRabbitGame.cs
Normal file
2298
Classic/scripts/LakRabbitGame.cs
Normal file
File diff suppressed because it is too large
Load diff
2187
Classic/scripts/SCtFGame.cs
Normal file
2187
Classic/scripts/SCtFGame.cs
Normal file
File diff suppressed because it is too large
Load diff
591
Classic/scripts/admin.cs
Normal file
591
Classic/scripts/admin.cs
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
// These have been secured against all those wanna-be-hackers.
|
||||
$VoteMessage["VoteAdminPlayer"] = "Admin Player";
|
||||
$VoteMessage["VoteKickPlayer"] = "Kick Player";
|
||||
$VoteMessage["BanPlayer"] = "Ban Player";
|
||||
$VoteMessage["VoteChangeMission"] = "change the mission to";
|
||||
$VoteMessage["VoteTeamDamage", 0] = "enable team damage";
|
||||
$VoteMessage["VoteTeamDamage", 1] = "disable team damage";
|
||||
$VoteMessage["VoteTournamentMode"] = "change the server to";
|
||||
$VoteMessage["VoteFFAMode"] = "change the server to";
|
||||
$VoteMessage["VoteChangeTimeLimit"] = "change the time limit to";
|
||||
$VoteMessage["VoteMatchStart"] = "start the match";
|
||||
$VoteMessage["VoteGreedMode", 0] = "enable Hoard Mode";
|
||||
$VoteMessage["VoteGreedMode", 1] = "disable Hoard Mode";
|
||||
$VoteMessage["VoteHoardMode", 0] = "enable Greed Mode";
|
||||
$VoteMessage["VoteHoardMode", 1] = "disable Greed Mode";
|
||||
// z0dd - ZOD, 5/13/03. Added vote Random, Fair teams and armor limiting
|
||||
$VoteMessage["VoteRandomTeams", 0] = "enable random teams";
|
||||
$VoteMessage["VoteRandomTeams", 1] = "disable random teams";
|
||||
$VoteMessage["VoteFairTeams", 0] = "enable fair teams";
|
||||
$VoteMessage["VoteFairTeams", 1] = "disable fair teams";
|
||||
$VoteMessage["VoteArmorLimits", 0] = "enable armor limiting";
|
||||
$VoteMessage["VoteArmorLimits", 1] = "disable armor limiting";
|
||||
$VoteMessage["VoteAntiTurtleTime"] = "change the anti turtle time to";
|
||||
$VoteMessage["VoteArmorClass"] = "change the armor class to";
|
||||
$VoteMessage["VoteClearServer"] = "clear server for match";
|
||||
$VoteMessage["VoteSkipMission"] = "skip the mission to";
|
||||
|
||||
function serverCmdStartNewVote(%client, %typeName, %arg1, %arg2, %arg3, %arg4, %playerVote)
|
||||
{
|
||||
// z0dd - ZOD, 9/29/02. Removed T2 demo code from here
|
||||
|
||||
// haha - who gets the last laugh... No admin for you!
|
||||
if( %typeName $= "VoteAdminPlayer" && !$Host::allowAdminPlayerVotes )
|
||||
if( !%client.isSuperAdmin ) // z0dd - ZOD, 5/12/02. Allow Supers to do whatever the hell they want
|
||||
return;
|
||||
|
||||
%typePass = true;
|
||||
|
||||
// if not a valid vote, turn back.
|
||||
// z0dd - ZOD, 5/13/03. Added vote Random, Fair teams, armor limting, Anti-Turtle and Armor Class
|
||||
if($VoteMessage[%typeName] $= "" && (%typeName !$= "VoteTeamDamage" && %typeName !$= "VoteHoardMode"
|
||||
&& %typeName !$= "VoteGreedMode" && %typeName !$= "VoteRandomTeams"
|
||||
&& %typeName !$= "VoteFairTeams" && %typeName !$= "VoteArmorLimits"
|
||||
&& %typeName !$= "VoteAntiTurtleTime" && %typeName !$= "VoteArmorClass"
|
||||
&& %typeName !$= "VoteClearServer" && %typeName !$= "VoteSkipMission")) {
|
||||
%typePass = false;
|
||||
}
|
||||
|
||||
if(( $VoteMessage[ %typeName, $TeamDamage ] $= "" && %typeName $= "VoteTeamDamage" ))
|
||||
%typePass = false;
|
||||
|
||||
if( !%typePass )
|
||||
return; // -> bye ;)
|
||||
|
||||
// ------------------------------------
|
||||
// z0dd - ZOD, 10/03/02. Fixed ban code
|
||||
//if( %typeName $= "BanPlayer" )
|
||||
// if( !%client.isSuperAdmin )
|
||||
// return; // -> bye ;)
|
||||
if( %typeName $= "BanPlayer" )
|
||||
{
|
||||
if( !%client.isSuperAdmin )
|
||||
{
|
||||
return; // -> bye ;)
|
||||
}
|
||||
else
|
||||
{
|
||||
ban( %arg1, %client );
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ------------------------------------
|
||||
|
||||
%isAdmin = ( %client.isAdmin || %client.isSuperAdmin );
|
||||
|
||||
// z0dd - ZOD, 5/19/03. Get the Admins client.
|
||||
if(%isAdmin)
|
||||
$AdminCl = %client;
|
||||
|
||||
// keep these under the server's control. I win.
|
||||
if( !%playerVote )
|
||||
%actionMsg = $VoteMessage[ %typeName ];
|
||||
else if( %typeName $= "VoteTeamDamage" || %typeName $= "VoteGreedMode" || %typeName $= "VoteHoardMode" )
|
||||
%actionMsg = $VoteMessage[ %typeName, $TeamDamage ];
|
||||
else
|
||||
%actionMsg = $VoteMessage[ %typeName ];
|
||||
|
||||
if( !%client.canVote && !%isAdmin )
|
||||
return;
|
||||
|
||||
if ( ( !%isAdmin || ( %arg1.isAdmin && ( %client != %arg1 ) ) ) && // z0dd - ZOD, 4/7/02. Allow SuperAdmins to kick Admins
|
||||
!( ( %typeName $= "VoteKickPlayer" ) && %client.isSuperAdmin ) ) // z0dd - ZOD, 4/7/02. Allow SuperAdmins to kick Admins
|
||||
{
|
||||
%teamSpecific = false;
|
||||
%gender = (%client.sex $= "Male" ? 'he' : 'she');
|
||||
if ( Game.scheduleVote $= "" )
|
||||
{
|
||||
%clientsVoting = 0;
|
||||
|
||||
//send a message to everyone about the vote...
|
||||
if ( %playerVote )
|
||||
{
|
||||
%teamSpecific = ( %typeName $= "VoteKickPlayer" ) && ( Game.numTeams > 1 );
|
||||
%kickerIsObs = %client.team == 0;
|
||||
%kickeeIsObs = %arg1.team == 0;
|
||||
%sameTeam = %client.team == %arg1.team;
|
||||
|
||||
if( %kickeeIsObs )
|
||||
{
|
||||
%teamSpecific = false;
|
||||
%sameTeam = false;
|
||||
}
|
||||
if(( !%sameTeam && %teamSpecific) && %typeName !$= "VoteAdminPlayer")
|
||||
{
|
||||
messageClient(%client, '', '\c2Player votes must be team based.');
|
||||
return;
|
||||
}
|
||||
|
||||
// kicking is team specific
|
||||
if( %typeName $= "VoteKickPlayer" )
|
||||
{
|
||||
if(%arg1.isSuperAdmin)
|
||||
{
|
||||
messageClient(%client, '', '\c2You can not %1 %2, %3 is a Super Admin!', %actionMsg, %arg1.name, %gender);
|
||||
return;
|
||||
}
|
||||
|
||||
Game.kickClient = %arg1;
|
||||
Game.kickClientName = %arg1.name;
|
||||
Game.kickGuid = %arg1.guid;
|
||||
Game.kickTeam = %arg1.team;
|
||||
|
||||
if(%teamSpecific)
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
|
||||
if (%cl.isAdmin == true || (%cl.team == %client.team && !%cl.isAIControlled()))
|
||||
{
|
||||
if(%cl.isAdmin == true && %cl.team !$= %client.team) {
|
||||
messageClient(%cl, 'AdminOtherTeamKickVoteStarted', '\c2%1 has initiated a vote to kick %2 on the \c3Other Team.~wgui/objective_notification.wav', %client.name, %arg1.name);
|
||||
}
|
||||
else
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1.name);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( %typeName $= "VoteChangeMission" )
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3 (%4).', %client.name, %actionMsg, %arg1, %arg2 );
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (%arg1 !$= 0)
|
||||
{
|
||||
if (%arg2 !$= 0)
|
||||
{
|
||||
if(%typeName $= "VoteTournamentMode")
|
||||
{
|
||||
%admin = getAdmin();
|
||||
if(%admin > 0)
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 Tournament Mode (%3).', %client.name, %actionMsg, %arg1);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
messageClient( %client, 'clientMsg', 'There must be a server admin to play in Tournament Mode.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3 %4.', %client.name, %actionMsg, %arg1, %arg2);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2 %3.', %client.name, %actionMsg, %arg1);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( %idx = 0; %idx < ClientGroup.getCount(); %idx++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %idx );
|
||||
if ( !%cl.isAIControlled() )
|
||||
{
|
||||
messageClient( %cl, 'VoteStarted', '\c2%1 initiated a vote to %2.', %client.name, %actionMsg);
|
||||
%clientsVoting++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// open the vote hud for all clients that will participate in this vote
|
||||
if(%teamSpecific)
|
||||
{
|
||||
for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %clientIndex );
|
||||
|
||||
if(%cl.team == %client.team && !%cl.isAIControlled())
|
||||
messageClient(%cl, 'openVoteHud', "", %clientsVoting, ($Host::VotePassPercent / 100));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %clientIndex );
|
||||
if ( !%cl.isAIControlled() )
|
||||
messageClient(%cl, 'openVoteHud', "", %clientsVoting, ($Host::VotePassPercent / 100));
|
||||
}
|
||||
}
|
||||
clearVotes();
|
||||
Game.voteType = %typeName;
|
||||
Game.scheduleVote = schedule( ($Host::VoteTime * 1000), 0, "calcVotes", %typeName, %arg1, %arg2, %arg3, %arg4 );
|
||||
%client.vote = true;
|
||||
messageAll('addYesVote', "");
|
||||
|
||||
if(!%client.team == 0)
|
||||
clearBottomPrint(%client);
|
||||
}
|
||||
else
|
||||
messageClient( %client, 'voteAlreadyRunning', '\c2A vote is already in progress.' );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( Game.scheduleVote !$= "" && Game.voteType $= %typeName )
|
||||
{
|
||||
messageAll('closeVoteHud', "");
|
||||
cancel(Game.scheduleVote);
|
||||
Game.scheduleVote = "";
|
||||
}
|
||||
|
||||
// if this is a superAdmin, don't kick or ban
|
||||
if(%arg1 != %client)
|
||||
{
|
||||
if(!%arg1.isSuperAdmin)
|
||||
{
|
||||
// Set up kick/ban values:
|
||||
if ( %typeName $= "VoteBanPlayer" || %typeName $= "VoteKickPlayer" )
|
||||
{
|
||||
Game.kickClient = %arg1;
|
||||
Game.kickClientName = %arg1.name;
|
||||
Game.kickGuid = %arg1.guid;
|
||||
Game.kickTeam = %arg1.team;
|
||||
}
|
||||
|
||||
//Tinman - PURE servers can't call "eval"
|
||||
//Mark - True, but neither SHOULD a normal server
|
||||
// - thanks Ian Hardingham
|
||||
//if (!isPureServer())
|
||||
// eval( "Game." @ %typeName @ "(true,\"" @ %arg1 @ "\",\"" @ %arg2 @ "\",\"" @ %arg3 @ "\",\"" @ %arg4 @ "\");" );
|
||||
//else
|
||||
Game.evalVote(%typeName, true, %arg1, %arg2, %arg3, %arg4);
|
||||
}
|
||||
else
|
||||
messageClient(%client, '', '\c2You can not %1 %2, %3 is a Super Admin!', %actionMsg, %arg1.name, %gender);
|
||||
}
|
||||
}
|
||||
%client.canVote = false;
|
||||
%client.rescheduleVote = schedule( ($Host::voteSpread * 1000) + ($Host::voteTime * 1000) , 0, "resetVotePrivs", %client );
|
||||
}
|
||||
|
||||
function resetVotePrivs( %client )
|
||||
{
|
||||
//messageClient( %client, '', 'You may now start a new vote.');
|
||||
%client.canVote = true;
|
||||
%client.rescheduleVote = "";
|
||||
}
|
||||
|
||||
function serverCmdSetPlayerVote(%client, %vote)
|
||||
{
|
||||
// players can only vote once
|
||||
if( %client.vote $= "" )
|
||||
{
|
||||
%client.vote = %vote;
|
||||
if(%client.vote == 1)
|
||||
messageAll('addYesVote', "");
|
||||
else
|
||||
messageAll('addNoVote', "");
|
||||
|
||||
commandToClient(%client, 'voteSubmitted', %vote);
|
||||
}
|
||||
}
|
||||
|
||||
function calcVotes(%typeName, %arg1, %arg2, %arg3, %arg4)
|
||||
{
|
||||
if(%typeName $= "voteMatchStart")
|
||||
if($MatchStarted || $countdownStarted)
|
||||
return;
|
||||
|
||||
for ( %clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++ )
|
||||
{
|
||||
%cl = ClientGroup.getObject( %clientIndex );
|
||||
messageClient(%cl, 'closeVoteHud', "");
|
||||
|
||||
if ( %cl.vote !$= "" )
|
||||
{
|
||||
if ( %cl.vote )
|
||||
{
|
||||
Game.votesFor[%cl.team]++;
|
||||
Game.totalVotesFor++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.votesAgainst[%cl.team]++;
|
||||
Game.totalVotesAgainst++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Game.votesNone[%cl.team]++;
|
||||
Game.totalVotesNone++;
|
||||
}
|
||||
}
|
||||
//Tinman - PURE servers can't call "eval"
|
||||
//Mark - True, but neither SHOULD a normal server
|
||||
// - thanks Ian Hardingham
|
||||
//if (!isPureServer())
|
||||
// eval( "Game." @ %typeName @ "(false,\"" @ %arg1 @ "\",\"" @ %arg2 @ "\",\"" @ %arg3 @ "\",\"" @ %arg4 @ "\");" );
|
||||
//else
|
||||
Game.evalVote(%typeName, false, %arg1, %arg2, %arg3, %arg4);
|
||||
Game.scheduleVote = "";
|
||||
Game.kickClient = "";
|
||||
clearVotes();
|
||||
}
|
||||
|
||||
function clearVotes()
|
||||
{
|
||||
for(%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
|
||||
{
|
||||
%client = ClientGroup.getObject(%clientIndex);
|
||||
%client.vote = "";
|
||||
messageClient(%client, 'clearVoteHud', "");
|
||||
}
|
||||
|
||||
for(%team = 1; %team < 5; %team++)
|
||||
{
|
||||
Game.votesFor[%team] = 0;
|
||||
Game.votesAgainst[%team] = 0;
|
||||
Game.votesNone[%team] = 0;
|
||||
Game.totalVotesFor = 0;
|
||||
Game.totalVotesAgainst = 0;
|
||||
Game.totalVotesNone = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Tournament mode Stuff-----------------------------------
|
||||
|
||||
function setModeFFA( %mission, %missionType )
|
||||
{
|
||||
if( $Host::TournamentMode )
|
||||
{
|
||||
$Host::TournamentMode = false;
|
||||
|
||||
if( isObject( Game ) )
|
||||
Game.gameOver();
|
||||
|
||||
loadMission(%mission, %missionType, false);
|
||||
}
|
||||
}
|
||||
|
||||
function setModeTournament( %mission, %missionType )
|
||||
{
|
||||
if( !$Host::TournamentMode )
|
||||
{
|
||||
$Host::TournamentMode = true;
|
||||
|
||||
if( isObject( Game ) )
|
||||
Game.gameOver();
|
||||
|
||||
loadMission(%mission, %missionType, false);
|
||||
}
|
||||
}
|
||||
|
||||
// z0dd - ZOD, 5/23/03. New function, vote for CTF Anti-Turtle time setting
|
||||
function serverCmdGetAntiTurtleTimeList( %client, %key )
|
||||
{
|
||||
if ( isObject( Game ) )
|
||||
Game.sendAntiTurtleTimeList( %client, %key );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// z0dd - ZOD- Founder, 7/13/03. From Mechina Mod, Admin punishments etc.
|
||||
|
||||
function serverCmdTogglePlayerGag(%client, %who)
|
||||
{
|
||||
if(%client.isSuperAdmin)
|
||||
{
|
||||
if(!%who.isGagged && !%who.isSuperAdmin)
|
||||
{
|
||||
%who.isGagged = true;
|
||||
messageClient(%client, 'MsgAdmin', 'You have Gagged %1.', %who.name);
|
||||
messageAllExcept(%who, -1, 'MsgAdminForce', '%1 has been Gagged by %2 for talking too much crap.', %who.name, %client.name);
|
||||
messageClient(%who, 'MsgAdminAction', 'You have Been Gagged by %1, quit talking trash and play.', %client.name);
|
||||
logEcho(%client.nameBase @ " gagged " @ %target.nameBase, 1);
|
||||
}
|
||||
else if (%who.isGagged)
|
||||
{
|
||||
%who.isGagged = false;
|
||||
messageClient(%client, 'MsgAdmin', 'You have UnGagged %1.', %who.name);
|
||||
messageAllExcept(%who, -1, 'MsgAdminAction', '%1 has been UnGagged by %2.', %who.name, %client.name);
|
||||
messageClient(%who, 'MsgAdminAction', 'You have Been UnGagged by %1, quit talking trash and play.', %client.name);
|
||||
logEcho(%client.nameBase @ " ungagged " @ %who.nameBase, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
messageClient(%client, 'MsgError', '\c2Only Super Admins can use this command.');
|
||||
}
|
||||
|
||||
function serverCmdTogglePlayerFreeze(%client, %who)
|
||||
{
|
||||
if(%client.isSuperAdmin)
|
||||
{
|
||||
if(!$MatchStarted)
|
||||
{
|
||||
messageClient(%client, 'MsgError', 'You must wait for the match to start!');
|
||||
return;
|
||||
}
|
||||
if (!%who.isFroze && !%who.isSuperAdmin)
|
||||
{
|
||||
if(!isobject(%who.player))
|
||||
{
|
||||
messageClient(%client, 'MsgError', 'You must wait for the player to spawn!');
|
||||
return;
|
||||
}
|
||||
%who.isFroze = true;
|
||||
%who.player.setvelocity("0 0 0");
|
||||
%who.player.setMoveState(true);
|
||||
%who.player.invincible = true;
|
||||
messageClient(%client, 'MsgAdmin', 'You have Frozen %1.', %who.name);
|
||||
messageAllExcept(%who, -1, 'MsgAdminForce', '%1 has been Frozen by %2 for being a Llama.', %who.name, %client.name);
|
||||
messageClient(%who, 'MsgAdminAction', 'You have Been Frozen by %1, Think about what you have been doing.', %client.name);
|
||||
logEcho(%client.nameBase @ " froze " @ %who.nameBase, 1);
|
||||
}
|
||||
else if (%who.isFroze)
|
||||
{
|
||||
%who.isFroze = false;
|
||||
%who.player.setMoveState(false);
|
||||
%who.player.invincible = false;
|
||||
messageClient(%client, 'MsgAdmin', 'You have de-iced %1.', %who.name);
|
||||
messageAllExcept(%who, -1, 'MsgAdminForce', '%1 has been Un Frozen by %2.', %who.name, %client.name);
|
||||
messageClient(%who, 'MsgAdminAction', 'You have Been de-Iced by %1, now behave.', %client.name);
|
||||
logEcho(%client.nameBase @ " unfroze " @ %who.nameBase, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
messageClient(%client, 'MsgError', '\c2Only Super Admins can use this command.');
|
||||
}
|
||||
|
||||
function serverCmdBootToTheRear(%client, %who)
|
||||
{
|
||||
if(%client.isSuperAdmin)
|
||||
{
|
||||
if(!$MatchStarted)
|
||||
{
|
||||
messageClient(%client, 'MsgError', 'You must wait for the match to start!');
|
||||
return;
|
||||
}
|
||||
if(isObject(%who.player) && !%who.isSuperAdmin)
|
||||
{
|
||||
%time = getTime();
|
||||
%obj = %who.player;
|
||||
%vec = "0 0 10";
|
||||
%obj.applyImpulse(%obj.position, VectorScale(%vec, %obj.getDataBlock().mass*20));
|
||||
messageAllExcept(%who, -1, 'MsgAdminForce', '%1 has been given a boot to the rear by %2.', %who.name, %client.name);
|
||||
messageClient(%who, 'MsgAdminAction', 'You have Been given a boot to the ass by %1, now behave.', %client.name);
|
||||
logEcho(%client.nameBase @ " gave " @ %who.nameBase @ " a boot to the rear", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageClient(%client, 'MsgError', 'You must wait for the player to spawn!');
|
||||
}
|
||||
}
|
||||
else
|
||||
messageClient(%client, 'MsgError', '\c2Only Super Admins can use this command.');
|
||||
}
|
||||
|
||||
function serverCmdExplodePlayer(%client, %who)
|
||||
{
|
||||
if(%client.isSuperAdmin)
|
||||
{
|
||||
if(!$MatchStarted)
|
||||
{
|
||||
messageClient(%client, 'MsgError', 'You must wait for the match to start!');
|
||||
return;
|
||||
}
|
||||
if(isObject(%who.player) && !%who.isSuperAdmin)
|
||||
{
|
||||
%who.player.blowup();
|
||||
%who.player.scriptKill(0);
|
||||
messageAllExcept(%who, -1, 'MsgAdminForce', '%1 found some explosives in his pants planted by %2.', %who.name, %client.name);
|
||||
messageClient(%who, 'MsgAdminAction', 'You have Been dissasembled for inspection by the Super Admin %1, now behave.', %client.name);
|
||||
logEcho(%client.nameBase @ " exploded " @ %who.nameBase, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
messageClient(%client, 'MsgError', 'You must wait for the player to spawn!');
|
||||
}
|
||||
}
|
||||
else
|
||||
messageClient(%client, 'MsgError', '\c2Only Super Admins can use this command.');
|
||||
}
|
||||
|
||||
// z0dd - ZOD - MeBad, 7/13/03. Send client information.
|
||||
function ServerCmdPrintClientInfo(%client, %targetClient)
|
||||
{
|
||||
if (%client.isAdmin)
|
||||
{
|
||||
if ((!%targetClient.isSuperAdmin) && (%client.isSuperAdmin))
|
||||
{
|
||||
%wonid = getField( %targetClient.getAuthInfo(), 3);
|
||||
%ip = %targetClient.getAddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
%wonid = "PROTECTED";
|
||||
%ip = "PROTECTED";
|
||||
}
|
||||
MessageClient(%client, '', '---------------------------------------------------------------');
|
||||
MessageClient(%client, 'ClientInfo', "\c3Client Info...\n" @
|
||||
"ClientName: \c2" @ %targetClient.nameBase @ "\n" @
|
||||
"\c3Wonid: \c2" @ %wonid @ "\n" @
|
||||
"\c3IP: \c2" @ %ip @ "\n\n" @
|
||||
"\c3TeamKills:\c2 " @ %targetClient.teamkills @ "\n" @
|
||||
"\c3BK (BaseKills): \c2" @ %targetClient.tkDestroys @ "\n" @
|
||||
"\c3Suicides:\c2 " @ %targetClient.suicides @ "\n");
|
||||
MessageClient(%client, '', '---------------------------------------------------------------');
|
||||
}
|
||||
else
|
||||
messageClient(%client, 'MsgError', '\c2Only Admins can use this command.');
|
||||
}
|
||||
15
Classic/scripts/autoexec/AntiCloak.cs
Normal file
15
Classic/scripts/autoexec/AntiCloak.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
$AntiCloakPlayerCount = 6; // amount of players needed on server for CloakPack to be selectable
|
||||
|
||||
//Activates when default Inventory for player is set so player cant select it thru hotkeys or select it thru the gui.
|
||||
function ActivateAntiCloak ()
|
||||
{
|
||||
//echo("TotalTeamPlayerCount " @ $TotalTeamPlayerCount);
|
||||
//echo("AntiCloakPlayerCount " @ $AntiCloakPlayerCount);
|
||||
|
||||
if(!$Host::TournamentMode && $TotalTeamPlayerCount < $AntiCloakPlayerCount)
|
||||
//If server is in Tourny mode or if the server population isnt higher than the AntiCloakPlayerCount the CloakPack is not selectable.
|
||||
$InvBanList[CTF, "CloakingPack"] = true;
|
||||
else
|
||||
//If AntiCloakPlayerCount is lower than server population, CloakPack is enabled and Selectable.
|
||||
$InvBanList[CTF, "CloakingPack"] = false;
|
||||
}
|
||||
99
Classic/scripts/autoexec/GetTeamCounts.cs
Normal file
99
Classic/scripts/autoexec/GetTeamCounts.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
//This function is Called at:
|
||||
//CreateServer(%mission, %missionType) in Server.cs
|
||||
|
||||
package StartTeamCounts {
|
||||
|
||||
//Start
|
||||
function CreateServer(%mission, %missionType)
|
||||
{
|
||||
//Call default function
|
||||
parent::CreateServer(%mission, %missionType);
|
||||
//Start
|
||||
//Make sure our activation variable is set
|
||||
ResetClientChangedTeams();
|
||||
//Keeps server Auto Reset off
|
||||
$Host::Dedicated = 0;
|
||||
//Call for a GetTeamCount update
|
||||
GetTeamCounts( %game, %client, %respawn );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Prevent package from being activated if it is already
|
||||
if (!isActivePackage(StartTeamCounts))
|
||||
activatePackage(StartTeamCounts);
|
||||
|
||||
function GetTeamCounts( %game, %client, %respawn )
|
||||
{
|
||||
if (!isActivePackage(StartTeamCounts)) {
|
||||
deactivatePackage(StartTeamCounts);
|
||||
}
|
||||
|
||||
//Check pug password
|
||||
CheckPUGpassword();
|
||||
|
||||
//Get teamcounts
|
||||
if($GetCountsClientTeamChange && $countdownStarted && $MatchStarted) {
|
||||
//Team Count code by Keen
|
||||
$PlayerCount[0] = 0;
|
||||
$PlayerCount[1] = 0;
|
||||
$PlayerCount[2] = 0;
|
||||
|
||||
for(%i = 0; %i < ClientGroup.getCount(); %i++)
|
||||
{
|
||||
%client = ClientGroup.getObject(%i);
|
||||
|
||||
//if(!%client.isAIControlled())
|
||||
$PlayerCount[%client.team]++;
|
||||
}
|
||||
|
||||
//echo ("Clientgroup " @ ClientGroup.getCount());
|
||||
//echo ("$PlayerCount[0] " @ $PlayerCount[0]);
|
||||
//echo ("$PlayerCount[1] " @ $PlayerCount[1]);
|
||||
//echo ("$PlayerCount[2] " @ $PlayerCount[2]);
|
||||
//echo ("client.team " @ %client.team);
|
||||
|
||||
//Other variables
|
||||
//Amount of players on teams
|
||||
$TotalTeamPlayerCount = $PlayerCount[1] + $PlayerCount[2];
|
||||
//Amount of all players including observers
|
||||
$AllPlayerCount = $PlayerCount[1] + $PlayerCount[2] + $PlayerCount[0];
|
||||
|
||||
|
||||
//Start Base Rape Notify
|
||||
//Make sure it's CTF Mode
|
||||
if($CurrentMissionType $= "CTF") {
|
||||
PlayerNotify::AtSpawn( %game, %client, %respawn );
|
||||
}
|
||||
//Call Team Balance Notify
|
||||
//Make sure it's CTF Mode
|
||||
if($CurrentMissionType $= "CTF" && $TotalTeamPlayerCount !$= 0) {
|
||||
TeamBalanceNotify::AtSpawn( %game, %client, %respawn );
|
||||
}
|
||||
if($CurrentMissionType $= "sctf" && $TotalTeamPlayerCount !$= 0) {
|
||||
TeamBalanceNotify::AtSpawn( %game, %client, %respawn );
|
||||
}
|
||||
//AntiCloak Start
|
||||
//if($CurrentMissionType $= "CTF") {
|
||||
//ActivateAntiCloak ();
|
||||
//}
|
||||
|
||||
$GetCountsClientTeamChange = false;
|
||||
|
||||
}
|
||||
|
||||
//Call itself again. Every 5 seconds.
|
||||
schedule(5000, 0, "GetTeamCounts");
|
||||
|
||||
}
|
||||
|
||||
//Run at DefaultGame::clientJoinTeam, DefaultGame::clientChangeTeam, DefaultGame::assignClientTeam in evo defaultgame.ovl
|
||||
//Also Run at DefaultGame::onClientEnterObserverMode, DefaultGame::AIChangeTeam, DefaultGame::onClientLeaveGame, DefaultGame::forceObserver in evo defaultgame.ovl
|
||||
//And finally GameConnection::onConnect in evo server.ovl
|
||||
//Added so the bulk of GetCounts doesnt run when it doesnt need to causing unnecessary latency that may or may not have existed, but probably is good practice.
|
||||
//GetCounts still runs every 5 seconds as it did, but whether or not someone has changed teams, joined obs, left, etc etc will decide whether or not the bulk of it runs.
|
||||
function ResetClientChangedTeams() {
|
||||
//Let GetTeamCounts run if there is a Teamchange.
|
||||
$GetCountsClientTeamChange = true;
|
||||
}
|
||||
72
Classic/scripts/autoexec/NoBaseRapeNotify.cs
Normal file
72
Classic/scripts/autoexec/NoBaseRapeNotify.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
//Start and Reset Notify
|
||||
//package NoRapeNotify {
|
||||
|
||||
//Start Notify
|
||||
//function DefaultGame::spawnPlayer( %game, %client, %respawn ) {
|
||||
//Call default function
|
||||
//parent::spawnPlayer( %game, %client, %respawn );
|
||||
//Start
|
||||
//Make sure it's CTF Mode
|
||||
//if( $CurrentMissionType $= "CTF" ) {
|
||||
//PlayerNotify::AtSpawn( %game, %client, %respawn );
|
||||
//}
|
||||
//}
|
||||
|
||||
//Moved the DefaultGame::gameOver in evo defaultgame.ovl
|
||||
|
||||
//Reset Notify
|
||||
//function DefaultGame::gameOver( %game ) {
|
||||
//Call default function
|
||||
//parent::gameOver( %game );
|
||||
//Reset NoBaseRape Notify
|
||||
//ResetNotify::MissionEnd( %game, %client );
|
||||
//}
|
||||
|
||||
//};
|
||||
|
||||
// Prevent package from being activated if it is already
|
||||
//if (!isActivePackage(NoRapeNotify))
|
||||
//activatePackage(NoRapeNotify);
|
||||
|
||||
|
||||
|
||||
//This function is at DefaultGame::spawnPlayer( %game, %client, %respawn ) defaultGame.cs
|
||||
//Notifys the user if NoBase rape is on or off. Has a Counter so it is only run once and doesnt spam the client. It is triggered at spawn.
|
||||
function PlayerNotify::AtSpawn( %game, %client, %respawn )
|
||||
{
|
||||
//echo ("%client " @ %client);
|
||||
//echo ("$TeamBalanceClient " @ $TeamBalanceClient);
|
||||
|
||||
//Is NoBaseRape On or off
|
||||
if( !$Host::TournamentMode && $Host::EvoNoBaseRapeEnabled && $Host::EvoNoBaseRapeClassicPlayerCount > $TotalTeamPlayerCount ) {
|
||||
//If on, has the client gotten the notification already
|
||||
if($NoBaseRapeNotifyCount !$= 0) {
|
||||
messageAll('MsgNoBaseRapeNotify', 'No Base Rape is \c1Enabled.~wfx/misc/nexus_cap.wav');
|
||||
$NoBaseRapeNotifyCount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
//NoBaseRape is off
|
||||
//Has the client gotten the notification already
|
||||
if($NoBaseRapeNotifyCount !$= 1) {
|
||||
messageAll('MsgNoBaseRapeNotify', 'No Base Rape is \c1Disabled.~wfx/misc/diagnostic_on.wav');
|
||||
$NoBaseRapeNotifyCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//This function is at StaticShapeData::damageObject(%data, %targetObject, %sourceObject, %position, %amount, %damageType)
|
||||
//In the evopackage.cs or evoClassic.vl2
|
||||
//Plays a sound when a player hits a protected asset
|
||||
function PlayerNotifyEnabled::OnDamage( %game, %sourceObject )
|
||||
{
|
||||
messageClient(%sourceObject.client, 'MsgNoBaseRapeNotify', '~wfx/misc/diagnostic_beep.wav');
|
||||
}
|
||||
|
||||
//This function is at DefaultGame::gameOver(%game) CTFGame.cs
|
||||
//Resets the client NotifyCount when the mission ends
|
||||
function ResetNotify::MissionEnd( %game, %client )
|
||||
{
|
||||
$NoBaseRapeNotifyCount = -1;
|
||||
}
|
||||
|
||||
|
||||
58
Classic/scripts/autoexec/PUGpasscheck.cs
Normal file
58
Classic/scripts/autoexec/PUGpasscheck.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//To activate a password in certain gamemodes
|
||||
//called in Getcounts.cs
|
||||
//and also other options like distance and speed
|
||||
//turn tournament mode off when switched to lak
|
||||
|
||||
// Variables
|
||||
// Add these to ServerPrefs
|
||||
//
|
||||
// Turn on Auto Password at a player limit
|
||||
// $Host::PUGautoPassword = 1;
|
||||
// What value does Auto Password turn on
|
||||
// $Host::PUGautoPasswordLimit = 10;
|
||||
// The PUG password you want
|
||||
// $Host::PUGPassword = "pickup";
|
||||
|
||||
function CheckPUGpassword()
|
||||
{
|
||||
//Only run before mission start and countdown start
|
||||
if( !$MatchStarted && !$countdownStarted )
|
||||
{
|
||||
if( $CurrentMissionType !$= "LakRabbit" )
|
||||
{
|
||||
if( $Host::TournamentMode )
|
||||
$Host::Password = $Host::PUGPassword;
|
||||
|
||||
else if( !$Host::TournamentMode )
|
||||
{
|
||||
$Host::Password = "";
|
||||
|
||||
//if 10 players are already on the server when the map changes
|
||||
if( $TotalTeamPlayerCount >= $Host::PUGautoPasswordLimit && $Host::PUGautoPassword )
|
||||
$Host::Password = $Host::PUGPassword;
|
||||
}
|
||||
|
||||
$Host::HiVisibility = "0";
|
||||
}
|
||||
else if( $CurrentMissionType $= "LakRabbit" )
|
||||
{
|
||||
$Host::Password = "";
|
||||
$Host::TournamentMode = 0;
|
||||
|
||||
$Host::HiVisibility = "1";
|
||||
}
|
||||
|
||||
//echo ("PUGpassCheck");
|
||||
}
|
||||
|
||||
//If someone changes teams
|
||||
else if( $Host::PUGautoPassword && $CurrentMissionType !$= "LakRabbit" && !$Host::TournamentMode )
|
||||
{
|
||||
if( $TotalTeamPlayerCount < $Host::PUGautoPasswordLimit )
|
||||
$Host::Password = "";
|
||||
else if( $TotalTeamPlayerCount >= $Host::PUGautoPasswordLimit )
|
||||
$Host::Password = $Host::PUGPassword;
|
||||
|
||||
//echo ("PUGpassCheckTeamchange");
|
||||
}
|
||||
}
|
||||
77
Classic/scripts/autoexec/TeamBalanceNotify.cs
Normal file
77
Classic/scripts/autoexec/TeamBalanceNotify.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//Give the client a notification on the current state of balancing.
|
||||
//This function is in GetTeamCounts( %game, %client, %respawn ) GetTeamCounts.cs
|
||||
function TeamBalanceNotify::AtSpawn( %game, %client, %respawn )
|
||||
{
|
||||
//Call for a GetTeamCount update
|
||||
//GetTeamCounts( %game, %client, %respawn );
|
||||
|
||||
//evoplayercount does not count yourself
|
||||
|
||||
//variables
|
||||
//%balancedifference = 2; //player difference you want to allow before sending notifications between teams.
|
||||
//%Team1Difference = $PlayerCount[1] - $PlayerCount[2];
|
||||
//%Team2Difference = $PlayerCount[2] - $PlayerCount[1];
|
||||
|
||||
|
||||
//echo ("%Team1Difference " @ %Team1Difference);
|
||||
//echo ("%Team2Difference " @ %Team2Difference);
|
||||
|
||||
|
||||
//Are teams unbalanced?
|
||||
if( $PlayerCount[1] !$= $PlayerCount[2] ) {
|
||||
//Reset Balanced
|
||||
$BalancedCount = 0;
|
||||
if( ($PlayerCount[1] - $PlayerCount[2]) >= 2 || ($PlayerCount[2] - $PlayerCount[1]) >= 2 ) {
|
||||
//Has the client gotten the notification already
|
||||
if($TeamBalanceNotifyCount !$= 1) {
|
||||
//If unbalanced, send a notification. Will continue to send notifications until teams are balanced.
|
||||
messageAll('MsgTeamBalanceNotify', '\c1Teams are unbalanced.');
|
||||
//Only get the notification once per spawn.
|
||||
$TeamBalanceNotifyCount = 1;
|
||||
//Reset Stat
|
||||
$StatsBalanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
//If teams are balanced and teams dont equal 0.
|
||||
if( $PlayerCount[1] == $PlayerCount[2] && $TotalTeamPlayerCount !$= 0 ) {
|
||||
//Has the client gotten the notification already
|
||||
if($BalancedCount !$= 1) {
|
||||
//If balanced, send a notification.
|
||||
messageAll('MsgTeamBalanceNotify', '\c1Teams are balanced.');
|
||||
//Only get the balance notification once.
|
||||
$BalancedCount = 1;
|
||||
//Reset Unbalanced
|
||||
$TeamBalanceNotifyCount = 0;
|
||||
//Reset Stat
|
||||
$StatsBalanceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//3 or more difference gets a count notify
|
||||
if( ($PlayerCount[1] - $PlayerCount[2]) >= 3 || ($PlayerCount[2] - $PlayerCount[1]) >= 3 ) {
|
||||
//Run it once
|
||||
if($StatsBalanceCount !$= 1) {
|
||||
messageAll('MsgTeamBalanceNotify', '\c1It is currently %1 vs %2 with %3 observers.', $PlayerCount[1], $PlayerCount[2], $PlayerCount[0] );
|
||||
$StatsBalanceCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Called in CTFGame::flagCap in evo CTFGame.ovl
|
||||
//Allows for another unbalanced notification everytime the flag is capped.
|
||||
function ResetUnbalancedNotifyPerCap()
|
||||
{
|
||||
$TeamBalanceNotifyCount = 0;
|
||||
$StatsBalanceCount = 0;
|
||||
}
|
||||
|
||||
//Reset Notify at defaultgame::gameOver in evo defaultgame.ovl
|
||||
function ResetTeamBalanceNotifyGameOver( %game ) {
|
||||
//Reset TeamBalance Variables
|
||||
$BalancedCount = -1;
|
||||
$TeamBalanceNotifyCount = -1;
|
||||
$StatsBalanceCount = -1;
|
||||
|
||||
}
|
||||
88
Classic/scripts/autoexec/VoteOverTime.cs
Normal file
88
Classic/scripts/autoexec/VoteOverTime.cs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
//Changes were also made in the Evo Admin.ovl and DefaultGame.ovl
|
||||
//DefaultGame::voteChangeMission, DefaultGame::voteChangeTimeLimit, serverCmdStartNewVote
|
||||
|
||||
package VoteOverTime {
|
||||
|
||||
function DefaultGame::checkTimeLimit(%game, %forced)
|
||||
{
|
||||
// Don't add extra checks:
|
||||
if ( %forced )
|
||||
cancel( %game.timeCheck );
|
||||
|
||||
// if there is no time limit, check back in a minute to see if it's been set
|
||||
if(($Host::TimeLimit $= "") || $Host::TimeLimit == 0)
|
||||
{
|
||||
%game.timeCheck = %game.schedule(20000, "checkTimeLimit");
|
||||
return;
|
||||
}
|
||||
|
||||
%curTimeLeftMS = ($Host::TimeLimit * 60 * 1000) + $missionStartTime - getSimTime();
|
||||
|
||||
if (%curTimeLeftMS <= 0)
|
||||
{
|
||||
//Vote Overtime
|
||||
//Check if Vote is active or if the timelimit has changed.
|
||||
if( !$VoteInProgress && !$TimeLimitChanged ) {
|
||||
// time's up, put down your pencils
|
||||
%game.timeLimitReached();
|
||||
|
||||
//Reset Everything to do with Vote Overtime
|
||||
//Moved to function DefaultGame::gameOver in DefaultGame.ovl in evo
|
||||
}
|
||||
else if( $missionRunning && $VoteInProgress && !$TimeLimitChanged ) {
|
||||
//Restart the function so the map can end if the Vote doesnt pass.
|
||||
schedule(2000, 0, "RestartcheckTimeLimit", %game, %forced);
|
||||
|
||||
//Messege
|
||||
if( !$VoteInProgressMessege ) {
|
||||
messageAll('', '\c2Vote Overtime Initiated.~wfx/powered/turret_heavy_activate.wav', %display);
|
||||
$VoteInProgressMessege = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(%curTimeLeftMS >= 20000)
|
||||
%game.timeCheck = %game.schedule(20000, "checkTimeLimit");
|
||||
else
|
||||
%game.timeCheck = %game.schedule(%curTimeLeftMS + 1, "checkTimeLimit");
|
||||
|
||||
//now synchronize everyone's clock
|
||||
messageAll('MsgSystemClock', "", $Host::TimeLimit, %curTimeLeftMS);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function RestartcheckTimeLimit(%game, %forced)
|
||||
{
|
||||
%game.checkTimeLimit(%game, %forced);
|
||||
}
|
||||
|
||||
function StartVOTimeVote(%game)
|
||||
{
|
||||
$VoteSoundInProgress = true;
|
||||
$VoteInProgress = true;
|
||||
$TimeLimitChanged = false;
|
||||
}
|
||||
|
||||
function ResetVOTimeChanged(%game)
|
||||
{
|
||||
$VoteInProgress = false;
|
||||
$TimeLimitChanged = true;
|
||||
$VoteInProgressMessege = false;
|
||||
$VoteSoundInProgress = false;
|
||||
}
|
||||
|
||||
function ResetVOall(%game)
|
||||
{
|
||||
$VoteInProgress = false;
|
||||
$TimeLimitChanged = false;
|
||||
$VoteInProgressMessege = false;
|
||||
$VoteSoundInProgress = false;
|
||||
}
|
||||
|
||||
|
||||
// Prevent package from being activated if it is already
|
||||
if (!isActivePackage(VoteOverTime))
|
||||
activatePackage(VoteOverTime);
|
||||
13
Classic/scripts/autoexec/VoteSound.cs
Normal file
13
Classic/scripts/autoexec/VoteSound.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//Make a sound every so seconds to make sure everyone votes
|
||||
|
||||
function VoteSound( %game ) {
|
||||
|
||||
if($VoteSoundInProgress) {
|
||||
messageAll('', '\c1Vote in Progress: \c0Press Insert for Yes or Delete for No.~wgui/objective_notification.wav', %display);
|
||||
//$VoteSoundSchedule = schedule(12000, "VoteSound", %game);
|
||||
schedule(12000, 0, "VoteSound", %game);
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
}
|
||||
19
Classic/scripts/autoexec/antiTurret.cs
Normal file
19
Classic/scripts/autoexec/antiTurret.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
$TurretPlayerCount = 10; // amount of players needed on server for turrets
|
||||
|
||||
package antiTurret {
|
||||
|
||||
function TurretData::selectTarget(%this, %turret)
|
||||
{
|
||||
if( !$Host::TournamentMode && $TotalTeamPlayerCount < $TurretPlayerCount) {
|
||||
%turret.clearTarget();
|
||||
}
|
||||
else {
|
||||
Parent::selectTarget(%this, %turret);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Prevent package from being activated if it is already
|
||||
if (!isActivePackage(antiTurret))
|
||||
activatePackage(antiTurret);
|
||||
21
Classic/scripts/autoexec/anti_NoFog_Snipe.cs
Normal file
21
Classic/scripts/autoexec/anti_NoFog_Snipe.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// anti NoFog Snipe by Red Shifter
|
||||
// A far cry to the solution of noFog, but this'll stop the snipes
|
||||
// This is a Server-Side Script
|
||||
|
||||
package antiNoFogSnipe {
|
||||
|
||||
function DefaultGame::missionLoadDone(%game) {
|
||||
|
||||
Parent::missionLoadDone(%game);
|
||||
|
||||
if (Sky.visibleDistance $= "" || Sky.visibleDistance == 0) {
|
||||
// This script plays it safe. You better have a map that works.
|
||||
error("WARNING! This map will not work with NoFog Snipe!");
|
||||
BasicSniperShot.maxRifleRange = 1000;
|
||||
}
|
||||
else
|
||||
BasicSniperShot.maxRifleRange = Sky.visibleDistance;
|
||||
}
|
||||
|
||||
};
|
||||
activatePackage(antiNoFogSnipe);
|
||||
77
Classic/scripts/autoexec/checkver.cs
Normal file
77
Classic/scripts/autoexec/checkver.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// TribesNext Minimum Version Enforcement
|
||||
// Written by Thyth
|
||||
// 2014-08-18
|
||||
|
||||
// Updated on 2014-08-31 after testing/feedback from Heat Killer.
|
||||
|
||||
// This script prevents clients from joining a non-observer team if they are not running
|
||||
// TribesNext RC2a or newer, with the tournamentNetClient.vl2 installed. An early form of
|
||||
// anticheat was added to the RC2 patch that kills HM2. This script allows detecting of
|
||||
// a new enough version by the interaction with the TribesNext community/browser system.
|
||||
// Support for clan tags (and account renaming) was added along with the HM2 killer in RC2,
|
||||
// but no client side code to talk to the browser server was in yet. Now that the browser
|
||||
// system backend is complete, all clients can install the tournamentNetClient to the
|
||||
// browser, and users running RC2 (with HM2 killer) can be detected.
|
||||
|
||||
// The variable on the client object:
|
||||
// %client.t2csri_sentComCertDone
|
||||
// Will be 1 if they are running RC2+ with tournamentNetClient.vl2
|
||||
|
||||
// Admins can override this restriction when forcing players to join a team.
|
||||
|
||||
function checkVer_showBanner(%client)
|
||||
{
|
||||
// customize me
|
||||
commandToClient(%client, 'CenterPrint', "<font:Sui Generis:22><color:3cb4b4>Version Check Failed!\n<font:Univers:16><color:3cb4b4>You need the latest TribesNext patch and TournyNetClient to play.\n Download it from T2Discord.tk and drop it into your GameData/Base folder.", 10, 3);
|
||||
}
|
||||
|
||||
package checkver
|
||||
{
|
||||
function serverCmdClientJoinTeam(%client, %team)
|
||||
{
|
||||
if (!%client.t2csri_sentComCertDone)
|
||||
{
|
||||
checkVer_showBanner(%client);
|
||||
return;
|
||||
}
|
||||
Parent::serverCmdClientJoinTeam(%client, %team);
|
||||
}
|
||||
function serverCmdClientJoinGame(%client)
|
||||
{
|
||||
if (!%client.t2csri_sentComCertDone)
|
||||
{
|
||||
checkVer_showBanner(%client);
|
||||
return;
|
||||
}
|
||||
Parent::serverCmdClientJoinGame(%client);
|
||||
}
|
||||
function serverCmdClientPickedTeam(%client, %option)
|
||||
{
|
||||
if (!%client.t2csri_sentComCertDone)
|
||||
{
|
||||
checkVer_showBanner(%client);
|
||||
return;
|
||||
}
|
||||
Parent::serverCmdClientPickedTeam(%client, %option);
|
||||
}
|
||||
function serverCmdClientTeamChange(%client, %option)
|
||||
{
|
||||
if (!%client.t2csri_sentComCertDone)
|
||||
{
|
||||
checkVer_showBanner(%client);
|
||||
return;
|
||||
}
|
||||
Parent::serverCmdClientTeamChange(%client, %option);
|
||||
}
|
||||
function Observer::onTrigger(%data, %obj, %trigger, %state)
|
||||
{
|
||||
%client = %obj.getControllingClient();
|
||||
if (!%client.t2csri_sentComCertDone)
|
||||
{
|
||||
checkVer_showBanner(%client);
|
||||
return;
|
||||
}
|
||||
Parent::onTrigger(%data, %obj, %trigger, %state);
|
||||
}
|
||||
};
|
||||
activatePackage(checkver);
|
||||
19
Classic/scripts/autoexec/noMortarTurret.cs
Normal file
19
Classic/scripts/autoexec/noMortarTurret.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// ban mortar turret from inventory in main gametypes
|
||||
$InvBanList[CTF, "MortarBarrelPack"] = 1;
|
||||
$InvBanList[CnH, "MortarBarrelPack"] = 1;
|
||||
$InvBanList[Siege, "MortarBarrelPack"] = 1;
|
||||
|
||||
package noMortarTurret {
|
||||
|
||||
// if a mortar turret somehow makes it into the game, keep it from working
|
||||
function TurretData::selectTarget(%this, %turret) {
|
||||
if( %turret.initialBarrel !$= "MortarBarrelLarge" ) {
|
||||
Parent::selectTarget(%this, %turret);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Prevent package from being activated if it is already
|
||||
if (!isActivePackage( noMortarTurret ))
|
||||
activatePackage( noMortarTurret );
|
||||
13
Classic/scripts/autoexec/packetsettings.cs
Normal file
13
Classic/scripts/autoexec/packetsettings.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
$pref::Net::PacketRateToClient = "32"; //determines how many packets per second sent to each client
|
||||
$pref::Net::PacketRateToServer = "32"; //may determine how many packets are allowed from each client
|
||||
$pref::Net::PacketSize = "450"; //size of each packet sent to each client, maximum.has no effect on size of packets client send to the server
|
||||
|
||||
|
||||
setlogmode(0);
|
||||
// leave this set to zero unless you are coding and need a log it will make a huge file...!!!
|
||||
|
||||
$logechoenabled=0;
|
||||
//set to 1 you can now see game details in console. Thanks to tubaguy.
|
||||
|
||||
SetPerfCounterEnable(0);
|
||||
//server stutter fix
|
||||
8
Classic/scripts/autoexec/security.cs
Normal file
8
Classic/scripts/autoexec/security.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
memPatch("A3C300","A370C3A300E8D609A0FF8B46205053E98103A0FF");
|
||||
memPatch("A3C330","C70570C3A30000000000E8A109A0FF8B462085C0E96D03A0FF");
|
||||
memPatch("A3C400","E80BFB9FFF6089C38B1570C3A300B8FF00000029D039C37D0661E92509A0FFA380C3A30061A180C3A300E91509A0FF");
|
||||
memPatch("A3C430","E8DBFA9FFF6089C38B1570C3A300B8FF00000029D039C37D0661E9A009A0FFA380C3A30061A180C3A300E99009A0FF");
|
||||
memPatch("43C68B","E970FC5F00");
|
||||
memPatch("43C6AC","E97FFC5F00");
|
||||
memPatch("43CD3F","E9BCF65F00");
|
||||
memPatch("43CDEA","E941F65F00");
|
||||
3948
Classic/scripts/defaultGame.cs
Normal file
3948
Classic/scripts/defaultGame.cs
Normal file
File diff suppressed because it is too large
Load diff
637
Classic/scripts/inventory.cs
Normal file
637
Classic/scripts/inventory.cs
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
//----------------------------------------------------------------------------
|
||||
|
||||
// Item Datablocks
|
||||
// image = Name of mounted image datablock
|
||||
// onUse(%this,%object)
|
||||
|
||||
// Item Image Datablocks
|
||||
// item = Name of item inventory datablock
|
||||
|
||||
// ShapeBase Datablocks
|
||||
// max[Item] = Maximum amount that can be caried
|
||||
|
||||
// ShapeBase Objects
|
||||
// inv[Item] = Count of item in inventory
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
$TestCheats = 0;
|
||||
|
||||
function serverCmdUse(%client,%data)
|
||||
{
|
||||
// Item names from the client must converted
|
||||
// into DataBlocks
|
||||
// %data = ItemDataBlock[%item];
|
||||
if(isObject(%client.player)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
%client.getControlObject().use(%data);
|
||||
}
|
||||
|
||||
function serverCmdThrow(%client,%data)
|
||||
{
|
||||
// Item names from the client must converted
|
||||
// into DataBlocks
|
||||
// %data = ItemDataBlock[%item];
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// z0dd - ZOD, 4/18/02. Let one keybind handle all grenade types.
|
||||
if(isObject(%client.player)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
{
|
||||
if(%data $= Grenade)
|
||||
{
|
||||
// figure out which grenade type you're using
|
||||
for(%x = 0; $InvGrenade[%x] !$= ""; %x++)
|
||||
{
|
||||
if(%client.getControlObject().inv[$NameToInv[$InvGrenade[%x]]] > 0)
|
||||
{
|
||||
%data = $NameToInv[$InvGrenade[%x]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
%client.getControlObject().throw(%data);
|
||||
}
|
||||
else if(%data $= Mine)
|
||||
{
|
||||
for(%x = 0; $InvMine[%x] !$= ""; %x++)
|
||||
{
|
||||
if(%client.getControlObject().inv[$NameToInv[$InvMine[%x]]] > 0)
|
||||
{
|
||||
%data = $NameToInv[$InvMine[%x]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
%client.getControlObject().throw(%data);
|
||||
}
|
||||
else if(%data $= "Ammo")
|
||||
{
|
||||
%weapon = %client.getControlObject().getMountedImage($WeaponSlot);
|
||||
if(%weapon !$= "")
|
||||
{
|
||||
if(%weapon.ammo !$= "")
|
||||
%client.getControlObject().throw(%weapon.ammo);
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
%client.getControlObject().throw(%data);
|
||||
}
|
||||
}
|
||||
|
||||
function serverCmdThrowWeapon(%client,%data)
|
||||
{
|
||||
// Item names from the client must converted
|
||||
// into DataBlocks
|
||||
// %data = ItemDataBlock[%item];
|
||||
if(isObject(%client.player)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
%client.getControlObject().throwWeapon();
|
||||
}
|
||||
|
||||
function serverCmdThrowPack(%client,%data)
|
||||
{
|
||||
if(isObject(%client.player)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
%client.getControlObject().throwPack();
|
||||
}
|
||||
|
||||
function serverCmdTogglePack(%client,%data)
|
||||
{
|
||||
// this function is apparently never called
|
||||
%client.getControlObject().togglePack();
|
||||
}
|
||||
|
||||
function serverCmdThrowFlag(%client)
|
||||
{
|
||||
//Game.playerDroppedFlag(%client.player);
|
||||
Game.dropFlag(%client.player);
|
||||
}
|
||||
|
||||
function serverCmdSelectWeaponSlot( %client, %data )
|
||||
{
|
||||
if(isObject(%client.player)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
%client.getControlObject().selectWeaponSlot( %data );
|
||||
}
|
||||
|
||||
function serverCmdCycleWeapon( %client, %data )
|
||||
{
|
||||
if(isObject(%client.player)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
%client.getControlObject().cycleWeapon( %data );
|
||||
}
|
||||
|
||||
function serverCmdStartThrowCount(%client, %data)
|
||||
{
|
||||
%client.player.throwStart = getSimTime();
|
||||
}
|
||||
|
||||
$maxThrowStr = 2.2; // z0dd - ZOD, 8/6/02. New throw str features
|
||||
|
||||
function serverCmdEndThrowCount(%client, %data)
|
||||
{
|
||||
if(%client.player.throwStart == 5)
|
||||
return;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// z0dd - ZOD, 8/6/02. New throw str features
|
||||
%throwStrength = (getSimTime() - %client.player.throwStart) / 150;
|
||||
if(%throwStrength > $maxThrowStr)
|
||||
%throwStrength = $maxThrowStr;
|
||||
else if(%throwStrength < 0.5)
|
||||
%throwStrength = 0.5;
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
%throwScale = %throwStrength / 2;
|
||||
%client.player.throwStrength = %throwScale;
|
||||
|
||||
%client.player.throwStart = 5;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// z0dd - ZOD, 9/27/02. No buildup power. Rewrote function
|
||||
function serverCmdthrowMaxEnd(%client, %data)
|
||||
{
|
||||
%client.player.throwStrength = $maxThrowStr / 2;
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
function ShapeBase::throwWeapon(%this)
|
||||
{
|
||||
if(Game.shapeThrowWeapon(%this)) {
|
||||
%image = %this.getMountedImage($WeaponSlot);
|
||||
%this.throw(%image.item);
|
||||
%this.client.setWeaponsHudItem(%image.item, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function ShapeBase::throwPack(%this)
|
||||
{
|
||||
if(isObject(%this)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
{
|
||||
%image = %this.getMountedImage($BackpackSlot);
|
||||
%this.throw(%image.item);
|
||||
%this.client.setBackpackHudItem(%image.item, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function ShapeBase::throw(%this,%data)
|
||||
{
|
||||
if(!isObject(%data))
|
||||
return false;
|
||||
|
||||
if (%this.inv[%data.getName()] > 0) {
|
||||
|
||||
// save off the ammo count on this item
|
||||
if( %this.getInventory( %data ) < $AmmoIncrement[%data.getName()] )
|
||||
%data.ammoStore = %this.getInventory( %data );
|
||||
else
|
||||
%data.ammoStore = $AmmoIncrement[%data.getName()];
|
||||
|
||||
// Throw item first...
|
||||
%this.throwItem(%data);
|
||||
if($AmmoIncrement[%data.getName()] !$= "")
|
||||
%this.decInventory(%data,$AmmoIncrement[%data.getName()]);
|
||||
else
|
||||
%this.decInventory(%data,1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function ShapeBase::use(%this, %data)
|
||||
{
|
||||
//if(%data.class $= "Weapon") {
|
||||
// error("ShapeBase::use " @ %data);
|
||||
//}
|
||||
if(isObject(%this) && %data !$= "") // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
{
|
||||
if(%data $= Grenade)
|
||||
{
|
||||
// figure out which grenade type you're using
|
||||
for(%x = 0; $InvGrenade[%x] !$= ""; %x++) {
|
||||
if(%this.inv[$NameToInv[$InvGrenade[%x]]] > 0)
|
||||
{
|
||||
%data = $NameToInv[$InvGrenade[%x]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(%data $= Mine) // z0dd - ZOD, 5/18/03. For more mine types
|
||||
{
|
||||
// figure out which mine type you're using
|
||||
for(%m = 0; $InvMine[%m] !$= ""; %m++) {
|
||||
if(%this.inv[$NameToInv[$InvMine[%m]]] > 0)
|
||||
{
|
||||
%data = $NameToInv[$InvMine[%m]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(%data $= "Backpack") {
|
||||
%pack = %this.getMountedImage($BackpackSlot);
|
||||
// if you don't have a pack but have placed a satchel charge, detonate it
|
||||
if(!%pack && (%this.thrownChargeId > 0) && %this.thrownChargeId.armed )
|
||||
{
|
||||
%this.playAudio( 0, SatchelChargeExplosionSound );
|
||||
schedule( 600, %this, "detonateSatchelCharge", %this ); // z0dd - ZOD, 8/24/02. Time after pressing fire that satchel blows. Was 800
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if(%data $= Beacon)
|
||||
{
|
||||
%data.onUse(%this);
|
||||
if (%this.inv[%data.getName()] > 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// default case
|
||||
if (%this.inv[%data.getName()] > 0) {
|
||||
%data.onUse(%this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function ShapeBase::pickup(%this,%obj,%amount)
|
||||
{
|
||||
%data = %obj.getDatablock();
|
||||
%delta = %this.incInventory(%data,%amount);
|
||||
|
||||
if (%delta)
|
||||
%data.onPickup(%obj,%this,%delta);
|
||||
return %delta;
|
||||
}
|
||||
|
||||
function ShapeBase::hasInventory(%this, %data)
|
||||
{
|
||||
// changed because it was preventing weapons cycling correctly (MES)
|
||||
return (%this.inv[%data] > 0);
|
||||
}
|
||||
|
||||
function ShapeBase::maxInventory(%this, %data)
|
||||
{
|
||||
//error("ShapeBase::maxInventory( " @ %this.client.nameBase @ ", " @ %data @ " )");
|
||||
if(isObject(%data)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
{
|
||||
if($TestCheats)
|
||||
return 999;
|
||||
else
|
||||
return %this.getDatablock().max[%data.getName()];
|
||||
}
|
||||
}
|
||||
|
||||
function ShapeBase::incInventory(%this, %data, %amount)
|
||||
{
|
||||
if(isObject(%data)) // z0dd - ZOD, 5/18/03. Console spam fix
|
||||
{
|
||||
%max = %this.maxInventory(%data);
|
||||
%cv = %this.inv[%data.getName()];
|
||||
if (%cv < %max) {
|
||||
if (%cv + %amount > %max)
|
||||
%amount = %max - %cv;
|
||||
|
||||
%this.setInventory(%data,%cv + %amount);
|
||||
%data.incCatagory(%this); // Inc the players weapon count
|
||||
return %amount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function ShapeBase::decInventory(%this,%data,%amount)
|
||||
{
|
||||
%name = %data.getName();
|
||||
%cv = %this.inv[%name];
|
||||
if (%cv > 0) {
|
||||
if (%cv < %amount)
|
||||
%amount = %cv;
|
||||
%this.setInventory(%data,%cv - %amount, true);
|
||||
%data.decCatagory(%this); // Dec the players weapon count
|
||||
return %amount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function SimObject::decCatagory(%this)
|
||||
{
|
||||
//function was added to reduce console err msg spam
|
||||
}
|
||||
|
||||
function SimObject::incCatagory(%this)
|
||||
{
|
||||
//function was added to reduce console err msg spam
|
||||
}
|
||||
|
||||
function ShapeBase::setInventory(%this,%data,%value,%force)
|
||||
{
|
||||
if (!isObject(%data))
|
||||
return;
|
||||
|
||||
%name = %data.getName();
|
||||
if (%value < 0)
|
||||
%value = 0;
|
||||
else
|
||||
{
|
||||
if (!%force)
|
||||
{
|
||||
// Impose inventory limits
|
||||
%max = %this.maxInventory(%data);
|
||||
if (%value > %max)
|
||||
%value = %max;
|
||||
}
|
||||
}
|
||||
if (%this.inv[%name] != %value)
|
||||
{
|
||||
%this.inv[%name] = %value;
|
||||
%data.onInventory(%this,%value);
|
||||
|
||||
if ( %data.className $= "Weapon" )
|
||||
{
|
||||
if ( %this.weaponSlotCount $= "" )
|
||||
%this.weaponSlotCount = 0;
|
||||
|
||||
%cur = -1;
|
||||
for ( %slot = 0; %slot < %this.weaponSlotCount; %slot++ )
|
||||
{
|
||||
if ( %this.weaponSlot[%slot] $= %name )
|
||||
{
|
||||
%cur = %slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( %cur == -1 )
|
||||
{
|
||||
// Put this weapon in the next weapon slot:
|
||||
if ( %this.weaponSlot[%this.weaponSlotCount - 1] $= "TargetingLaser" )
|
||||
{
|
||||
%this.weaponSlot[%this.weaponSlotCount - 1] = %name;
|
||||
%this.weaponSlot[%this.weaponSlotCount] = "TargetingLaser";
|
||||
}
|
||||
else
|
||||
%this.weaponSlot[%this.weaponSlotCount] = %name;
|
||||
%this.weaponSlotCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the weapon from the weapon slot:
|
||||
for ( %i = %cur; %i < %this.weaponSlotCount - 1; %i++ )
|
||||
%this.weaponSlot[%i] = %this.weaponSlot[%i + 1];
|
||||
%this.weaponSlot[%i] = "";
|
||||
%this.weaponSlotCount--;
|
||||
}
|
||||
}
|
||||
|
||||
%this.getDataBlock().onInventory(%data,%value);
|
||||
}
|
||||
return %value;
|
||||
}
|
||||
|
||||
function ShapeBase::getInventory(%this,%data)
|
||||
{
|
||||
if ( isObject( %data ) )
|
||||
return( %this.inv[%data.getName()] );
|
||||
else
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
// z0dd - ZOD, 9/13/02. Streamlined.
|
||||
function ShapeBase::hasAmmo( %this, %weapon )
|
||||
{
|
||||
if(%weapon $= LaserRifle)
|
||||
return( %this.getInventory( EnergyPack ) );
|
||||
|
||||
if (%weapon.image.ammo $= "")
|
||||
{
|
||||
if (%weapon $= TargetingLaser)
|
||||
{
|
||||
return( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
return( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return( %this.getInventory( %weapon.image.ammo ) > 0 );
|
||||
}
|
||||
}
|
||||
|
||||
function SimObject::onInventory(%this, %obj)
|
||||
{
|
||||
//function was added to reduce console error msg spam
|
||||
}
|
||||
|
||||
function ShapeBase::throwItem(%this,%data)
|
||||
{
|
||||
%item = new Item() {
|
||||
dataBlock = %data;
|
||||
rotation = "0 0 1 " @ (getRandom() * 360);
|
||||
};
|
||||
|
||||
%item.ammoStore = %data.ammoStore;
|
||||
MissionCleanup.add(%item);
|
||||
%this.throwObject(%item);
|
||||
}
|
||||
|
||||
function ShapeBase::throwObject(%this,%obj)
|
||||
{
|
||||
//------------------------------------------------------------------
|
||||
// z0dd - ZOD, 4/15/02. Allow respawn switching during tourney wait.
|
||||
if(!$MatchStarted)
|
||||
return;
|
||||
//------------------------------------------------------------------
|
||||
|
||||
// z0dd - ZOD, 5/26/02. Remove anti-hover so flag can be thrown properly
|
||||
if(%obj.getDataBlock().getName() $= "Flag")
|
||||
{
|
||||
%obj.static = false;
|
||||
// z0dd - ZOD - SquirrelOfDeath, 10/02/02. Hack for flag collision bug.
|
||||
if(Game.Class $= CTFGame || Game.Class $= PracticeCTFGame)
|
||||
%obj.searchSchedule = Game.schedule(10, "startFlagCollisionSearch", %obj);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
||||
%srcCorpse = (%this.getState() $= "Dead"); // z0dd - ZOD, 4/14/02. Flag tossed from corpse
|
||||
//if the object is being thrown by a corpse, use a random vector
|
||||
if (%srcCorpse && %obj.getDataBlock().getName() !$= "Flag") // z0dd - ZOD, 4/14/02. Except for flags..
|
||||
{
|
||||
%vec = (-1.0 + getRandom() * 2.0) SPC (-1.0 + getRandom() * 2.0) SPC getRandom();
|
||||
%vec = vectorScale(%vec, 10);
|
||||
}
|
||||
else // else Initial vel based on the dir the player is looking
|
||||
{
|
||||
%eye = %this.getEyeVector();
|
||||
%vec = vectorScale(%eye, 20);
|
||||
}
|
||||
|
||||
// Add a vertical component to give the item a better arc
|
||||
%dot = vectorDot("0 0 1",%eye);
|
||||
if (%dot < 0)
|
||||
%dot = -%dot;
|
||||
%vec = vectorAdd(%vec,vectorScale("0 0 12",1 - %dot)); // z0dd - ZOD, 9/10/02. 10 was 8
|
||||
|
||||
// Add player's velocity
|
||||
%vec = vectorAdd(%vec,%this.getVelocity());
|
||||
%pos = getBoxCenter(%this.getWorldBox());
|
||||
|
||||
//since flags have a huge mass (so when you shoot them, they don't bounce too far)
|
||||
//we need to up the %vec so that you can still throw them...
|
||||
if (%obj.getDataBlock().getName() $= "Flag")
|
||||
{
|
||||
if ($CurrentMissionType $= "sctf")
|
||||
%vec = vectorScale(%vec, (%srcCorpse ? 50 : 95)); // Added so SCtF gets more force for Flag passes
|
||||
else
|
||||
%vec = vectorScale(%vec, (%srcCorpse ? 40 : 75)); // z0dd - ZOD, 4/14/02. Throw flag force. Value was 40
|
||||
// ------------------------------------------------------------
|
||||
// z0dd - ZOD, 9/27/02. Delay on grabbing flag after tossing it
|
||||
%this.flagTossWait = true;
|
||||
%this.schedule(1000, resetFlagTossWait);
|
||||
// ------------------------------------------------------------
|
||||
}
|
||||
|
||||
//
|
||||
%obj.setTransform(%pos);
|
||||
%obj.applyImpulse(%pos,%vec);
|
||||
%obj.setCollisionTimeout(%this);
|
||||
%data = %obj.getDatablock();
|
||||
|
||||
%data.onThrow(%obj,%this);
|
||||
|
||||
//call the AI hook
|
||||
AIThrowObject(%obj);
|
||||
}
|
||||
|
||||
function ShapeBase::clearInventory(%this)
|
||||
{
|
||||
// z0dd - ZOD, 5/18/03. Auto cleanup of weapons and ammo. Streamline
|
||||
for(%i = 0; %i < $WeaponsHudCount; %i++)
|
||||
{
|
||||
%this.setInventory($WeaponsHudData[%i, itemDataName], 0);
|
||||
if($WeaponsHudData[%i, ammoDataName] !$= "")
|
||||
%this.setInventory($WeaponsHudData[%i, ammoDataName], 0);
|
||||
}
|
||||
for(%i = 0; $InvGrenade[%i] !$= ""; %i++)
|
||||
%this.setInventory($NameToInv[$InvGrenade[%i]], 0);
|
||||
|
||||
for(%i = 0; $InvMine[%i] !$= ""; %i++)
|
||||
%this.setInventory($NameToInv[$InvMine[%i]], 0);
|
||||
|
||||
%this.setInventory(RepairKit, 0);
|
||||
%this.setInventory(Beacon, 0);
|
||||
|
||||
// take away any pack the player has
|
||||
%curPack = %this.getMountedImage($BackpackSlot);
|
||||
if(%curPack > 0)
|
||||
%this.setInventory(%curPack.item, 0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
function ShapeBase::cycleWeapon( %this, %data )
|
||||
{
|
||||
if ( %this.weaponSlotCount == 0 )
|
||||
return;
|
||||
|
||||
%slot = -1;
|
||||
if ( %this.getMountedImage($WeaponSlot) != 0 )
|
||||
{
|
||||
%curWeapon = %this.getMountedImage($WeaponSlot).item.getName();
|
||||
for ( %i = 0; %i < %this.weaponSlotCount; %i++ )
|
||||
{
|
||||
//error("curWeaponName == " @ %curWeaponName);
|
||||
if ( %curWeapon $= %this.weaponSlot[%i] )
|
||||
{
|
||||
%slot = %i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( %data $= "prev" )
|
||||
{
|
||||
// Previous weapon...
|
||||
if ( %slot == 0 || %slot == -1 )
|
||||
{
|
||||
%i = %this.weaponSlotCount - 1;
|
||||
%slot = 0;
|
||||
}
|
||||
else
|
||||
%i = %slot - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Next weapon...
|
||||
if ( %slot == ( %this.weaponSlotCount - 1 ) || %slot == -1 )
|
||||
{
|
||||
%i = 0;
|
||||
%slot = ( %this.weaponSlotCount - 1 );
|
||||
}
|
||||
else
|
||||
%i = %slot + 1;
|
||||
}
|
||||
|
||||
%newSlot = -1;
|
||||
while ( %i != %slot )
|
||||
{
|
||||
if ( %this.weaponSlot[%i] !$= ""
|
||||
&& %this.hasInventory( %this.weaponSlot[%i] )
|
||||
&& %this.hasAmmo( %this.weaponSlot[%i] ) )
|
||||
{
|
||||
// player has this weapon and it has ammo or doesn't need ammo
|
||||
%newSlot = %i;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( %data $= "prev" )
|
||||
{
|
||||
if ( %i == 0 )
|
||||
%i = %this.weaponSlotCount - 1;
|
||||
else
|
||||
%i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( %i == ( %this.weaponSlotCount - 1 ) )
|
||||
%i = 0;
|
||||
else
|
||||
%i++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( %newSlot != -1 )
|
||||
%this.use( %this.weaponSlot[%newSlot] );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
function ShapeBase::selectWeaponSlot( %this, %data )
|
||||
{
|
||||
if ( %data < 0 || %data > %this.weaponSlotCount
|
||||
|| %this.weaponSlot[%data] $= "" || %this.weaponSlot[%data] $= "TargetingLaser" )
|
||||
return;
|
||||
|
||||
%this.use( %this.weaponSlot[%data] );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
function serverCmdGiveAll(%client)
|
||||
{
|
||||
if($TestCheats)
|
||||
{
|
||||
%player = %client.player;
|
||||
// z0dd - ZOD, 5/18/03. Auto increment of weapons and ammo. Streamline
|
||||
for(%i = 0; %i < $WeaponsHudCount; %i++)
|
||||
{
|
||||
%player.setInventory($WeaponsHudData[%i, itemDataName], 1);
|
||||
if($WeaponsHudData[%i, ammoDataName] !$= "")
|
||||
%player.setInventory($WeaponsHudData[%i, ammoDataName], 999);
|
||||
}
|
||||
for(%i = 0; $InvGrenade[%i] !$= ""; %i++)
|
||||
%player.setInventory($NameToInv[$InvGrenade[%i]], 0);
|
||||
|
||||
for(%i = 0; $InvMine[%i] !$= ""; %i++)
|
||||
%player.setInventory($NameToInv[$InvMine[%i]], 0);
|
||||
|
||||
%player.setInventory(RepairKit, 999);
|
||||
%player.setInventory(Beacon, 999);
|
||||
%player.setInventory(RocketCannonAmmo, 999);
|
||||
}
|
||||
}
|
||||
1171
Classic/scripts/inventoryHud.cs
Normal file
1171
Classic/scripts/inventoryHud.cs
Normal file
File diff suppressed because it is too large
Load diff
147
Classic/scripts/packs/sensorjammerpack.cs
Normal file
147
Classic/scripts/packs/sensorjammerpack.cs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// ------------------------------------------------------------------
|
||||
// SENSOR JAMMER PACK
|
||||
//
|
||||
// When activated, the sensor jammer pack emits a sensor-jamming field of
|
||||
// 20m radius. Any players within this field are completely invisible to
|
||||
// all sensors, turrets and cameras.
|
||||
//
|
||||
// When not activated, the pack has no effect.
|
||||
//
|
||||
datablock EffectProfile(SensorJammerPackActivateEffect)
|
||||
{
|
||||
effectname = "packs/cloak_on";
|
||||
minDistance = 2.5;
|
||||
maxDistance = 2.5;
|
||||
};
|
||||
|
||||
datablock AudioProfile(SensorJammerActivateSound)
|
||||
{
|
||||
filename = "fx/packs/sensorjammerpack_on.wav";
|
||||
description = ClosestLooping3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock ShapeBaseImageData(SensorJammerPackImage)
|
||||
{
|
||||
shapeFile = "pack_upgrade_sensorjammer.dts";
|
||||
item = SensorJammerPack;
|
||||
mountPoint = 1;
|
||||
offset = "0 0 0";
|
||||
|
||||
usesEnergy = true;
|
||||
minEnergy = 3;
|
||||
|
||||
stateName[0] = "Idle";
|
||||
stateTransitionOnTriggerDown[0] = "Activate";
|
||||
|
||||
stateName[1] = "Activate";
|
||||
stateScript[1] = "onActivate";
|
||||
stateSequence[1] = "fire";
|
||||
stateSound[1] = SensorJammerActivateSound;
|
||||
stateEnergyDrain[1] = 10.5;
|
||||
stateTransitionOnTriggerUp[1] = "Deactivate";
|
||||
stateTransitionOnNoAmmo[1] = "Deactivate";
|
||||
|
||||
stateName[2] = "Deactivate";
|
||||
stateScript[2] = "onDeactivate";
|
||||
stateTransitionOnTimeout[2] = "Idle";
|
||||
};
|
||||
|
||||
datablock ItemData(SensorJammerPack)
|
||||
{
|
||||
className = Pack;
|
||||
catagory = "Packs";
|
||||
shapeFile = "pack_upgrade_sensorjammer.dts";
|
||||
mass = 1;
|
||||
elasticity = 0.2;
|
||||
friction = 0.6;
|
||||
pickupRadius = 2;
|
||||
rotate = true;
|
||||
image = "SensorJammerPackImage";
|
||||
pickUpName = "a sensor jammer pack";
|
||||
|
||||
computeCRC = true;
|
||||
};
|
||||
|
||||
|
||||
datablock SensorData(JammerSensorObjectPassive) //v2 was commented out...
|
||||
{
|
||||
// same detection info as 'PlayerObject' sensorData
|
||||
detects = true;
|
||||
detectsUsingLOS = true;
|
||||
detectsPassiveJammed = true;
|
||||
detectRadius = 2000;
|
||||
detectionPings = false;
|
||||
detectsFOVOnly = true;
|
||||
detectFOVPercent = 1.3;
|
||||
useObjectFOV = true;
|
||||
|
||||
//detectscloaked = 1; //v2
|
||||
|
||||
jams = true;
|
||||
jamsOnlyGroup = true;
|
||||
jamsUsingLOS = true;
|
||||
jamRadius = 0;
|
||||
};
|
||||
|
||||
datablock SensorData(JammerSensorObjectActive)
|
||||
{
|
||||
// same detection info as 'PlayerObject' sensorData
|
||||
detects = true;
|
||||
detectsUsingLOS = true;
|
||||
detectsPassiveJammed = true;
|
||||
detectRadius = 2000;
|
||||
detectionPings = false;
|
||||
detectsFOVOnly = true;
|
||||
detectFOVPercent = 1.3;
|
||||
useObjectFOV = true;
|
||||
|
||||
detectscloaked = 1; //v2
|
||||
|
||||
jams = true;
|
||||
jamsOnlyGroup = true;
|
||||
jamsUsingLOS = true;
|
||||
jamRadius = 30;
|
||||
};
|
||||
|
||||
function SensorJammerPackImage::onMount(%data, %obj, %slot)
|
||||
{
|
||||
setTargetSensorData(%obj.client.target, JammerSensorObjectPassive); //v2
|
||||
%obj.setImageTrigger(%slot, false);
|
||||
commandToClient( %obj.client, 'setSenJamIconOff' );
|
||||
//%obj.setJammerFX(false);
|
||||
}
|
||||
|
||||
function deactivateJammer(%data, %obj, %slot)
|
||||
{
|
||||
SensorJammerPackImage::onDeactivate(%data, %obj, %slot);
|
||||
}
|
||||
|
||||
function SensorJammerPackImage::onUnmount(%data, %obj, %slot) //v2
|
||||
{
|
||||
%obj.setImageTrigger(%slot, false);
|
||||
setTargetSensorData(%obj.client.target, PlayerSensor);
|
||||
}
|
||||
|
||||
function SensorJammerPackImage::onActivate(%data, %obj, %slot)
|
||||
{
|
||||
messageClient(%obj.client, 'MsgSensorJammerPackOn', '\c2Sensor jammer pack on.');
|
||||
setTargetSensorData(%obj.client.target, JammerSensorObjectActive);
|
||||
commandToClient( %obj.client, 'setSenJamIconOn' );
|
||||
//%obj.setJammerFX( true );
|
||||
}
|
||||
|
||||
function SensorJammerPackImage::onDeactivate(%data, %obj, %slot)
|
||||
{
|
||||
messageClient(%obj.client, 'MsgSensorJammerPackOff', '\c2Sensor jammer pack off.');
|
||||
setTargetSensorData(%obj.client.target, PlayerSensor); //v2 H bug fix
|
||||
%obj.setImageTrigger(%slot, false);
|
||||
setTargetSensorData(%obj.client.target, JammerSensorObjectPassive); //v2 was PlayerSensor
|
||||
commandToClient( %obj.client, 'setSenJamIconOff' );
|
||||
//%obj.setJammerFX( false );
|
||||
}
|
||||
|
||||
function SensorJammerPack::onPickup(%this, %obj, %shape, %amount)
|
||||
{
|
||||
//Nope
|
||||
}
|
||||
3297
Classic/scripts/player.cs
Normal file
3297
Classic/scripts/player.cs
Normal file
File diff suppressed because it is too large
Load diff
3187
Classic/scripts/server.cs
Normal file
3187
Classic/scripts/server.cs
Normal file
File diff suppressed because it is too large
Load diff
1162
Classic/scripts/station.cs
Normal file
1162
Classic/scripts/station.cs
Normal file
File diff suppressed because it is too large
Load diff
1698
Classic/scripts/vehicles/vehicle.cs
Normal file
1698
Classic/scripts/vehicles/vehicle.cs
Normal file
File diff suppressed because it is too large
Load diff
788
Classic/scripts/weapons/grenadeLauncher.cs
Normal file
788
Classic/scripts/weapons/grenadeLauncher.cs
Normal file
|
|
@ -0,0 +1,788 @@
|
|||
//--------------------------------------
|
||||
// Grenade launcher
|
||||
//--------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Force-Feedback Effects
|
||||
//--------------------------------------
|
||||
datablock EffectProfile(GrenadeSwitchEffect)
|
||||
{
|
||||
effectname = "weapons/generic_switch";
|
||||
minDistance = 2.5;
|
||||
maxDistance = 2.5;
|
||||
};
|
||||
|
||||
datablock EffectProfile(GrenadeFireEffect)
|
||||
{
|
||||
effectname = "weapons/grenadelauncher_fire";
|
||||
minDistance = 2.5;
|
||||
maxDistance = 2.5;
|
||||
};
|
||||
|
||||
datablock EffectProfile(GrenadeDryFireEffect)
|
||||
{
|
||||
effectname = "weapons/grenadelauncher_dryfire";
|
||||
minDistance = 2.5;
|
||||
maxDistance = 2.5;
|
||||
};
|
||||
|
||||
datablock EffectProfile(GrenadeReloadEffect)
|
||||
{
|
||||
effectname = "weapons/generic_switch";
|
||||
minDistance = 2.5;
|
||||
maxDistance = 2.5;
|
||||
};
|
||||
|
||||
datablock EffectProfile(GrenadeExplosionEffect)
|
||||
{
|
||||
effectname = "explosions/grenade_explode";
|
||||
minDistance = 10;
|
||||
maxDistance = 35;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Sounds
|
||||
//--------------------------------------
|
||||
datablock AudioProfile(GrenadeSwitchSound)
|
||||
{
|
||||
filename = "fx/weapons/generic_switch.wav";
|
||||
description = AudioClosest3d;
|
||||
preload = true;
|
||||
effect = GrenadeSwitchEffect;
|
||||
};
|
||||
|
||||
datablock AudioProfile(GrenadeFireSound)
|
||||
{
|
||||
filename = "fx/weapons/grenadelauncher_fire.wav";
|
||||
description = AudioDefault3d;
|
||||
preload = true;
|
||||
effect = GrenadeFireEffect;
|
||||
};
|
||||
|
||||
datablock AudioProfile(GrenadeProjectileSound)
|
||||
{
|
||||
filename = "fx/weapons/grenadelauncher_projectile.wav";
|
||||
description = ProjectileLooping3d;
|
||||
preload = true;
|
||||
};
|
||||
|
||||
datablock AudioProfile(GrenadeReloadSound)
|
||||
{
|
||||
filename = "fx/weapons/generic_switch.wav";
|
||||
description = AudioClosest3d;
|
||||
preload = true;
|
||||
effect = GrenadeReloadEffect;
|
||||
};
|
||||
|
||||
datablock AudioProfile(GrenadeExplosionSound)
|
||||
{
|
||||
filename = "fx/weapons/grenade_explode.wav";
|
||||
description = AudioExplosion3d;
|
||||
preload = true;
|
||||
effect = GrenadeExplosionEffect;
|
||||
};
|
||||
|
||||
datablock AudioProfile(UnderwaterGrenadeExplosionSound)
|
||||
{
|
||||
filename = "fx/weapons/grenade_explode_UW.wav";
|
||||
description = AudioExplosion3d;
|
||||
preload = true;
|
||||
effect = GrenadeExplosionEffect;
|
||||
};
|
||||
|
||||
datablock AudioProfile(GrenadeDryFireSound)
|
||||
{
|
||||
filename = "fx/weapons/grenadelauncher_dryfire.wav";
|
||||
description = AudioClose3d;
|
||||
preload = true;
|
||||
effect = GrenadeDryFireEffect;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Underwater fx
|
||||
//----------------------------------------------------------------------------
|
||||
datablock ParticleData(GrenadeExplosionBubbleParticle)
|
||||
{
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.25;
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 1500;
|
||||
lifetimeVarianceMS = 600;
|
||||
useInvAlpha = false;
|
||||
textureName = "special/bubbles";
|
||||
|
||||
spinRandomMin = -100.0;
|
||||
spinRandomMax = 100.0;
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 0.0";
|
||||
colors[1] = "0.7 0.8 1.0 0.4";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
sizes[0] = 1.0;
|
||||
sizes[1] = 1.0;
|
||||
sizes[2] = 1.0;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
datablock ParticleEmitterData(GrenadeExplosionBubbleEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 5;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 1.0;
|
||||
ejectionOffset = 3.0;
|
||||
velocityVariance = 0.5;
|
||||
thetaMin = 0;
|
||||
thetaMax = 80;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
particles = "GrenadeExplosionBubbleParticle";
|
||||
};
|
||||
|
||||
datablock ParticleData(UnderwaterGrenadeDust)
|
||||
{
|
||||
dragCoefficient = 1.0;
|
||||
gravityCoefficient = -0.01;
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = -1.1;
|
||||
lifetimeMS = 1000;
|
||||
lifetimeVarianceMS = 100;
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -90.0;
|
||||
spinRandomMax = 500.0;
|
||||
textureName = "particleTest";
|
||||
colors[0] = "0.6 0.6 1.0 0.5";
|
||||
colors[1] = "0.6 0.6 1.0 0.5";
|
||||
colors[2] = "0.6 0.6 1.0 0.0";
|
||||
sizes[0] = 3.0;
|
||||
sizes[1] = 3.0;
|
||||
sizes[2] = 3.0;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.7;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(UnderwaterGrenadeDustEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 15;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 15.0;
|
||||
velocityVariance = 0.0;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 70;
|
||||
thetaMax = 70;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
lifetimeMS = 250;
|
||||
particles = "UnderwaterGrenadeDust";
|
||||
};
|
||||
|
||||
|
||||
datablock ParticleData(UnderwaterGrenadeExplosionSmoke)
|
||||
{
|
||||
dragCoeffiecient = 0.4;
|
||||
gravityCoefficient = -0.25; // rises slowly
|
||||
inheritedVelFactor = 0.025;
|
||||
constantAcceleration = -1.1;
|
||||
|
||||
lifetimeMS = 1250;
|
||||
lifetimeVarianceMS = 0;
|
||||
|
||||
textureName = "particleTest";
|
||||
|
||||
useInvAlpha = false;
|
||||
spinRandomMin = -200.0;
|
||||
spinRandomMax = 200.0;
|
||||
|
||||
textureName = "special/Smoke/smoke_001";
|
||||
|
||||
colors[0] = "0.1 0.1 1.0 1.0";
|
||||
colors[1] = "0.4 0.4 1.0 1.0";
|
||||
colors[2] = "0.4 0.4 1.0 0.0";
|
||||
sizes[0] = 2.0;
|
||||
sizes[1] = 6.0;
|
||||
sizes[2] = 2.0;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(UnderwaterGExplosionSmokeEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 15;
|
||||
periodVarianceMS = 0;
|
||||
|
||||
ejectionVelocity = 6.25;
|
||||
velocityVariance = 0.25;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
lifetimeMS = 250;
|
||||
|
||||
particles = "UnderwaterGrenadeExplosionSmoke";
|
||||
};
|
||||
|
||||
|
||||
|
||||
datablock ParticleData(UnderwaterGrenadeSparks)
|
||||
{
|
||||
dragCoefficient = 1;
|
||||
gravityCoefficient = 0.0;
|
||||
inheritedVelFactor = 0.2;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 350;
|
||||
textureName = "special/underwaterSpark";
|
||||
colors[0] = "0.6 0.6 1.0 1.0";
|
||||
colors[1] = "0.6 0.6 1.0 1.0";
|
||||
colors[2] = "0.6 0.6 1.0 0.0";
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.75;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(UnderwaterGrenadeSparksEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 2;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 12;
|
||||
velocityVariance = 6.75;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 0;
|
||||
thetaMax = 60;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
orientParticles = true;
|
||||
lifetimeMS = 100;
|
||||
particles = "UnderwaterGrenadeSparks";
|
||||
};
|
||||
|
||||
datablock ExplosionData(UnderwaterGrenadeExplosion)
|
||||
{
|
||||
soundProfile = UnderwaterGrenadeExplosionSound;
|
||||
|
||||
faceViewer = true;
|
||||
explosionScale = "0.8 0.8 0.8";
|
||||
|
||||
emitter[0] = UnderwaterGrenadeDustEmitter;
|
||||
emitter[1] = UnderwaterGExplosionSmokeEmitter;
|
||||
emitter[2] = UnderwaterGrenadeSparksEmitter;
|
||||
emitter[3] = GrenadeExplosionBubbleEmitter;
|
||||
|
||||
shakeCamera = true;
|
||||
camShakeFreq = "10.0 6.0 9.0";
|
||||
camShakeAmp = "20.0 20.0 20.0";
|
||||
camShakeDuration = 0.5;
|
||||
camShakeRadius = 20.0;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Bubbles
|
||||
//----------------------------------------------------------------------------
|
||||
datablock ParticleData(GrenadeBubbleParticle)
|
||||
{
|
||||
dragCoefficient = 0.0;
|
||||
gravityCoefficient = -0.25;
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 1500;
|
||||
lifetimeVarianceMS = 600;
|
||||
useInvAlpha = false;
|
||||
textureName = "special/bubbles";
|
||||
|
||||
spinRandomMin = -100.0;
|
||||
spinRandomMax = 100.0;
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 0.4";
|
||||
colors[1] = "0.7 0.8 1.0 0.4";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.5;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(GrenadeBubbleEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 5;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 1.0;
|
||||
ejectionOffset = 0.1;
|
||||
velocityVariance = 0.5;
|
||||
thetaMin = 0;
|
||||
thetaMax = 80;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
particles = "GrenadeBubbleParticle";
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Debris
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
datablock ParticleData( GDebrisSmokeParticle )
|
||||
{
|
||||
dragCoeffiecient = 1.0;
|
||||
gravityCoefficient = 0.0;
|
||||
inheritedVelFactor = 0.2;
|
||||
|
||||
lifetimeMS = 1000;
|
||||
lifetimeVarianceMS = 100;
|
||||
|
||||
textureName = "particleTest";
|
||||
|
||||
useInvAlpha = true;
|
||||
|
||||
spinRandomMin = -60.0;
|
||||
spinRandomMax = 60.0;
|
||||
|
||||
colors[0] = "0.4 0.4 0.4 1.0";
|
||||
colors[1] = "0.3 0.3 0.3 0.5";
|
||||
colors[2] = "0.0 0.0 0.0 0.0";
|
||||
sizes[0] = 0.0;
|
||||
sizes[1] = 1.0;
|
||||
sizes[2] = 1.0;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData( GDebrisSmokeEmitter )
|
||||
{
|
||||
ejectionPeriodMS = 7;
|
||||
periodVarianceMS = 1;
|
||||
|
||||
ejectionVelocity = 1.0; // A little oomph at the back end
|
||||
velocityVariance = 0.2;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 40.0;
|
||||
|
||||
particles = "GDebrisSmokeParticle";
|
||||
};
|
||||
|
||||
|
||||
datablock DebrisData( GrenadeDebris )
|
||||
{
|
||||
emitters[0] = GDebrisSmokeEmitter;
|
||||
|
||||
explodeOnMaxBounce = true;
|
||||
|
||||
elasticity = 0.4;
|
||||
friction = 0.2;
|
||||
|
||||
lifetime = 0.3;
|
||||
lifetimeVariance = 0.02;
|
||||
|
||||
numBounces = 1;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Splash
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
datablock ParticleData( GrenadeSplashParticle )
|
||||
{
|
||||
dragCoefficient = 1;
|
||||
gravityCoefficient = 0.0;
|
||||
inheritedVelFactor = 0.2;
|
||||
constantAcceleration = -1.4;
|
||||
lifetimeMS = 300;
|
||||
lifetimeVarianceMS = 0;
|
||||
textureName = "special/droplet";
|
||||
colors[0] = "0.7 0.8 1.0 1.0";
|
||||
colors[1] = "0.7 0.8 1.0 0.5";
|
||||
colors[2] = "0.7 0.8 1.0 0.0";
|
||||
sizes[0] = 0.05;
|
||||
sizes[1] = 0.2;
|
||||
sizes[2] = 0.2;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData( GrenadeSplashEmitter )
|
||||
{
|
||||
ejectionPeriodMS = 4;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 4;
|
||||
velocityVariance = 1.0;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 0;
|
||||
thetaMax = 50;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
orientParticles = true;
|
||||
lifetimeMS = 100;
|
||||
particles = "BlasterSplashParticle";
|
||||
};
|
||||
|
||||
|
||||
datablock SplashData(GrenadeSplash)
|
||||
{
|
||||
numSegments = 15;
|
||||
ejectionFreq = 15;
|
||||
ejectionAngle = 40;
|
||||
ringLifetime = 0.35;
|
||||
lifetimeMS = 300;
|
||||
velocity = 3.0;
|
||||
startRadius = 0.0;
|
||||
acceleration = -3.0;
|
||||
texWrap = 5.0;
|
||||
|
||||
texture = "special/water2";
|
||||
|
||||
emitter[0] = BlasterSplashEmitter;
|
||||
|
||||
colors[0] = "0.7 0.8 1.0 1.0";
|
||||
colors[1] = "0.7 0.8 1.0 1.0";
|
||||
colors[2] = "0.7 0.8 1.0 1.0";
|
||||
colors[3] = "0.7 0.8 1.0 1.0";
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.4;
|
||||
times[2] = 0.8;
|
||||
times[3] = 1.0;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Particle effects
|
||||
//--------------------------------------
|
||||
datablock ParticleData(GrenadeSmokeParticle)
|
||||
{
|
||||
dragCoeffiecient = 0.0;
|
||||
gravityCoefficient = -0.2; // rises slowly
|
||||
inheritedVelFactor = 0.00;
|
||||
|
||||
lifetimeMS = 700; // lasts 2 second
|
||||
lifetimeVarianceMS = 150; // ...more or less
|
||||
|
||||
textureName = "particleTest";
|
||||
|
||||
useInvAlpha = true;
|
||||
spinRandomMin = -30.0;
|
||||
spinRandomMax = 30.0;
|
||||
|
||||
colors[0] = "0.9 0.9 0.9 1.0";
|
||||
colors[1] = "0.6 0.6 0.6 1.0";
|
||||
colors[2] = "0.4 0.4 0.4 0.0";
|
||||
|
||||
sizes[0] = 0.25;
|
||||
sizes[1] = 1.0;
|
||||
sizes[2] = 3.0;
|
||||
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.2;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(GrenadeSmokeEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 15;
|
||||
periodVarianceMS = 5;
|
||||
|
||||
ejectionVelocity = 1.25;
|
||||
velocityVariance = 0.50;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
particles = "GrenadeSmokeParticle";
|
||||
};
|
||||
|
||||
|
||||
datablock ParticleData(GrenadeDust)
|
||||
{
|
||||
dragCoefficient = 1.0;
|
||||
gravityCoefficient = -0.01;
|
||||
inheritedVelFactor = 0.0;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 1000;
|
||||
lifetimeVarianceMS = 100;
|
||||
useInvAlpha = true;
|
||||
spinRandomMin = -90.0;
|
||||
spinRandomMax = 500.0;
|
||||
textureName = "particleTest";
|
||||
colors[0] = "0.3 0.3 0.3 0.5";
|
||||
colors[1] = "0.3 0.3 0.3 0.5";
|
||||
colors[2] = "0.3 0.3 0.3 0.0";
|
||||
sizes[0] = 3.2;
|
||||
sizes[1] = 4.6;
|
||||
sizes[2] = 5.0;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.7;
|
||||
times[2] = 1.0;
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(GrenadeDustEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 5;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 15.0;
|
||||
velocityVariance = 0.0;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 85;
|
||||
thetaMax = 85;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
lifetimeMS = 250;
|
||||
particles = "GrenadeDust";
|
||||
};
|
||||
|
||||
|
||||
datablock ParticleData(GrenadeExplosionSmoke)
|
||||
{
|
||||
dragCoeffiecient = 0.4;
|
||||
gravityCoefficient = -0.5; // rises slowly
|
||||
inheritedVelFactor = 0.025;
|
||||
|
||||
lifetimeMS = 1250;
|
||||
lifetimeVarianceMS = 0;
|
||||
|
||||
textureName = "particleTest";
|
||||
|
||||
useInvAlpha = true;
|
||||
spinRandomMin = -200.0;
|
||||
spinRandomMax = 200.0;
|
||||
|
||||
textureName = "special/Smoke/smoke_001";
|
||||
|
||||
colors[0] = "0.7 0.7 0.7 1.0";
|
||||
colors[1] = "0.2 0.2 0.2 1.0";
|
||||
colors[2] = "0.1 0.1 0.1 0.0";
|
||||
sizes[0] = 2.0;
|
||||
sizes[1] = 6.0;
|
||||
sizes[2] = 2.0;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(GExplosionSmokeEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 5;
|
||||
periodVarianceMS = 0;
|
||||
|
||||
ejectionVelocity = 6.25;
|
||||
velocityVariance = 0.25;
|
||||
|
||||
thetaMin = 0.0;
|
||||
thetaMax = 90.0;
|
||||
|
||||
lifetimeMS = 250;
|
||||
|
||||
particles = "GrenadeExplosionSmoke";
|
||||
};
|
||||
|
||||
|
||||
|
||||
datablock ParticleData(GrenadeSparks)
|
||||
{
|
||||
dragCoefficient = 1;
|
||||
gravityCoefficient = 0.0;
|
||||
inheritedVelFactor = 0.2;
|
||||
constantAcceleration = 0.0;
|
||||
lifetimeMS = 500;
|
||||
lifetimeVarianceMS = 350;
|
||||
textureName = "special/bigspark";
|
||||
colors[0] = "0.56 0.36 0.26 1.0";
|
||||
colors[1] = "0.56 0.36 0.26 1.0";
|
||||
colors[2] = "1.0 0.36 0.26 0.0";
|
||||
sizes[0] = 0.5;
|
||||
sizes[1] = 0.5;
|
||||
sizes[2] = 0.75;
|
||||
times[0] = 0.0;
|
||||
times[1] = 0.5;
|
||||
times[2] = 1.0;
|
||||
|
||||
};
|
||||
|
||||
datablock ParticleEmitterData(GrenadeSparksEmitter)
|
||||
{
|
||||
ejectionPeriodMS = 2;
|
||||
periodVarianceMS = 0;
|
||||
ejectionVelocity = 12;
|
||||
velocityVariance = 6.75;
|
||||
ejectionOffset = 0.0;
|
||||
thetaMin = 0;
|
||||
thetaMax = 60;
|
||||
phiReferenceVel = 0;
|
||||
phiVariance = 360;
|
||||
overrideAdvances = false;
|
||||
orientParticles = true;
|
||||
lifetimeMS = 100;
|
||||
particles = "GrenadeSparks";
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------
|
||||
// Explosion
|
||||
//----------------------------------------------------
|
||||
datablock ExplosionData(GrenadeExplosion)
|
||||
{
|
||||
soundProfile = GrenadeExplosionSound;
|
||||
|
||||
faceViewer = true;
|
||||
explosionScale = "0.8 0.8 0.8";
|
||||
|
||||
debris = GrenadeDebris;
|
||||
debrisThetaMin = 10;
|
||||
debrisThetaMax = 50;
|
||||
debrisNum = 8;
|
||||
debrisVelocity = 26.0;
|
||||
debrisVelocityVariance = 7.0;
|
||||
|
||||
emitter[0] = GrenadeDustEmitter;
|
||||
emitter[1] = GExplosionSmokeEmitter;
|
||||
emitter[2] = GrenadeSparksEmitter;
|
||||
|
||||
shakeCamera = true;
|
||||
camShakeFreq = "10.0 6.0 9.0";
|
||||
camShakeAmp = "20.0 20.0 20.0";
|
||||
camShakeDuration = 0.5;
|
||||
camShakeRadius = 20.0;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Projectile
|
||||
//--------------------------------------
|
||||
datablock GrenadeProjectileData(BasicGrenade)
|
||||
{
|
||||
projectileShapeName = "grenade_projectile.dts";
|
||||
emitterDelay = -1;
|
||||
directDamage = 0.0;
|
||||
hasDamageRadius = true;
|
||||
indirectDamage = 0.34; //was 0.40
|
||||
damageRadius = 15.0;
|
||||
radiusDamageType = $DamageType::Grenade;
|
||||
kickBackStrength = 1500;
|
||||
bubbleEmitTime = 1.0;
|
||||
|
||||
sound = GrenadeProjectileSound;
|
||||
explosion = "GrenadeExplosion";
|
||||
underwaterExplosion = "UnderwaterGrenadeExplosion";
|
||||
velInheritFactor = 0.85; // z0dd - ZOD, 3/30/02. Was 0.5
|
||||
splash = GrenadeSplash;
|
||||
|
||||
baseEmitter = GrenadeSmokeEmitter;
|
||||
bubbleEmitter = GrenadeBubbleEmitter;
|
||||
|
||||
grenadeElasticity = 0.30; // z0dd - ZOD, 9/13/02. Was 0.35
|
||||
grenadeFriction = 0.2;
|
||||
armingDelayMS = 650; // z0dd - ZOD, 9/13/02. Was 1000
|
||||
muzzleVelocity = 75.00; // z0dd - ZOD, 3/30/02. GL projectile is faster. Was 47.00
|
||||
//Chocotaco, drag was added back cuz if the grenade is fired under water the effect wont change from bubbles to smoke.
|
||||
drag = 0.001; // z0dd - ZOD, 3/30/02. No drag.
|
||||
gravityMod = 1.9; // z0dd - ZOD, 5/18/02. Make GL projectile heavier, less floaty
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Ammo
|
||||
//--------------------------------------
|
||||
|
||||
datablock ItemData(GrenadeLauncherAmmo)
|
||||
{
|
||||
className = Ammo;
|
||||
catagory = "Ammo";
|
||||
shapeFile = "ammo_grenade.dts";
|
||||
mass = 1;
|
||||
elasticity = 0.2;
|
||||
friction = 0.6;
|
||||
pickupRadius = 2;
|
||||
pickUpName = "some grenade launcher ammo";
|
||||
|
||||
computeCRC = true;
|
||||
emap = true;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Weapon
|
||||
//--------------------------------------
|
||||
datablock ItemData(GrenadeLauncher)
|
||||
{
|
||||
className = Weapon;
|
||||
catagory = "Spawn Items";
|
||||
shapeFile = "weapon_grenade_launcher.dts";
|
||||
image = GrenadeLauncherImage;
|
||||
mass = 1;
|
||||
elasticity = 0.2;
|
||||
friction = 0.6;
|
||||
pickupRadius = 2;
|
||||
pickUpName = "a grenade launcher";
|
||||
|
||||
computeCRC = true;
|
||||
|
||||
};
|
||||
|
||||
datablock ShapeBaseImageData(GrenadeLauncherImage)
|
||||
{
|
||||
className = WeaponImage;
|
||||
shapeFile = "weapon_grenade_launcher.dts";
|
||||
item = GrenadeLauncher;
|
||||
ammo = GrenadeLauncherAmmo;
|
||||
offset = "0 0 0";
|
||||
emap = true;
|
||||
|
||||
projectile = BasicGrenade;
|
||||
projectileType = GrenadeProjectile;
|
||||
|
||||
stateName[0] = "Activate";
|
||||
stateTransitionOnTimeout[0] = "ActivateReady";
|
||||
stateTimeoutValue[0] = 0.5;
|
||||
stateSequence[0] = "Activate";
|
||||
stateSound[0] = GrenadeSwitchSound;
|
||||
|
||||
stateName[1] = "ActivateReady";
|
||||
stateTransitionOnLoaded[1] = "Ready";
|
||||
stateTransitionOnNoAmmo[1] = "NoAmmo";
|
||||
|
||||
stateName[2] = "Ready";
|
||||
stateTransitionOnNoAmmo[2] = "NoAmmo";
|
||||
stateTransitionOnTriggerDown[2] = "Fire";
|
||||
|
||||
stateName[3] = "Fire";
|
||||
stateTransitionOnTimeout[3] = "Reload";
|
||||
stateTimeoutValue[3] = 0.4;
|
||||
stateFire[3] = true;
|
||||
stateRecoil[3] = LightRecoil;
|
||||
stateAllowImageChange[3] = false;
|
||||
stateSequence[3] = "Fire";
|
||||
stateScript[3] = "onFire";
|
||||
stateSound[3] = GrenadeFireSound;
|
||||
|
||||
stateName[4] = "Reload";
|
||||
stateTransitionOnNoAmmo[4] = "NoAmmo";
|
||||
stateTransitionOnTimeout[4] = "Ready";
|
||||
stateTimeoutValue[4] = 0.5;
|
||||
stateAllowImageChange[4] = false;
|
||||
stateSequence[4] = "Reload";
|
||||
stateSound[4] = GrenadeReloadSound;
|
||||
|
||||
stateName[5] = "NoAmmo";
|
||||
stateTransitionOnAmmo[5] = "Reload";
|
||||
stateSequence[5] = "NoAmmo";
|
||||
stateTransitionOnTriggerDown[5] = "DryFire";
|
||||
|
||||
stateName[6] = "DryFire";
|
||||
stateSound[6] = GrenadeDryFireSound;
|
||||
stateTimeoutValue[6] = 1.5;
|
||||
stateTransitionOnTimeout[6] = "NoAmmo";
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue