• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Actions Per Minute APM Calculating Script

Status
Not open for further replies.
Level 6
Joined
Sep 19, 2005
Messages
169
I am surprised this hasn't already been done. IF anyone could create it I'm sure many others would find this very useful as well. I know it might not be possible to create a flawless APM script, but is anyone who is decent at coding willing to help me with this?
 
Last edited:
It shouldn't be too much of a problem to make something like that, but accuracy may be an issue.

The easiest way I can think of is to register all order events and selection events, and make them increase the user's APM value. Have an array store the user's APM and then every minute average it out ((previous APM + current APM) / how many times APM has been calculated). Unless APM's don't work that way, because I haven't played Starcraft much so I never used those tools. They might just find the APM and refresh it to 0 every minute and recount it (so that each minute's APM is independent from the last).

I think part of the obstacle for this is figuring out just exactly how you want to create such a system. Some considerations:
  • How often do you want to update APM? (once a minute, twice, three times, etc.)
  • Do you want each APM to be averaged out with the previous APM? For example, a user who goes afk for a minute will have his APM suffer, but his APM won't reach 0 for that minute because it will instead average out the APM. (however, this makes the APM score difficult to bring back up)
  • Which events do you want to register for APM? (selection? issued orders?)
  • Are you going to allow button mashing to increase APM? (some APM system's filter out repeated orders to increase APM. Or they alternately spam orders to abuse it)

Possibly other things as well. Sounds like a cool idea to implement. Just have to get the details worked out.

For anyone else interested:
http://en.wikipedia.org/wiki/Actions_per_minute
 
Level 6
Joined
Sep 19, 2005
Messages
169
Ugh, I shoulda posted this in triggers and scripts. Oops. Well I have a risk map in mind. Although ideally it would be transferable to any melee or... fighting type screnario that isnt just a single unit type map. All great considerations Purge. I suppose it would make most sense to update it on a per minute basis, however have a threshold where if the actions are less than X it isn't included into the mean (average) APM
 

TKF

TKF

Level 19
Joined
Nov 29, 2006
Messages
1,266
This is a known implemented feature in some maps, such as Battle Tanks. I use APM system wheter to detect if a player goes afk or not and automatically makes shared control after 2 minutes, but I do not use it to stats settings.

Simply put a variable that register any orders of kind: APM / (gametime in seconds / 60)
 
Level 17
Joined
Jul 17, 2011
Messages
1,864
dota has this you can write -apm and it shows you a number pretty useless in my opinion however it could be used to detect if a player is afk or not im pretty sure registering all usable event in one trigger and then setting an array for each player should do it
 
Level 6
Joined
Sep 19, 2005
Messages
169
Im sure as other "league" organizers can attest, people are hardcore about their stats. And APM is a very useful tidbit of information and an epeen type of thing. I suppose the best way to do it would be to include apm as a string that showed different amounts of where the apm was coming from.

Select | Order | Command Y| TOTALAPM would appear as
32 | 12 | 54 | XXX for a grand total of whatever that equals to as a text string. Then the map maker could just parse it and grab what they wanted.

That sounds pretty sweet.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
For each interval per minute, reset your actionCounter to 0 and start counting.
At the end of the next minute, store the actionCounter set udg_totalCounter = udg_totalCounter + actionCounter and reset to 0 and repeat the process.

To get APM (average);
totalCounter / playingDuration

For example;
1st min - 20 APM
2nd min - 15 APM
3rd min - 17 APM
4th min - 12 APM
5th min- 18 APM

APM = 82 / 5 = 16.4 APM

But it's up to you how would you define "Action Per Minute".
Is it each minute ?
Average for duration of playing ?
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
I've edited my post #8, a bit clearer version of what I envisioned.

@Aero
A new feature for TCO ? :)

Also, first you need to define what do you meant by "action".
Cast Spells ?
Move ?
Order ?
Buying Item ?

You must have this list first.
 
Level 6
Joined
Sep 19, 2005
Messages
169
In my perfect world:
Selecting a new unit group including control groups and enemy units, deselecting unit groups, Training/detraining units, Any unit command including right clicks and rally point changes, Any non autocast ability including load and unload orders, any chat message sent.

