Community Tutorial: A Persistent Quest Counter in Verse Code

A look at creating a persistent QUEST counter in Verse Code. This is based on the Persistent Player Statistics tutorial within the Verse online documentation.

https://dev.epicgames.com/community/learning/tutorials/0J14/fortnite-a-persistent-quest-counter-in-verse-code

3 Likes

Hi ! I tried your code and it doesn’t work.

using { /Fortnite.com/Devices}
using { /Verse.org/Simulation}
using { /UnrealEngine.com/Temporary/Diagnostics}

#<persistable> added in UEFN 29.0
player_stats_table := class<final><persistable>:
    Score:player_stat = player_stat{}

var PlayerStatsMap:weak_map(player, player_stats_table) = map{}

MakePlayerStatsTable<constructor>(OldTable:player_stats_table)<transacts> := player_stats_table:
    Score := OldTable.Score

player_stat := class<final><persistable>:
    CurrentValue:int = 0

MakeUpdatedPlayerStat<constructor>(NewValue:int)<transacts> := player_stat:

stat_type := class<computes><unique><abstract>:
    DebugString():string

#Using instead of an enum because it can be added to later.
StatType := module:
    
    score_stat<public> := class<computes><unique>(stat_type):
        DebugString<override>():string = "Score"

    Score<public>:score_stat = score_stat{}

player_stats_manager := class():

    GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table=
        var PlayerStats:player_stats_table = player_stats_table{}
        if:
            Player := player[Agent]
            PlayerStatsTable := PlayerStatsMap[Player]
            set PlayerStats = MakePlayerStatsTable(PlayerStatsTable)
        PlayerStats

    InitializeAllPlayers(Players:[]player):void =
        for (Player : Players):
            InitializePlayer(Player)

    InitializePlayer(Player:player):void=
        if:
            not PlayerStatsMap[Player]
            set PlayerStatsMap[Player] = player_stats_table{}
    
    # ?Score needs a prefixed question mark indicating it matches
    # with a named argument when specifying a value other than the default.
    RecordPlayerStat(Agent:agent, Stat:stat_type, ?Score:int = 0):void=
        if:
            Player := player[Agent]
            PlayerStatsTable := PlayerStatsMap[Player]

            #Confirms which stat type to update.
            if(Stat = StatType.Score):

                set PlayerStatsMap[Player] = player_stats_table:
                    MakePlayerStatsTable<constructor>(PlayerStatsTable)
                    Score := MakeUpdatedPlayerStat(Score)
        Print("{Score}")


AND

using { /Fortnite.com/Devices}
using { /Verse.org/Simulation}
using { /UnrealEngine.com/Temporary/Diagnostics}

player_stats_example := class(creative_device):

    @editable
    MyTrigger:trigger_device = trigger_device{}

    @editable
    StatsBillboard:billboard_device = billboard_device{}

    PlayerStatsManager: player_stats_manager = player_stats_manager{}

    StatsMessage<localizes>(Score:int):message = "Score: {Score}"

    OnBegin<override>()<suspends>:void=
        MyTrigger.TriggeredEvent.Subscribe(AddScore)
        Players := GetPlayspace().GetPlayers()
        PlayerStatsManager.InitializeAllPlayers(Players)

    UpdateStatsBillboard(Agent:agent):void=
        if:
            CurrentPlayerStats := PlayerStatsManager.GetPlayerStats[Agent]
        then:
            StatsBillboard.SetText(StatsMessage(Score:=CurrentPlayerStats.Score.CurrentValue))

    #Code is more readable if put in IF/THEN expression
    AddScore(Agent:?agent):void=
        if:
            ValidAgent := Agent?,
            CurrentPlayerStats := PlayerStatsManager.GetPlayerStats[ValidAgent],
            CurrentScore := CurrentPlayerStats.Score.CurrentValue
        then:
            PlayerStatsManager.RecordPlayerStat(ValidAgent, StatType.Score, ?Score := CurrentScore + 1)
            UpdateStatsBillboard(ValidAgent)

Hi @ok_studios,

Great content. I’ve noticed that the stat_type class is displaying a deprecation warning in 31.00. Could you recommend the best approach to address this? Any suggestions would be appreciated!