Hi friends,
It has come to my attention recently that manta drivers aren't scoring points for assists and I wanted to share my findings. I contacted Piglet and Nardaq about the issue and apparently the point system is disabled while admins review the point structure. I understand the need to review this to prevent lower skilled players scoring higher as this could effect the stat system/balancer and I wanted to create a discussion around the subject so others can give their opinions.
Questions I have:
- Is it possible to edit the score system for manta runs separately to individual flag runs?
- Will reducing wingman cap points also reduce points for other flag runners?
- What are the proposed reductions in points for both driver and wingman?
I look forward to your responses, thanks! :cheers:
Hi,
As per Discord chat: My take on it is that the most points you could get for an assist was 15 and that it was important that they were given to ensure that the taxi driver was ranked appropriately highly. A good driver is more useful to a team than the dummy on the wing and should get full credit and a high pph ranking for the balancer to use at round start.
Here's the code and the configuration. I would welcome any input as to issues seen in the code, and code changes that would fix it.
Configuration:
[MiA_FlagrunAssist.mutFlagrunAssist]
ScoreMethod=1
MaxScore=15
MaxAdren=25
//============================================================================
// $Id: mutFlagrunAssist.uc by Jrubzjeknf
//============================================================================
class mutFlagrunAssist extends Mutator config(MiA_FlagRunAssist);
var CTFFlag RedFlag, BlueFlag;
var Mia_FlagrunInfo RedInfo, BlueInfo;
var config int ScoreMethod, MaxScore, MaxAdren;
//============================================================================
// PostBeginPlay
//
// Because the flags don't exist yet when this function is called, a timer is
// started to find them on level startup instead.
//============================================================================
function PostBeginPlay()
{
Super.PostBeginPlay();
SetTimer(1, true);
}
//============================================================================
// Timer
//
// Finds flags, saves their reference and spawns a Mia_FlagrunInfo for them.
//============================================================================
function Timer()
{
local CTFFlag F;
if(Level.Game.GameReplicationInfo.bMatchHasBegun) //Match started!
{
foreach AllActors(class'CTFFlag', F) //Find flags.
{
if ( F.TeamNum == 1 )
BlueFlag = F;
else
RedFlag = F;
}
if(RedFlag != None && BlueFlag != None) //Spawn Infos and set variables in those.
{
RedInfo = Spawn(class'Mia_FlagrunInfo', RedFlag);
BlueInfo = Spawn(class'Mia_FlagrunInfo', BlueFlag);
RedInfo.EnemyTeamInfo = BlueFlag.Team;
BlueInfo.EnemyTeamInfo = RedFlag.Team;
RedInfo.EnemyTeamScore = BlueFlag.Team.Score;
BlueInfo.EnemyTeamScore = RedFlag.Team.Score;
RedInfo.ScoreMethod = ScoreMethod;
RedInfo.MaxScore = MaxScore;
RedInfo.MaxAdren = MaxAdren;
BlueInfo.ScoreMethod = ScoreMethod;
BlueInfo.MaxScore = MaxScore;
BlueInfo.MaxAdren = MaxAdren;
SetTimer(0, false);
}
}
}
static function FillPlayInfo(PlayInfo PlayInfo)
{
local byte Weight; // weight must be a byte (max value 127?)
Weight=1;
Super.FillPlayInfo(PlayInfo);
PlayInfo.AddSetting(Default.FriendlyName, "ScoreMethod", "Select one", 0, Weight++, "Select", "0;Points every second carrying;1;Points in proportion to time carrying");
PlayInfo.AddSetting(Default.FriendlyName, "MaxScore", "Max Score for helping", 0, Weight++, "Text", "2;0:99");
PlayInfo.AddSetting(Default.FriendlyName, "MaxAdren", "Max Adren for helping", 0, Weight++, "Text", "2;0:99");
}
static function string GetDescriptionText(string PropName)
{
switch (PropName)
{
case "ScoreMethod": return "Method of points calculation";
case "MaxScore": return "Max score possible";
case "MaxAdren": return "Max Adrenaline possible";
}
return Super.GetDescriptionText(PropName);
}
//============================================================================
// Default Properties
//============================================================================
defaultproperties
{
GroupName="FlagrunAssist"
FriendlyName="Flagrun Assist"
Description="Flag run driver points."
ScoreMethod=1
MaxScore=15
MaxAdren=25
}
//============================================================================
// $Id: Mia_FlagrunInfo.uc by Jrubzjeknf
//============================================================================
class Mia_FlagrunInfo extends ReplicationInfo;
//============================================================================
// Variables
//============================================================================
var TeamInfo EnemyTeamInfo;
var float EnemyTeamScore;
var float TimeCarryingFlag;
var float FlagTakenTime;
var int ScoreMethod;
var int MaxScore;
var int MaxAdren;
struct VehicleDriverPoints
{
var Controller Driver;
var float TimeDriven;
};
var array<VehicleDriverPoints> VehicleDriverPointsArray;
//============================================================================
// PostBeginPlay
//
// Initiates flag monitoring.
//============================================================================
function PostBeginPlay()
{
Super.PostBeginPlay();
SetTimer(1, true);
}
//============================================================================
// Timer
//
// Checks if the flag carrier is sitting on a Vehicle. Every second he's sitting
// on one, the Vehicle driver gets an assist second. This will be used for
// giving the Vehicle driver points and adrenaline for the Vehicle run.
//============================================================================
function Timer()
{
local pawn Driver;
local Controller C;
if(Owner != None)
{
if(FlagTakenTime != CTFFlag(Owner).TakenTime) //the flag has just been taken, check it the flag has been captured between seconds.
{
CheckCapture();
FlagTakenTime = CTFFlag(Owner).TakenTime;
}
if(!Owner.IsInState('Home')) //The flag is being carried or has been dropped.
{
TimeCarryingFlag += 1;
if(CTFFlag(Owner).Holder != None &&
CTFFlag(Owner).Holder.Base != None &&
Vehicle(CTFFlag(Owner).Holder.Base) != None &&
Vehicle(CTFFlag(Owner).Holder.Base).Driver != None) //The flag carrier is sitting on an occupied Vehicle.
{
Driver = Vehicle(CTFFlag(Owner).Holder.Base).Driver;
if(Driver.GetTeamNum() == CTFFlag(Owner).Holder.GetTeamNum() && Driver != CTFFlag(Owner).Holder){ //The Vehicle driver is friendly (and not self!).
if (Driver.DrivenVehicle != None && Driver.DrivenVehicle.Controller != None){
C = Driver.DrivenVehicle.Controller;
}
else{
C = Driver.Controller;
}
UpdateTimeDrivenFor(C); //Give the driver seconds.
}
}
}
else if(TimeCarryingFlag != 0) //The flag is home, but has been carried. Check if the flag has been captured.
CheckCapture();
}
}
//============================================================================
// CheckCapture
//
// Check is the flag has been captured.
//============================================================================
function CheckCapture()
{
local int i;
local float RelativeTimeDriven;
local float Points;
local float Adren;
if(EnemyTeamScore != EnemyTeamInfo.Score)
{
EnemyTeamScore = EnemyTeamInfo.Score;
for(i=0; i<VehicleDriverPointsArray.Length; i++)
if(VehicleDriverPointsArray[i].Driver != None)
{
if (ScoreMethod == 1){
RelativeTimeDriven = VehicleDriverPointsArray[i].TimeDriven/TimeCarryingFlag;
Points = RelativeTimeDriven*MaxScore;
Adren = RelativeTimeDriven*MaxAdren;
}
else{
Points = min(VehicleDriverPointsArray[i].TimeDriven, MaxScore);
Adren = min(VehicleDriverPointsArray[i].TimeDriven*2, MaxAdren);
}
if(PlayerController(VehicleDriverPointsArray[i].Driver) != None)
PlayerController(VehicleDriverPointsArray[i].Driver).ClientMessage("Flag Run Assist! Points:"@string(int(Points * 100) / 100)$", Adrenaline:"@string(int(Adren * 100) / 100));
VehicleDriverPointsArray[i].Driver.PlayerReplicationInfo.Score += Points; //Flag carrier gets MaxScore points on flawless cap.
VehicleDriverPointsArray[i].Driver.Adrenaline += Adren; //Flag carriers get MaxAdren adrenaline.
}
}
TimeCarryingFlag = 0;
VehicleDriverPointsArray.Length = 0;
}
//============================================================================
// UpdateTimeDrivenFor: give current driver seconds.
// GetIndexOf: gets array index of current driver.
// AddToArray: add current driver to array.
//============================================================================
function UpdateTimeDrivenFor(Controller Driver)
{
local int i;
i = GetIndexOf(Driver);
if(i != -1)
VehicleDriverPointsArray[i].TimeDriven += 1;
else
AddToArray(Driver);
}
function int GetIndexOf(Controller C)
{
local int i;
for(i=0; i<VehicleDriverPointsArray.Length; i++)
if(VehicleDriverPointsArray[i].Driver == C)
return i;
return -1;
}
function AddToArray(Controller C)
{
local int i;
i = VehicleDriverPointsArray.Length;
VehicleDriverPointsArray.Length = i + 1; //VehicleDriverPointsArray.Length++; would make it crash 0_o
VehicleDriverPointsArray[i].Driver = C;
VehicleDriverPointsArray[i].TimeDriven = 1;
}
defaultproperties
{
}
Have you got that many comments in the code piglet? I'm impressed, I've just realised where I've been going wrong in most of my coding :)) :)) :))
This is just losely connected but I don't thing flag returns should give flat X points, they should give more points the closer the flag is about to get captured, which could be calculated based on the flag carrier's time/distance etc.
Relatively, the person standing on a manta wing should get many fewer points than the manta pilot, since the pilot is the one with the skill.
I've been a little miffed that taking the flag gets zero adrenaline. My understanding is that's due to the method of repeatedly dropping/picking up the flag to quickly get to 100 adrenaline, but maybe then dropping the flag should remove the same amount that picking up the flag gets you?
Piglet when you say dummy on the wing , I will reveal 1 thing which most people don't know: You can sit as a dummy and allow the driver to help you score BUT a real wing sitter is a very highly skilled player who knows how to not fall off the wing when it is shot at / player is hit etc. I am myself a very skilled wing sitter and I won't reveal how I don't fall off but I know there are others who knows the art of surviving a ride home and that is why there should be a few pat in the back for the wingers ;) Like we all know, the only way for sup to get laid is when hell is there as his wingman :D
We will have to create a demo tutorial to show 'friends' how to be a good wingman :D
Quote from: Stealer on February 28, 2024, 18:22
Have you got that many comments in the code piglet? I'm impressed, I've just realised where I've been going wrong in most of my coding :)) :)) :))
That's not my code.
In my paid coding career I commented, documented, and full-path tested everything...every single possible path through the code. I'm not as rigourous as that for home stuff. There are occasions I come back to things and try and remember quite why I did it like that....
Quote from: Unaben on February 28, 2024, 19:07
This is just losely connected but I don't thing flag returns should give flat X points, they should give more points the closer the flag is about to get captured, which could be calculated based on the flag carrier's time/distance etc.
That's sensible. Do you know of a serveractor for that, or are you able to write one? It doesn't sound that hard.
Quote from: hellfire on February 29, 2024, 11:16
Piglet when you say dummy on the wing ... a real wing sitter is a very highly skilled player who knows how to not fall off the wing when it is shot at
There's more than crouching and hoping?
Yup :) Way more. That is why in my vids you will see friends flying off my manta at the slightest touch anywhere vs Risel who when she sits, can be like a rock ;) The less experienced the wingman, the more tough luck the manta driver has :)
Hmmm... I'm not entirely sure I believe that...as long as you know which bits are safe to crouch on...which was something you needed to know from the very early days of ONS to ensure you got to the first node on Torlan
I'm not disparaging "dummies". I rarely do the flying. I'm more often the dummy.
Quote from: hellfire on February 29, 2024, 11:16
Like we all know, the only way for sup to get laid is when hell is there as his wingman :D
Yes, thanks hell
This is a great example of how not to sit on the manta wing
Quote from: Ekulz on February 29, 2024, 12:06
We will have to create a demo tutorial to show 'friends' how to be a good wingman :D
Agree
First step: double jump
Quote from: sup on February 29, 2024, 12:57
Quote from: hellfire on February 29, 2024, 11:16
Like we all know, the only way for sup to get laid is when hell is there as his wingman :D
Yes, thanks hell
This is a great example of how not to sit on the manta wing
:D :D :D
A decent wingman gives the driver the opportunity to perform tighter maneuvers that would otherwise catapult them to Valhala >:D
Anyone can stand how they want in a straight line, but crouching and sitting closer to the edge of the wing is important for a 1st class flight.
Quote from: Piglet on February 29, 2024, 12:11
That's sensible. Do you know of a serveractor for that, or are you able to write one? It doesn't sound that hard.
Sadly not. I could write one, but I have no experience with UE2.
The idea would be if you return a flag in the base you would only get 1 point, and for the most clutch return you would get X point, returning a flag in the middle of the map would be X/2 points.
This can be combined with time based return too, returning the flag that's been dropped under 3 seconds from it's pick up time is 1 points, returning a flag that's been taken for over 60 seconds would be X points.
This would hopefully incentivize players to go after carriers, instead of just camping in base. Also to prevent farming points by letting the enemy to pick up the flag intentionally.
I've added back in the manta assist code. I'm still happy to get any updates....
I saw the sup video and it proves my point :) If you notice where he sat when I used the slope to lift the manta, you will know what I meant about quality wingmen :) For perspective, I would have never fallen off that way ;) Lao taught me years back about this hehe
I notice manta assists have been re-enabled but drivers are scoring 3 points per run and wingmen are scoring the full 15 (i think)? I scored 3 manta runs (9 points total) but still finish on the bottom half of scoreboard :D Please can u explain what changes have been implemented? Thanks
No changes. See the code above for how it calculates score.
Quote from: Piglet on March 06, 2024, 09:41
No changes. See the code above for how it calculates score.
Unfortunately i'm no coder so it may as well be Japanese :P
It still appears to be awarding 3 points per run for me...strange!
You're quite right. Its configuration has been changed somehow. I'll correct it next time I have the server down for maintenance.
Quote from: Piglet on March 12, 2024, 20:54
You're quite right. Its configuration has been changed somehow. I'll correct it next time I have the server down for maintenance.
Perfect! Thanks buddy 8)
That should be fixed now. I still can't see how it got changed, as the backup had the right values. Wierd.
So if your passanger gets knocked down and you score the flag as a manta runner you are awarded with doubled 30+ points, this doesn't really seems reasonable for me. Some ppl can't even get this score in a 20 minute game. Saw this happen a couple of times yesterday.
Quote from: Piglet on March 13, 2024, 09:21
That should be fixed now. I still can't see how it got changed, as the backup had the right values. Wierd.
Quote from: Unaben on March 14, 2024, 22:17
So if your passanger gets knocked down and you score the flag as a manta runner you are awarded with doubled 30+ points, this doesn't really seems reasonable for me. Some ppl can't even get this score in a 20 minute game. Saw this happen a couple of times yesterday.
It isn't 30 points per cap lol! I believe Piglet reverted to the previous code which awards 15 for driver and 15 for wingman (those are the scores I saw today at least).
I'm not sure which part you don't understand...
Quote from: Ekulz on March 14, 2024, 22:52
Quote from: Unaben on March 14, 2024, 22:17
So if your passanger gets knocked down and you score the flag as a manta runner you are awarded with doubled 30+ points, this doesn't really seems reasonable for me. Some ppl can't even get this score in a 20 minute game. Saw this happen a couple of times yesterday.
It isn't 30 points per cap lol! I believe Piglet reverted to the previous code which awards 15 for driver and 15 for wingman (those are the scores I saw today at least).
If your passenger gets knocked off, you don't have the flag as driver O:-)
Well I figured the knocked off as dies due to cringe, auto-drops the flag because of health reached zero, then you exit your mantacopter on the left side then do a little fortnite dance emote while typing `lol` into chat before picking up the flag would be self explinatory. Because that's the only way you would score the flag as a manta driver and get double 15 point awarded for the same flagrun.
Quote from: Right on March 14, 2024, 23:33
If your passenger gets knocked off, you don't have the flag as driver O:-)
I really understand why you were banned
Quote from: Right on March 14, 2024, 23:33
If your passenger gets knocked off, you don't have the flag as driver O:-)
The code counts the time the flag runner was on the manta and also the time for the entire flag run. It gives each driver a proportion of the 15 points for the time they were assisting: 15 / (driver assist time / flag run time)
So technically you can get more than 15 points for the same flag run with the changes, which was my whole point of that beeing kinda unfair.
Quote from: Piglet on March 16, 2024, 18:40
Quote from: Right on March 14, 2024, 23:33
If your passenger gets knocked off, you don't have the flag as driver O:-)
The code counts the time the flag runner was on the manta and also the time for the entire flag run. It gives each driver a proportion of the 15 points for the time they were assisting: 15 / (driver assist time / flag run time)
Well, as I always say (when the code is provided)...if someone wants to spend the time and effort making it better I'll consider any submissions.
The strange thing is....I can't remember anyone other than @Holyspam ever taking me up on the offer. Guess what? His code is running...
It would be a lot easier of you open source it and accept pull requests, since it's kinda unexpected to make changes on a code that you don't know/see without the ability to test it yourself at all.
It this case my suggestion would be a simple maximizing that a singe flag score can't exceed 15 points.
Quote from: Piglet on March 18, 2024, 09:35
Well, as I always say (when the code is provided)...if someone wants to spend the time and effort making it better I'll consider any submissions.
The strange thing is....I can't remember anyone other than @Holyspam ever taking me up on the offer. Guess what? His code is running...
The code is here...on the second post of this thread (https://miasma.rocks/index.php/topic,1935.msg25076.html#msg25076)....
Cool, here are my suggested changes:
//============================================================================
// $Id: Mia_FlagrunInfo.uc by Jrubzjeknf
//============================================================================
class Mia_FlagrunInfo extends ReplicationInfo;
//============================================================================
// Variables
//============================================================================
var TeamInfo EnemyTeamInfo;
var float EnemyTeamScore;
var float TimeCarryingFlag;
var float FlagTakenTime;
var int ScoreMethod;
var int MaxScore;
var int MaxAdren;
var PlayerReplicationInfo LastHolderPRI;
struct VehicleDriverPoints
{
var Controller Driver;
var float TimeDriven;
};
var array<VehicleDriverPoints> VehicleDriverPointsArray;
//============================================================================
// PostBeginPlay
//
// Initiates flag monitoring.
//============================================================================
function PostBeginPlay()
{
Super.PostBeginPlay();
SetTimer(1, true);
}
//============================================================================
// Timer
//
// Checks if the flag carrier is sitting on a Vehicle. Every second he's sitting
// on one, the Vehicle driver gets an assist second. This will be used for
// giving the Vehicle driver points and adrenaline for the Vehicle run.
//============================================================================
function Timer()
{
local pawn Driver;
local Controller C;
if(Owner != None)
{
if(Owner.IsInState('Held'))
{
if(CTFFlag(Owner).Holder != None) {
LastHolderPRI = PlayerReplicationInfo(CTFFlag(Owner).Holder);
}
}
if(FlagTakenTime != CTFFlag(Owner).TakenTime) //the flag has just been taken, check it the flag has been captured between seconds.
{
CheckCapture();
FlagTakenTime = CTFFlag(Owner).TakenTime;
}
if(!Owner.IsInState('Home')) //The flag is being carried or has been dropped.
{
TimeCarryingFlag += 1;
if(CTFFlag(Owner).Holder != None &&
CTFFlag(Owner).Holder.Base != None &&
Vehicle(CTFFlag(Owner).Holder.Base) != None &&
Vehicle(CTFFlag(Owner).Holder.Base).Driver != None) //The flag carrier is sitting on an occupied Vehicle.
{
Driver = Vehicle(CTFFlag(Owner).Holder.Base).Driver;
if(Driver.GetTeamNum() == CTFFlag(Owner).Holder.GetTeamNum() && Driver != CTFFlag(Owner).Holder){ //The Vehicle driver is friendly (and not self!).
if (Driver.DrivenVehicle != None && Driver.DrivenVehicle.Controller != None){
C = Driver.DrivenVehicle.Controller;
}
else{
C = Driver.Controller;
}
UpdateTimeDrivenFor(C); //Give the driver seconds.
}
}
}
else if(TimeCarryingFlag != 0) //The flag is home, but has been carried. Check if the flag has been captured.
CheckCapture();
}
}
//============================================================================
// CheckCapture
//
// Check is the flag has been captured.
//============================================================================
function CheckCapture()
{
local int i;
local float RelativeTimeDriven;
local float Points;
local float Adren;
if(EnemyTeamScore != EnemyTeamInfo.Score)
{
EnemyTeamScore = EnemyTeamInfo.Score;
for(i=0; i<VehicleDriverPointsArray.Length; i++)
if(VehicleDriverPointsArray[i].Driver != None)
{
if(LastHolderPRI == None ||
LastHolderPRI.PlayerID != VehicleDriverPointsArray[i].Driver.PlayerReplicationInfo.PlayerID)
{
if (ScoreMethod == 1){
RelativeTimeDriven = VehicleDriverPointsArray[i].TimeDriven/TimeCarryingFlag;
Points = RelativeTimeDriven*MaxScore;
Adren = RelativeTimeDriven*MaxAdren;
}
else{
Points = min(VehicleDriverPointsArray[i].TimeDriven, MaxScore);
Adren = min(VehicleDriverPointsArray[i].TimeDriven*2, MaxAdren);
}
if(PlayerController(VehicleDriverPointsArray[i].Driver) != None)
PlayerController(VehicleDriverPointsArray[i].Driver).ClientMessage("Flag Run Assist! Points:"@string(int(Points * 100) / 100)$", Adrenaline:"@string(int(Adren * 100) / 100));
VehicleDriverPointsArray[i].Driver.PlayerReplicationInfo.Score += Points; //Flag carrier gets MaxScore points on flawless cap.
VehicleDriverPointsArray[i].Driver.Adrenaline += Adren; //Flag carriers get MaxAdren adrenaline.
}
}
}
TimeCarryingFlag = 0;
LastHolderPRI = None;
VehicleDriverPointsArray.Length = 0;
}
//============================================================================
// UpdateTimeDrivenFor: give current driver seconds.
// GetIndexOf: gets array index of current driver.
// AddToArray: add current driver to array.
//============================================================================
function UpdateTimeDrivenFor(Controller Driver)
{
local int i;
i = GetIndexOf(Driver);
if(i != -1)
VehicleDriverPointsArray[i].TimeDriven += 1;
else
AddToArray(Driver);
}
function int GetIndexOf(Controller C)
{
local int i;
for(i=0; i<VehicleDriverPointsArray.Length; i++)
if(VehicleDriverPointsArray[i].Driver == C)
return i;
return -1;
}
function AddToArray(Controller C)
{
local int i;
i = VehicleDriverPointsArray.Length;
VehicleDriverPointsArray.Length = i + 1; //VehicleDriverPointsArray.Length++; would make it crash 0_o
VehicleDriverPointsArray[i].Driver = C;
VehicleDriverPointsArray[i].TimeDriven = 1;
}
defaultproperties
{
}
Quote from: Piglet on March 18, 2024, 14:23
The code is here...on the second post of this thread (https://miasma.rocks/index.php/topic,1935.msg25076.html#msg25076)....
Thank you.
Yes. That makes perfect sense.
One small correction:
LastHolderPRI = CTFFlag(Owner).Holder.PlayerReplicationInfo;
The Holder is the pawn that's holding the flag. We need its PRI.