Am I missing any important ones?
Other map people could probably use item usage but it doesnt have a point in my map. In my map at least there is occasionally downtime where players apm would drop siginificantly from their "fighting" apm. There should be a way to prevent this from being included as well.
 
Level 33
Joined
Mar 27, 2008
Messages
8,035
In DotA, you can only control 1 Hero (and that APM is from that Hero ONLY - summoned units/etc doesn't count).

What is your map looks like ?
Sounds like mass-control RTS-like game ?
So this APM applies to Player, not a certain Unit, right ?
 
Level 37
Joined
Aug 14, 2006
Messages
7,601
I've edited my post #8, a bit clearer version of what I envisioned.

@Aero
A new feature for TCO ? :)

Also, first you need to define what do you meant by "action".
Cast Spells ?
Move ?
Order ?
Buying Item ?

You must have this list first.
Yes, it would be wonderful to have for players system like this. Well, pretty much everything you can think of.
 
Level 6
Joined
Sep 19, 2005
Messages
169
In DotA, you can only control 1 Hero (and that APM is from that Hero ONLY - summoned units/etc doesn't count).

What is your map looks like ?
Sounds like mass-control RTS-like game ?
So this APM applies to Player, not a certain Unit, right ?

Correct. My map is a risk map. Strategy game with sometimes thousands of units. When I use a "replay parser" pro players have apms around 250-300
http://www.youtube.com/watch?v=2S_iL_ue7IQ&feature=relmfu
http://www.youtube.com/watch?v=WGXQCl6ocqA
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
Here's a simple APM detection library. It registers unit orders and selection events. If you select a unit group, it will still only count as one action. If you order a group of units to move, it counts as one action.

I will keep on improving it.

JASS:
library APM initializer init
    globals
        private     trigger                 APM_TRG
        private     integer array           A_COUNT
        private     real    array           APM
        private     timer   array           APM_TMR
        private     timer                   ELAPSED_TIME
        private     hashtable               ht
    endglobals

    private function registerAction takes nothing returns boolean
        local player p = GetTriggerPlayer()
        local integer id = GetPlayerId(p)
        
        if TimerGetRemaining(APM_TMR[id]) == 0.0 then
            set A_COUNT[id] = A_COUNT[id] + 1
            set APM[id] = A_COUNT[id] / (TimerGetElapsed(ELAPSED_TIME) / 60)
            call TimerStart(APM_TMR[id], 0.01, false, null)
            call DisplayTimedTextToPlayer(Player(0), 0, 0, 5, "Player 1 APM: " + I2S(R2I(APM[id])))
        endif
        
        return false
    endfunction
    
    function startAPM takes nothing returns nothing
        call EnableTrigger(APM_TRG)
        call TimerStart(ELAPSED_TIME, 1000000, false, null)
    endfunction
    
    function pauseAPM takes nothing returns nothing
        call DisableTrigger(APM_TRG)
        call PauseTimer(ELAPSED_TIME)
    endfunction
    
    private function init takes nothing returns nothing
        local integer i
        
        set ht = InitHashtable()
        set ELAPSED_TIME = CreateTimer()
        
        set APM_TRG = CreateTrigger()
        call TriggerAddCondition(APM_TRG, function registerAction)
        set i = 0
        loop
            set APM[i] = 0
            set APM_TMR[i] = CreateTimer()
            
            call TriggerRegisterPlayerUnitEvent(APM_TRG, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(APM_TRG, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(APM_TRG, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
            
            call TriggerRegisterPlayerUnitEvent(APM_TRG, Player(i), EVENT_PLAYER_UNIT_SELECTED, null)
            exitwhen i == 11
            set i = i + 1
        endloop
        call DisableTrigger(APM_TRG)
        call startAPM()
        call DisplayTimedTextToPlayer(Player(0), 0, 0, 5, "Init Finish")
    endfunction
endlibrary
 

Attachments

  • APM.w3x
    13.9 KB · Views: 157
Status
Not open for further replies.
Top