Prepare fixtures

This commit is contained in:
dkanus 2026-07-14 20:27:09 +07:00
commit 9c94356263
6021 changed files with 722805 additions and 22 deletions

View file

@ -0,0 +1,681 @@
class ScrnVotingHandlerMut extends Mutator
Config(ScrnVoting);
var globalconfig int VoteCountDown;
var globalconfig float VotePercent, VotePercentCountDown;
const VERSION = 40600;
var localized string strVersion;
var protected bool bVoteInProgress;
var protected int VoteSecondsLeft;
var protected array <PlayerController> VotersYes, VotersNo;
var localized string strVoteInitiated, strVotePassed, strVoteFailed, strVoteFailedInitiator, strVoteFailedPlayer, strVoteTimeout,
strVoteInProgress, strNoVoteInProgress, strAlreadyVoted, strVoteUnknown, strVoteIllegal, strVoteHasNoEffect,
strForcedByAdmin, strVotedYes, strVotedNo, strVoteStatus, strSpectatorsCantVote, strOtherTeamVote;
var localized string strTimeout, strPlayerBlocked;
var string VoteInfo; // user-friendly information about current vore
var protected int VoteIndex;
var protected string VoteValue; // value to be set, if vote passes
var protected ScrnVotingOptions CurrentVotingObject; //objects that controls current vote value
var transient PlayerController VoteInitiator;
var transient TeamInfo VotedTeam;
var PlayerController TeamCaptains[2];
var transient PlayerController VotedPlayer;
var protected transient bool bVotedPlayer; // if true, VotedPlayer is used in the current vote
var protected array<ScrnVotingOptions> VotingOptions;
var array <localized string> HelpInfo;
var private bool bHelpPrepared;
var class<VHReplicationInfo> VHReplicationInfoClass;
var VHReplicationInfo VHRI;
var byte VoteID;
var globalconfig float VoteCoolDown;
var PlayerController FailedVoter;
var float FailedVoterBlockTime; // FailedVoter is unable to start a new vote till this time
// Players who can't start voting. Can be used by voting options
var array<PlayerController> BlockedVoters;
struct SVoteGroup
{
var String GroupName;
var ScrnVotingOptions VO;
};
var array<SVoteGroup> VoteGroups;
static function string GetVersionStr()
{
local String msg, s;
local int v, sub_v;
msg = default.strVersion;
v = VERSION / 100;
sub_v = VERSION % 100;
s = String(int(v%100));
if ( len(s) == 1 )
s = "0" $ s;
if ( sub_v > 0 )
s @= "(BETA "$sub_v$")";
ReplaceText(msg, "%n", s);
s = String(v/100);
ReplaceText(msg, "%m",s);
return msg;
}
function Mutate(string MutateString, PlayerController Sender)
{
if ( MutateString ~= "vote" )
Vote("", Sender);
else if ( left(MutateString, 5) ~= "vote " )
Vote(Right(MutateString, len(MutateString)-5), Sender);
else {
super.Mutate(MutateString, Sender);
if ( MutateString ~= "version" )
Sender.ClientMessage(GetVersionStr());
}
}
static function ScrnVotingHandlerMut GetVotingHandler(GameInfo Game)
{
local Mutator mut;
for ( mut = Game.BaseMutator; mut != none; mut = mut.NextMutator ) {
if ( ScrnVotingHandlerMut(mut) != none )
return ScrnVotingHandlerMut(mut);
}
return none;
}
function ScrnVotingOptions AddVotingOptions(class<ScrnVotingOptions> VO_Class)
{
local int i;
local ScrnVotingOptions VO;
// don't add same class twice
for ( i=0; i < VotingOptions.length; ++i ) {
if ( VotingOptions[i].class == VO_Class )
return VotingOptions[i];
}
VO = spawn(VO_Class, self);
if ( VO != none ) {
VO.VotingHandler = self;
VotingOptions[VotingOptions.length] = VO;
VO.InitGroups();
}
return VO;
}
function RemoveVotingOptions(class<ScrnVotingOptions> VO_Class, optional bool bChildsToo)
{
local int i, j;
for ( i=0; i < VotingOptions.length; ++i ) {
if ( VotingOptions[i].class == VO_Class || (bChildsToo && ClassIsChildOf(VotingOptions[i].class, VO_Class)) ) {
// unregister groups too
for ( j=0; j<VoteGroups.length; ++j) {
if ( VoteGroups[j].VO == VotingOptions[i] )
VoteGroups.remove(j--, 1);
}
VotingOptions.remove(i--, 1);
}
}
}
function ScrnVotingOptions GetGroupOptions(string GroupName)
{
local int i;
for ( i=0; i<VoteGroups.length; ++i ) {
if ( VoteGroups[i].GroupName ~= GroupName )
return VoteGroups[i].VO;
}
return none;
}
function RegisterGroup(string GroupName, ScrnVotingOptions VO)
{
local int i;
if ( InStr(GroupName, " ") != -1 ) {
warn("Voting group can not have spaces: '" $ GroupName $ "'");
return;
}
if ( GetGroupOptions(GroupName) != none )
return; // already registered
i = VoteGroups.length;
VoteGroups.insert(i, 1);
VoteGroups[i].GroupName = GroupName;
VoteGroups[i].VO = VO;
}
static function string Trim(string str)
{
local int l;
l = len(str);
while ( l > 0 && left(str,1) == " " )
str = right(str, --l);
while ( l > 0 && right(str,1) == " " )
str = left(str, --l);
return str;
}
function bool IsVoteInProgress()
{
return bVoteInProgress;
}
function string GetVoteStatus(optional PlayerController Voter, optional bool bVotedYes)
{
local string result;
if ( !bVoteInProgress )
return strNoVoteInProgress;
if ( Voter != none && Voter.PlayerReplicationInfo != none ) {
if ( bVotedYes )
result = strVotedYes;
else
result = strVotedNo;
ReplaceText(result, "%p", Voter.PlayerReplicationInfo.PlayerName);
}
else {
result = strVoteStatus;
}
ReplaceText(result, "%v", VoteInfo);
ReplaceText(result, "%y", String(VotersYes.length));
ReplaceText(result, "%n", String(VotersNo.length));
return result;
}
// returns number of players who are able to vote
function int MaxVoters()
{
local int result;
if ( VotedTeam != none )
result = VotedTeam.Size;
else
result = Level.Game.NumPlayers;
return max(result, 1);
}
function Vote(string VoteString, PlayerController Sender)
{
local int i, idx;
local string k, v, g;
local ScrnVotingOptions VO;
if ( Sender == none || Sender.PlayerReplicationInfo == none )
return; // wtf?
VoteString = caps(Trim(VoteString));
if ( VoteString == "" || VoteString == "HELP" || VoteString ~= "INFO" || VoteString ~= "?") {
SendHelp(Sender);
}
else if ( VoteString == "STATUS" ) {
Sender.ClientMessage(GetVoteStatus());
}
else if ( Sender.PlayerReplicationInfo.bOnlySpectator && !Sender.PlayerReplicationInfo.bAdmin ) {
Sender.ClientMessage(strSpectatorsCantVote);
}
else if ( VoteString == "YES" || VoteString == "TRYYES" ) {
if ( bVoteInProgress ) {
if ( Sender.PlayerReplicationInfo.bAdmin ) {
VotePassed(Sender.PlayerReplicationInfo.PlayerName);
return;
}
else if ( VotedTeam != none ) {
if ( VotedTeam != Sender.PlayerReplicationInfo.Team ) {
if ( VoteString != "TRYYES" )
Sender.ClientMessage(strOtherTeamVote);
return;
}
else if ( VotedTeam.TeamIndex < 2 && TeamCaptains[VotedTeam.TeamIndex] == Sender ) {
VotePassed(Sender.PlayerReplicationInfo.PlayerName);
return;
}
}
for ( i = 0; i < VotersNo.length; i++ ) {
if ( VotersNo[i] == Sender ) {
VotersNo.remove(i, 1);
break;
}
}
for ( i = 0; i < VotersYes.length; i++ ) {
if ( VotersYes[i] == Sender ) {
Sender.ClientMessage(strAlreadyVoted);
return;
}
}
VotersYes[VotersYes.length] = Sender;
BroadcastMessage(GetVoteStatus(Sender, true));
if ( float(VotersYes.length) / MaxVoters() * 100.0 >= VotePercent )
VotePassed();
else {
VHRI.UpdateVoteStatus(self, VHRI.VS_INPROGRESS, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
}
else if ( VoteString != "TRYYES" )
Sender.ClientMessage(strNoVoteInProgress);
}
else if ( VoteString == "NO" || VoteString == "TRYNO" ) {
if ( bVoteInProgress ) {
if ( Sender.PlayerReplicationInfo.bAdmin ) {
VoteInfo @= strForcedByAdmin;
ReplaceText(VoteInfo, "%p", Sender.PlayerReplicationInfo.PlayerName);
VoteFailed();
return;
}
else if ( VotedTeam != none ) {
if ( VotedTeam != Sender.PlayerReplicationInfo.Team ) {
if ( VoteString != "TRYNO" )
Sender.ClientMessage(strOtherTeamVote);
return;
}
else if ( VotedTeam.TeamIndex < 2 && TeamCaptains[VotedTeam.TeamIndex] == Sender ) {
VoteInfo @= strForcedByAdmin;
ReplaceText(VoteInfo, "%p", Sender.PlayerReplicationInfo.PlayerName);
VoteFailed();
return;
}
}
for ( i = 0; i < VotersYes.length; i++ ) {
if ( VotersYes[i] == Sender ) {
VotersYes.remove(i, 1);
break;
}
}
for ( i = 0; i < VotersNo.length; i++ ) {
if ( VotersNo[i] == Sender ) {
Sender.ClientMessage(strAlreadyVoted);
return;
}
}
VotersNo[VotersNo.length] = Sender;
BroadcastMessage(GetVoteStatus(Sender, false));
if ( float(MaxVoters() - VotersNo.length) / MaxVoters() * 100.0 < VotePercent )
VoteFailed(); // vote fails when it can't theoretically pass the vote
else
VHRI.UpdateVoteStatus(self, VHRI.VS_INPROGRESS, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
else if ( VoteString != "TRYNO" )
Sender.ClientMessage(strNoVoteInProgress);
}
else if ( bVoteInProgress )
Sender.ClientMessage(strVoteInProgress);
else if ( !MayStartVoting(Sender))
Sender.ClientMessage(strPlayerBlocked);
else {
VoteInfo = "";
VotedPlayer = none;
VotedTeam = none;
if ( Divide(VoteString, " ", k, v) ) {
k = trim(k);
v = trim(v);
}
else {
k = VoteString;
v = "";
}
// check if first is a group
VO = GetGroupOptions(k);
if ( VO != none ) {
// first word is a group, then second is a key and others - value
g = k;
if ( Divide(v, " ", k, v) ) {
k = trim(k);
v = trim(v);
}
else {
k = v;
v = "";
}
if ( k == "" || k == "HELP" || k ~= "?" )
VO.SendGroupHelp(Sender, g);
else {
idx = VO.GetGroupVoteIndex(Sender, g, k, v, VoteInfo);
switch (idx) {
case VO.VOTE_UNKNOWN:
Sender.ClientMessage(strVoteIllegal);
VO.SendGroupHelp(Sender, g);
break;
case VO.VOTE_ILLEGAL:
Sender.ClientMessage(strVoteIllegal);
break;
case VO.VOTE_NOEFECT:
Sender.ClientMessage(strVoteHasNoEffect);
break;
case VO.VOTE_LOCAL:
return;
default:
CurrentVotingObject = VO;
VoteIndex = idx;
VoteValue = v;
if ( VoteInfo == "" )
VoteInfo = g @ k @ v;
StartVoting(Sender);
}
}
}
else {
// no group found - do global vote check
for ( i = 0; i < VotingOptions.length; ++i ) {
if ( VotingOptions[i] == none || !VotingOptions[i].bAcceptsGlobalVotes )
continue;
VO = VotingOptions[i];
idx = VO.GetVoteIndex(Sender, k, v, VoteInfo);
if ( idx != VO.VOTE_UNKNOWN ) {
switch (idx) {
case VO.VOTE_ILLEGAL:
Sender.ClientMessage(strVoteIllegal);
break;
case VO.VOTE_NOEFECT:
Sender.ClientMessage(strVoteHasNoEffect);
break;
case VO.VOTE_LOCAL:
return;
default:
CurrentVotingObject = VO;
VoteIndex = idx;
VoteValue = v;
if ( VoteInfo == "" )
VoteInfo = k @ v;
StartVoting(Sender);
}
return;
}
}
if ( VO != none && idx == VO.VOTE_UNKNOWN ) {
Sender.ClientMessage(strVoteUnknown);
}
}
}
}
function bool MayStartVoting(PlayerController Sender)
{
local int i;
if ( Sender.PlayerReplicationInfo == none )
return false;
// admins can always vote
if ( Sender.PlayerReplicationInfo.bAdmin )
return true;
// spectators can't vote
if ( Sender.PlayerReplicationInfo.bOnlySpectator )
return false;
if ( Level.Game.NumPlayers == 1 )
return true;
if ( Sender == FailedVoter && Level.TimeSeconds < FailedVoterBlockTime )
return false;
for ( i=0; i<BlockedVoters.length; ++i ) {
if ( BlockedVoters[i] == Sender)
return false;
}
return true;
}
function BroadcastMessage(string msg)
{
local Controller P;
local PlayerController Player;
for ( P = Level.ControllerList; P != none; P = P.nextController ) {
Player = PlayerController(P);
if ( Player != none ) {
Player.ClientMessage(msg);
}
}
}
function StartVoting(PlayerController Initiator)
{
local string msg;
if ( Initiator == none || Initiator.PlayerReplicationInfo == none )
return;
VoteInitiator = Initiator;
bVotedPlayer = VotedPlayer != none;
VotersYes.Length = 1;
VotersYes[0] = Initiator;
VotersNo.Length = 0;
bVoteInProgress = true;
VoteID++;
if ( Level.NetMode == NM_Standalone || Initiator.PlayerReplicationInfo.bAdmin ) {
VotePassed(Initiator.PlayerReplicationInfo.PlayerName);
}
else if ( MaxVoters() == 1 && !Initiator.PlayerReplicationInfo.bOnlySpectator ) {
VotePassed();
}
else if ( VotedTeam != none && VotedTeam.TeamIndex < 2 && TeamCaptains[VotedTeam.TeamIndex] == Initiator ) {
VotePassed(Initiator.PlayerReplicationInfo.PlayerName);
}
else {
msg = strVoteInitiated;
ReplaceText(msg, "%p", Initiator.PlayerReplicationInfo.PlayerName);
ReplaceText(msg, "%v", VoteInfo);
BroadcastMessage(chr(27)$chr(200)$chr(200)$chr(1)$msg);
VHRI.UpdateVoteStatus(self, VHRI.VS_INPROGRESS, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
VoteSecondsLeft = VoteCountDown;
SetTimer(1, true);
}
}
function Timer()
{
if ( VoteInitiator == none ) {
EndVoting();
BroadcastMessage(chr(27)$chr(200)$chr(1)$chr(1)$strVoteFailedInitiator);
VHRI.UpdateVoteStatus(self, VHRI.VS_FAILED, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
else if ( bVotedPlayer && (VotedPlayer == none || VotedPlayer.PlayerReplicationInfo == none) ) {
EndVoting();
BroadcastMessage(chr(27)$chr(200)$chr(1)$chr(1)$strVoteFailedPlayer);
VHRI.UpdateVoteStatus(self, VHRI.VS_FAILED, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
else if ( --VoteSecondsLeft <= 0 ) {
if ( float(VotersYes.length) / MaxVoters() * 100.0 >= VotePercentCountDown ) {
VotePassed(strTimeout);
}
else {
EndVoting();
BroadcastMessage(strVoteTimeout);
VHRI.UpdateVoteStatus(self, VHRI.VS_FAILED, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
}
}
function EndVoting()
{
bVoteInProgress = false;
SetTimer(0, false);
}
function VotePassed(optional String ForcedByPlayerName)
{
local string msg;
if ( !bVoteInProgress )
return;
EndVoting();
if ( VoteInitiator == none ) {
BroadcastMessage(chr(27)$chr(200)$chr(1)$chr(1)$strVoteFailedInitiator);
VHRI.UpdateVoteStatus(self, VHRI.VS_FAILED, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
return;
}
CurrentVotingObject.ApplyVoteValue(VoteIndex, VoteValue);
msg = strVotePassed;
ReplaceText(msg, "%v", VoteInfo);
if ( ForcedByPlayerName != "" ) {
msg @= strForcedByAdmin;
ReplaceText(msg, "%p", ForcedByPlayerName);
}
BroadcastMessage(chr(27)$chr(1)$chr(200)$chr(1)$msg);
VHRI.UpdateVoteStatus(self, VHRI.VS_PASSED, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
function VoteFailed()
{
if ( VoteCoolDown > 0 ) {
FailedVoter = VoteInitiator;
FailedVoterBlockTime = Level.TimeSeconds + VoteCoolDown;
}
EndVoting();
BroadcastMessage(chr(27)$chr(200)$chr(1)$chr(1)$strVoteFailed);
VHRI.UpdateVoteStatus(self, VHRI.VS_FAILED, VoteInfo, VotersYes.length, VotersNo.length, VoteID);
}
static function string ParseHelpLine(string s)
{
ReplaceText(s, "%r", chr(27)$chr(200)$chr(1)$chr(1));
ReplaceText(s, "%g", chr(27)$chr(1)$chr(200)$chr(1));
ReplaceText(s, "%b", chr(27)$chr(1)$chr(100)$chr(200));
ReplaceText(s, "%w", chr(27)$chr(200)$chr(200)$chr(200));
ReplaceText(s, "%y", chr(27)$chr(200)$chr(200)$chr(1));
ReplaceText(s, "%p", chr(27)$chr(200)$chr(1)$chr(200));
ReplaceText(s, "%k", chr(27)$chr(64)$chr(64)$chr(64));
return s;
}
function PrepareHelp()
{
local int i, j, l;
local ScrnVotingOptions VO;
bHelpPrepared = true;
l = HelpInfo.length;
// add help infos from voting options
for ( j=0; j < VotingOptions.length; ++j ) {
VO = VotingOptions[j];
if ( VO != none) {
HelpInfo.insert(l, VO.HelpInfo.length);
for ( i = 0; i < VO.HelpInfo.length; ++i) {
HelpInfo[l++] = VO.HelpInfo[i];
}
}
}
for ( i = 0; i < l; ++i) {
HelpInfo[i] = ParseHelpLine(HelpInfo[i]);
}
}
function SendHelp(PlayerController Sender)
{
local int i;
if ( !bHelpPrepared )
PrepareHelp();
for ( i = 0; i < HelpInfo.length; ++i)
Sender.ClientMessage(HelpInfo[i]);
}
simulated function PostBeginPlay()
{
if ( Level.NetMode == NM_Client ) {
log("Voting Handler should be used only on the server side", class.outer.name);
Destroy();
return;
}
VHRI = Spawn(VHReplicationInfoClass, self);
VHRI.mutRef = Self;
}
function ServerTraveling(string URL, bool bItems)
{
if (NextMutator != None)
NextMutator.ServerTraveling(URL,bItems);
if ( VHRI != none ) {
VHRI.Destroy();
VHRI = none;
}
}
//returns true, if specifield vote is in progress
//pass -1 to VIndex to check all votes from specified ScrnVotingOptions object
function bool IsMyVotingRunning(ScrnVotingOptions VO, int VIndex)
{
return bVoteInProgress && CurrentVotingObject == VO && (VoteIndex == VIndex || VIndex == -1);
}
defaultproperties
{
VoteCountDown=70
VotePercent=51.000000
VotePercentCountDown=51.000000
strVersion="ScrN Voting Handler v%m.%n"
strVoteInitiated="%p initiated a vote: %v."
strVotePassed="Vote passed: %v"
strVoteFailed="Vote failed"
strVoteFailedInitiator="Vote failed due to initiator's disconnect"
strVoteFailedPlayer="Vote failed due to player's disconnect"
strVoteTimeout="Vote failed due to timeout"
strVoteInProgress="Another vote in progress"
strNoVoteInProgress="No vote in progress"
strAlreadyVoted="You've already voted"
strVoteUnknown="Unknown vote"
strVoteIllegal="Illegal vote arguments"
strVoteHasNoEffect="Vote has no effect"
strForcedByAdmin="(forced by %p)"
strVotedYes="%p voted YES on: %v (+%y -%n)"
strVotedNo="%p voted NO on: %v (+%y -%n)"
strVoteStatus="Current vote: %v (+%y -%n)"
strSpectatorsCantVote="Spectators can not vote!"
strOtherTeamVote="Can't participate in other team's voting!"
strTimeout="TIMEOUT"
strPlayerBlocked="You are disallowed to start a voting"
HelpInfo(0)="%bVoting Options:"
HelpInfo(1)="%gHELP %w Show this information"
HelpInfo(2)="%gYES%w|%gNO %w Accept|Decline current vote"
HelpInfo(3)="%gSTATUS %w Show status of the current vote"
VHReplicationInfoClass=Class'ScrnVotingHandlerV4.VHReplicationInfo'
VoteCoolDown=10.000000
bAddToServerPackages=True
GroupName="SCRN-VOTE"
FriendlyName="ScrN Voting Handler"
Description="Allows voting via MUTATE VOTE console command"
}

View file

@ -0,0 +1,177 @@
class ScrnVotingOptions extends Info
abstract;
var ScrnVotingHandlerMut VotingHandler;
var string DefaultGroup; // in cases of MUTATE VOTE GROUP KEY VALUE
var bool bAcceptsGlobalVotes; // should voting handler call GetVoteIndex(), if vote has no group?
var array <localized string> HelpInfo;
var array <localized string> GroupInfo;
var protected bool bHelpPrepared;
var array <string> TrueStrings, FalseStrings;
var localized string strRestartRequired;
var localized string strOptionDisabled;
var localized string strNotAvaliableATM;
var localized string strPlayerNotFound;
const VOTE_UNKNOWN = -1;
const VOTE_ILLEGAL = -2;
const VOTE_NOEFECT = -3;
const VOTE_LOCAL = -10;
function Destroyed()
{
if ( VotingHandler != none )
VotingHandler.RemoveVotingOptions(self.class);
super.Destroyed();
}
/*
This function is called by VotingHandler immediatelly after the spawn.
It should register the voting groups for GetGroupVoteIndex() callings.
*/
function InitGroups()
{
if ( DefaultGroup == "" )
bAcceptsGlobalVotes = true;
else {
VotingHandler.RegisterGroup(DefaultGroup, self);
bAcceptsGlobalVotes = false;
}
}
/*
Function must return VOTE_UNKNOWN if this class doesn't recognizes the Key
If Key is recognized, but value is incorrect, return VOTE_ILLEGAL
If value is already set, or can not vote at the current moment, return VOTE_NOEFECT.
If Key is correct, but no vote should be done (e.g. displaying additional help on command)
return VOTE_LOCAL
Keys are case-insensitive and are already passed in upper case.
*/
function int GetVoteIndex(PlayerController Sender, string Key, out string Value, out string VoteInfo)
{
return VOTE_UNKNOWN;
}
function int GetGroupVoteIndex(PlayerController Sender, string Group, string Key, out string Value, out string VoteInfo)
{
return VOTE_UNKNOWN;
}
function ApplyVoteValue(int VoteIndex, string VoteValue);
// returns 1 (true), 0 (false) or -1 (error)
function int TryStrToBool(string str)
{
local int i;
for ( i = 0; i < TrueStrings.Length; ++i ) {
if ( str ~= TrueStrings[i] ) {
return 1;
}
}
for ( i = 0; i < FalseStrings.Length; ++i ) {
if ( str ~= FalseStrings[i] ) {
return 0;
}
}
return -1;
}
static function int TryStrToBoolStatic(string str)
{
local int i;
for ( i = 0; i < default.TrueStrings.Length; ++i ) {
if ( str ~= default.TrueStrings[i] ) {
return 1;
}
}
for ( i = 0; i < default.FalseStrings.Length; ++i ) {
if ( str ~= default.FalseStrings[i] ) {
return 0;
}
}
return -1;
}
function SendPlayerList(PlayerController Sender)
{
local array<PlayerReplicationInfo> AllPRI;
local PlayerController PC;
local int i;
Level.Game.GameReplicationInfo.GetPRIArray(AllPRI);
for (i = 0; i<AllPRI.Length; i++) {
PC = PlayerController(AllPRI[i].Owner);
if( PC != none && AllPRI[i].PlayerName != "WebAdmin")
Sender.ClientMessage(Right(" "$AllPRI[i].PlayerID, 3)$")"
//@ PC.GetPlayerIDHash()
@ AllPRI[i].PlayerName);
}
}
function PlayerController FindPlayer(string NameOrID)
{
local Controller C;
local PlayerController PC;
if ( NameOrID == "" || NameOrID == "0" || NameOrID ~= "WebAdmin" )
return none;
for ( C = Level.ControllerList; C != None; C = C.NextController ) {
PC = PlayerController(C);
if ( PC != None && C.PlayerReplicationInfo != None ) {
if ( (C.PlayerReplicationInfo.PlayerID > 0 && String(C.PlayerReplicationInfo.PlayerID) == NameOrID)
|| C.PlayerReplicationInfo.PlayerName ~= NameOrID )
{
return PC;
}
}
}
return none;
}
function SendGroupHelp(PlayerController Sender, string Group)
{
local int i;
if ( !bHelpPrepared ) {
bHelpPrepared = true;
for ( i=0; i<GroupInfo.length; ++i ) {
GroupInfo[i] = VotingHandler.ParseHelpLine(GroupInfo[i]);
}
}
for ( i=0; i<GroupInfo.length; ++i )
Sender.ClientMessage(GroupInfo[i]);
}
defaultproperties
{
TrueStrings(0)="ON"
TrueStrings(1)="TRUE"
TrueStrings(2)="1"
TrueStrings(3)="YES"
TrueStrings(4)="ENABLE"
FalseStrings(0)="OFF"
FalseStrings(1)="FALSE"
FalseStrings(2)="0"
FalseStrings(3)="NO"
FalseStrings(4)="DISABLE"
strRestartRequired="Map restart required to apply changes"
strOptionDisabled="Voting option is disabled on the server"
strNotAvaliableATM="Voting option is not avaliable at this moment"
strPlayerNotFound="Player with a given ID or name does not exist"
}

View file

@ -0,0 +1,296 @@
// Custom Interaction for displaying current vote status
class VHInteraction extends Interaction
config(user);
var transient VHReplicationInfo VHRI;
var float FadeTime;
var config float PosY; // vertical position of vote status message (it will be centered horizontally)
var localized String strVoteInProgress, strVotePassed, strVoteFailed;
var localized String strVotedYes, strVotedNo;
var localized String strKeyToVoteYes, strKeyToVoteNo, strNoKeySetYes, strNoKeySetNo;
var String Status, VoteName;
var String strKeyBindYes, strKeyBindNo;
var bool bKeyBindYesFound, bKeyBindNoFound;
var color colStatus, colName, colPassed, colFailed;
var byte Alpha;
var transient bool bVotePassed;
var transient int YesVotes, NoVotes;
function UpdateVotes(int y, int n)
{
YesVotes = y;
NoVotes = n;
}
function VoteStarted(String DisplayString)
{
if ( IsInState('InProgress') )
GotoState(''); // wtf?
VoteName = DisplayString;
YesVotes = 1; //initiator
NoVotes = 0;
GotoState('InProgress');
}
function VoteEnded(bool bPassed)
{
bVotePassed = bPassed;
GotoState('Closing');
}
// returns key name, that is bound to the given alias
// returns an empty string, if not key bound
function string GetBoundKey(string Alias)
{
local GUIController GC;
local array<string> BindKeyNames;
local array<string> LocalizedBindKeyNames;
GC = GUIController(ViewportOwner.GUIController);
if ( GC == none )
return "";
GC.GetAssignedKeys(Alias, BindKeyNames, LocalizedBindKeyNames);
if ( BindKeyNames.length == 0 )
return "";
if ( LocalizedBindKeyNames[0] != "" )
return LocalizedBindKeyNames[0];
return BindKeyNames[0];
}
// bind command to a key, if it is unassigned
function bool BindIfUnassigned(string BindKeyName, string BindKeyValue)
{
local string cmd;
cmd = ViewportOwner.Actor.ConsoleCommand("KEYBINDING" @ BindKeyName);
if ( cmd ~= BindKeyValue )
return true;
else if ( cmd == "" ) {
ViewportOwner.Actor.ConsoleCommand("set Input" @ BindKeyName @ BindKeyValue);
return true;
}
else
return false;
}
state Closing
{
function BeginState()
{
if ( bVotePassed ) {
Status = strVotePassed;
colStatus = colPassed;
colName = colPassed;
}
else {
Status = strVoteFailed;
colStatus = colFailed;
colName = colFailed;
}
bRequiresTick = true;
FadeTime = default.FadeTime;
bVisible=true;
}
function EndState()
{
bRequiresTick = false;
}
function VoteEnded(bool bPassed)
{
bVotePassed = bPassed;
BeginState();
}
function Tick(float DeltaTime)
{
FadeTime -= DeltaTime;
if ( FadeTime <= 0 ) {
bVisible = false;
GotoState('');
}
else {
Alpha = FadeTime / default.FadeTime * default.Alpha;
}
}
}
state InProgress
{
function BeginState()
{
local string s;
Status = strVoteInProgress;
colStatus = default.colStatus;
colName = default.colName;
if ( !bKeyBindYesFound ) {
BindIfUnassigned("F3", "MUTATE VOTE YES")
&& BindIfUnassigned("Y", "MUTATE VOTE YES")
&& BindIfUnassigned("NumPad1", "MUTATE VOTE YES");
strKeyBindYes = strKeyToVoteYes;
if ( InStr(strKeyBindYes, "%k") != -1 ) {
s = GetBoundKey("MUTATE VOTE YES");
if ( s != "" ) {
ReplaceText(strKeyBindYes, "%k", s);
bKeyBindYesFound = true;
}
else strKeyBindYes = strNoKeySetYes;
}
else bKeyBindYesFound = true;
}
if ( !bKeyBindNoFound ) {
BindIfUnassigned("F2", "MUTATE VOTE NO")
&& BindIfUnassigned("N", "MUTATE VOTE NO")
&& BindIfUnassigned("NumPad0", "MUTATE VOTE NO");
strKeyBindNo = strKeyToVoteNo;
if ( InStr(strKeyBindNo, "%k") != -1 ) {
s = GetBoundKey("MUTATE VOTE NO");
if ( s != "" ) {
ReplaceText(strKeyBindNo, "%k", s);
bKeyBindNoFound = true;
}
else strKeyBindNo = strNoKeySetNo;
}
else bKeyBindNoFound = true;
}
strVotedYes = default.strVotedYes $ YesVotes $ strKeyBindYes;
strVotedNo = default.strVotedNo $ NoVotes $ strKeyBindNo;
Alpha=255;
bVisible=true;
}
function UpdateVotes(int y, int n)
{
if ( YesVotes != y ) {
YesVotes = y;
strVotedYes = default.strVotedYes $ y $ strKeyBindYes;
}
if ( NoVotes != n ) {
NoVotes = n;
strVotedNo = default.strVotedNo $ n $ strKeyBindNo;
}
}
function DrawAdditionalInfo(Canvas canvas, float y)
{
local float TextWidth, TextHeight;
local float x;
canvas.Font = class'ROHUD'.Static.LoadSmallFontStatic(6);
// voted yes
canvas.DrawColor = colPassed;
canvas.DrawColor.A = Alpha;
canvas.StrLen(strVotedYes, TextWidth, TextHeight);
x = (canvas.ClipX - TextWidth) * 0.5;
canvas.SetPos(x, y);
canvas.DrawTextClipped(strVotedYes);
//voted no
y += TextHeight;
canvas.DrawColor = colFailed;
canvas.DrawColor.A = Alpha;
canvas.StrLen(strVotedNo, TextWidth, TextHeight);
x = (canvas.ClipX - TextWidth) * 0.5;
canvas.SetPos(x, y);
canvas.DrawTextClipped(strVotedNo);
}
}
function PostRender(Canvas canvas)
{
local float TextWidth, TextHeight, vMargin;
local float x, y;
// vote status
canvas.DrawColor = colStatus;
canvas.DrawColor.A = Alpha;
canvas.Font = class'ROHUD'.Static.LoadSmallFontStatic(5);
canvas.StrLen(StripColor(Status), TextWidth, TextHeight);
y = canvas.ClipY * PosY;
x = (canvas.ClipX - TextWidth) * 0.5;
canvas.SetPos(x, y);
canvas.DrawTextClipped(Status);
//vMargin = TextHeight * 0.25;
vMargin = 0;
//vote name
y += TextHeight + vMargin;
canvas.DrawColor = colName;
canvas.DrawColor.A = Alpha;
canvas.Font = class'ROHUD'.Static.LoadSmallFontStatic(1);
canvas.StrLen(StripColor(VoteName), TextWidth, TextHeight);
x = (canvas.ClipX - TextWidth) * 0.5;
canvas.SetPos(x, y);
canvas.DrawTextClipped(VoteName);
//additional info
y += TextHeight + vMargin;
DrawAdditionalInfo(canvas, y);
}
event NotifyLevelChange()
{
Master.RemoveInteraction(self);
if ( VHRI != none ) {
VHRI.myInteraction = none;
VHRI.Destroy();
VHRI = none;
}
}
function DrawAdditionalInfo(Canvas canvas, float y) {}
static final function string StripColor(string s)
{
local int p;
p = InStr(s,chr(27));
while ( p>=0 )
{
s = left(s,p)$mid(S,p+4);
p = InStr(s,Chr(27));
}
return s;
}
defaultproperties
{
FadeTime=5.000000
PosY=0.100000
strVoteInProgress="VOTE IN PROGRESS"
strVotePassed="VOTE PASSED"
strVoteFailed="VOTE FAILED"
strVotedYes="YES = "
strVotedNo="NO = "
strKeyToVoteYes=" (press %k to vote)"
strKeyToVoteNo=" (press %k to vote)"
strNoKeySetYes=" (type MUTATE VOTE YES in console to vote)"
strNoKeySetNo=" (type MUTATE VOTE NO in console to vote)"
colStatus=(B=127,G=127,R=127,A=255)
colName=(B=27,G=200,R=200,A=255)
colPassed=(G=200,A=255)
colFailed=(R=200,A=255)
Alpha=255
bActive=False
}

View file

@ -0,0 +1,9 @@
class VHKeyBinding extends GUIUserKeyBinding;
defaultproperties
{
KeyData(0)=(KeyLabel="Voting Controls",bIsSection=True)
KeyData(1)=(Alias="MUTATE VOTE YES",KeyLabel="Vote YES")
KeyData(2)=(Alias="MUTATE VOTE NO ",KeyLabel="Vote NO")
KeyData(3)=(Alias="MUTATE VOTE STATUS",KeyLabel="Show Current Vote Status")
}

View file

@ -0,0 +1,129 @@
class VHReplicationInfo extends ReplicationInfo;
var transient ScrnVotingHandlerMut mutRef;
var class<VHInteraction> InteractionClass;
var transient VHInteraction myInteraction;
var String VoteName;
var int YesVotes, NoVotes;
var int VoteStatus, OldVoteStatus;
var byte VoteID; // ID ensures that data will be replicated to clients in cases when 2 same rows are passed in a row
const VS_INACTIVE = 0;
const VS_INPROGRESS = 1;
const VS_PASSED = 2;
const VS_FAILED = 3;
replication {
reliable if ( Role == ROLE_Authority )
VoteID, VoteStatus, YesVotes, NoVotes, VoteName;
}
simulated function PostNetReceive()
{
if ( Level.NetMode != NM_DedicatedServer && VoteStatus != VS_INACTIVE ) {
if ( myInteraction == none )
SpawnInteraction();
if ( myInteraction == none ) {
log("Unable to spawn Voting Interaction", class.outer.name);
return;
}
myInteraction.VoteName = VoteName; //just to be sure
if ( VoteStatus == VS_INPROGRESS ) {
if ( OldVoteStatus != VS_INPROGRESS) {
myInteraction.VoteStarted(VoteName);
}
myInteraction.UpdateVotes(YesVotes, NoVotes);
}
else {
myInteraction.VoteEnded(VoteStatus == VS_PASSED);
}
OldVoteStatus = VoteStatus;
}
}
simulated function PreBeginPlay()
{
local VHInteraction RemoveMe;
super.PreBeginPlay();
// remove interaction left the from previous map
foreach AllObjects(class'VHInteraction', RemoveMe) {
if ( RemoveMe.VHRI == self ) {
// wtf? shouldn't happen
log(RemoveMe $ " seems to be myInteraction", class.outer.name);
myInteraction = RemoveMe;
}
else {
log(RemoveMe $ " left from the previous game", class.outer.name);
if ( RemoveMe.VHRI != none ) {
RemoveMe.VHRI.myInteraction = none;
RemoveMe.VHRI = none;
}
if ( RemoveMe.Master != none ) {
RemoveMe.Master.RemoveInteraction(RemoveMe);
}
}
}
}
function UpdateVoteStatus(Actor Updater, int Status, String VoteName, int YesVotes, int NoVotes, byte VoteID)
{
self.VoteStatus = Status;
self.VoteName = VoteName;
self.YesVotes = YesVotes;
self.NoVotes = NoVotes;
self.VoteID = VoteID;
NetUpdateTime = Level.TimeSeconds - 1;
if ( Level.GetLocalPlayerController() != none )
PostNetReceive(); // solo mode or listen servers
if ( VoteStatus == VS_PASSED || VoteStatus == VS_FAILED ) {
SetTimer(1, false); // bug fix when late joiners received status of already ended vote
}
}
function Timer()
{
VoteStatus = VS_INACTIVE;
}
simulated function SpawnInteraction()
{
local PlayerController PC;
if ( myInteraction != none )
return;
PC = Level.GetLocalPlayerController();
if (PC != None ) {
myInteraction = VHInteraction(PC.Player.InteractionMaster.AddInteraction(String(InteractionClass),PC.Player));
if ( myInteraction != none ) {
myInteraction.VHRI = self;
}
else {
warn("Cannot add interaction " $ String(InteractionClass));
}
}
}
simulated function Destroyed()
{
if ( myInteraction != none ) {
myInteraction.Master.RemoveInteraction(myInteraction);
myInteraction.VHRI = none;
myInteraction = none;
}
super.Destroyed();
}
defaultproperties
{
InteractionClass=Class'ScrnVotingHandlerV4.VHInteraction'
bNetNotify=True
}

View file

@ -0,0 +1,11 @@
<html>
<head><title>Index of /kf_sources/ScrnVotingHandlerV4/Classes/</title></head>
<body>
<h1>Index of /kf_sources/ScrnVotingHandlerV4/Classes/</h1><hr><pre><a href="../">../</a>
<a href="ScrnVotingHandlerMut.uc">ScrnVotingHandlerMut.uc</a> 01-Jul-2020 18:12 22142
<a href="ScrnVotingOptions.uc">ScrnVotingOptions.uc</a> 01-Jul-2020 18:12 4984
<a href="VHInteraction.uc">VHInteraction.uc</a> 01-Jul-2020 18:12 8028
<a href="VHKeyBinding.uc">VHKeyBinding.uc</a> 01-Jul-2020 18:12 343
<a href="VHReplicationInfo.uc">VHReplicationInfo.uc</a> 01-Jul-2020 18:12 3724
</pre><hr></body>
</html>