murder mystery voting to spawning system

@BRGJuanCruzMK I don’t want to annoy you with this again so my apologies,but I’ve been testing out the spawning and for some reason, the ui isn’t popping up nor is it teleporting could you tell me whats wrong its been driving me nuts again thank you for your help i don’t think i could have made it this far with out you

using { /Fortnite.com/Devices }

using { /Verse.org/Simulation }

using { /UnrealEngine.com/Temporary/Diagnostics }

# A Verse-authored creative device that can be placed in a level

voting := class(creative_device):

#The candidates

@editable Candidates : \[\]voting_candidate = array{}



#These start/end the voting

@editable StartVotingTrigger : trigger_device = trigger_device{}

@editable EndVotingTrigger : trigger_device = trigger_device{}



#If false, just waits for the end voting trigger

#If there's a value, it will end after that duration

@editable Duration : ?float = false



#The number of voting candidates to pick when voting

@editable NumToPick : int = 4

@editable Randomize : logic = false



#UI Settings

@editable ShowVoteCount : logic = false #If true, shows the vote count in the UI



var PlayerUIMap : \[player\]voting_ui = map{}

var PlayerChoiceMap : \[player\]candidate_enum = map{}

using { /Fortnite.com/Devices }

using { /Verse.org/Simulation }

using { /UnrealEngine.com/Temporary/Diagnostics }

using { /Fortnite.com/Devices }

using { /Fortnite.com/UI }

using { /Verse.org/Simulation }

using { /Verse.org/Random }

using { /Verse.org/Assets }

using { /Verse.org/Colors }

using { /UnrealEngine.com/Temporary/Diagnostics }

using { /UnrealEngine.com/Temporary/UI }

using { /UnrealEngine.com/Temporary/SpatialMath }

using { /Fortnite.com/Characters }

(Widget:widget).Refresh():void=

Widget.SetVisibility(widget_visibility.Hidden)

Widget.SetVisibility(widget_visibility.Visible)

<#> BEGIN STUFF YOU NEED TO CHANGE IN VERSE0.0.0.0.0

#Things you are voting on

candidate_enum:=enum:

sunriseapartments

nightscabin

floatblock

cosyvillage

(CE:candidate_enum).ToTexture():texture= #FolderName.TextureName

case(CE):

    candidate_enum.sunriseapartments=>Textures.sunriseapartments

    candidate_enum.nightscabin=>Textures.nightscabin

    candidate_enum.floatblock=>Textures.floatblock

    candidate_enum.cosyvillage=>Textures.cosyvillagevote

<#> END STUFF YOU NEED TO CHANGE IN VERSE

# A Verse-authored creative device that can be placed in a level

voting_ui_device := class(creative_device):

#The candidates

@editable Candidates : \[\]voting_candidate = array{}



#These start/end the voting

@editable StartVotingTrigger : trigger_device = trigger_device{}

@editable EndVotingTrigger : trigger_device = trigger_device{}



#If false, just waits for the end voting trigger

#If there's a value, it will end after that duration

@editable Duration : ?float = false



#The number of voting candidates to pick when voting

@editable NumToPick : int = 4

@editable Randomize : logic = false



#UI Settings

@editable ShowVoteCount : logic = false #If true, shows the vote count in the UI



var PlayerUIMap : \[player\]voting_ui = map{}

var PlayerChoiceMap : \[player\]candidate_enum = map{}

var ActiveCandidates : \[\]candidate_enum = array{}



\# Runs when the device is started in a running game

OnBegin<override>()<suspends>:void=

    StartVotingTrigger.TriggeredEvent.Subscribe(StartVoting)



StartVoting(mAgent:?agent):void=

    DoneVoting.Signal() #ERROR, kill any current voting systems

    spawn. HandleStart()



HandleStart()<suspends>:void=

    AllCandidates : \[\]candidate_enum = for(C:Candidates). C.Candidate

    #ERROR: Slice Already does EndIndex-1

    if:

        Randomize?

        NewCandidates:=Shuffle(AllCandidates).Slice\[0,NumToPick\]

    then. set ActiveCandidates = NewCandidates

    else if:

        NewCandidates:=AllCandidates.Slice\[0,NumToPick\]

    then. set ActiveCandidates = NewCandidates

    else:

        Print("ERROR: Failed to generate candidates")

        return

    var ClassArray : \[\]voting_candidate = array{}

    for(AC:ActiveCandidates):

        for(C:Candidates). if(C.Candidate=AC). set ClassArray += array. C



    #Add UIs to Players

    for(Player:GetPlayspace().GetPlayers()):

        NewVotingUI:=MakeVotingUI(ClassArray)

        if:

            set PlayerUIMap\[Player\] = NewVotingUI

            PlayerUI:=GetPlayerUI\[Player\]

        then:

            PlayerUI.AddWidget(NewVotingUI.Widget,player_ui_slot{InputMode:=ui_input_mode.All})

            #ERROR

            NewVotingUI.Widget.Refresh()

            spawn. HandleUI(Player,NewVotingUI)



    spawn. HandleVoteChange()

    #Wait for duration or for the trigger

    if(TrueDuration:=Duration?):

        race:

            Sleep(TrueDuration)

            EndVotingTrigger.TriggeredEvent.Await()

    else. EndVotingTrigger.TriggeredEvent.Await()



    #End Voting

    EndVoting()



HandleDuration(VoteUI:voting_ui)<suspends>:void=

    if(TrueDuration:=Duration?):

        StartTime:=GetSimulationElapsedTime()

        loop:

            Sleep(1.0)

            PassedTime:=GetSimulationElapsedTime()-StartTime

            if(PassedTime>=TrueDuration). return

            else. VoteUI.PromptTextBlock.SetText(S2M("Vote: {Ceil\[TrueDuration-PassedTime\] or -1}"))



HandleVoteChange()<suspends>:void=

    if(ShowVoteCount?):

        race:

            DoneVoting.Await()

            loop:

                var CurrVotes : \[candidate_enum\]int = map{}

                #ERROR: Initialize first

                for(AC:ActiveCandidates). if. set CurrVotes\[AC\] = 0

                for(Choice:PlayerChoiceMap):

                    if. set CurrVotes\[Choice\] += 1

                #Get Current Votes

                #Set on each ui

                for(UI:PlayerUIMap):

                    UI.UpdateVotes(CurrVotes)

                PlayerChoiceChangedEvent.Await()



HandleUI(Player:player,VoteUI:voting_ui)<suspends>:void=

    spawn. HandleDuration(VoteUI)

    race:

        DoneVoting.Await()

        loop:

            ChosenCandidate:=VoteUI.CandidateSelectionEvent.Await()

            if. set PlayerChoiceMap\[Player\] = ChosenCandidate

            PlayerChoiceChangedEvent.Signal()

        VoteUI.SubmitButton.OnClick().Await()



    if. PlayerUI:=GetPlayerUI\[Player\]

    then. PlayerUI.RemoveWidget(VoteUI.Widget)

    VoteUI.Widget.Refresh() #ERROR

    VoteUI.KillEvent.Await() #ERROR 1: KILL AFTERWARDS



DoneVoting : event() = event(){}

PlayerChoiceChangedEvent : event() = event(){}



EndVoting():void=

    DoneVoting.Signal() #Kills handleUI, removes player uis

    set PlayerUIMap = map{}



    TallyVotes()



    #Clear data for future use

    set PlayerChoiceMap = map{}



TallyVotes():void=

    #The key is the candidate, int is num votes

    var Ballot : \[candidate_enum\]int = map{}

    for(AC:ActiveCandidates). if. set Ballot\[AC\] = 0

    for(Candidate:PlayerChoiceMap):

        if. set Ballot\[Candidate\] += 1



    var HighestVotes : int = -1

    var Winners : \[\]candidate_enum = array{}



    for(Candidate->NumVotes:Ballot):

        if(NumVotes>HighestVotes): #New Winner

            set HighestVotes = NumVotes

            set Winners = array. Candidate

        else if(NumVotes=HighestVotes): #Tie

            set Winners += array. Candidate



    var Winner : ?candidate_enum = false

    #What about when no votes have been submitted?

    if(Winners.Length<=0):

        Print("No votes found, picking random")

        if. FoundWinner:=Shuffle(ActiveCandidates)\[0\]

        then. set Winner = option{FoundWinner}

    else:

        Print("Picking from {Winners.Length} Tied Winners ")

        if. FoundWinner:=Shuffle(Winners)\[0\]

        then. set Winner = option{FoundWinner}



    if(TrueWinner:=Winner?):

        for(CandidateClass:Candidates):

            if(CandidateClass.Candidate = TrueWinner):

                CandidateClass.CompletedEvent.Trigger()

                return



    else. Print("ERROR: Failed to select winner")

voting_candidate := class:

@editable Candidate : candidate_enum = candidate_enum.sunriseapartments

@editable Title : string = ""

@editable Description : string = ""

@editable CompletedEvent : trigger_device = trigger_device{}

MakeVotingUI(ActiveCandidates:[]voting_candidate):voting_ui=

KillEvent : event() = event(){}

SelectionEvent : event(candidate_enum) = event(candidate_enum){}

NewVotingUI:=voting_ui:

    PromptTextBlock:=text_block{DefaultText:=S2M("VOTE"),DefaultTextColor:=color{R:=1.0,G:=1.0,B:=1.0}}

    CandidateWidgets:=for(AC:ActiveCandidates). MakeCandidateWidget(KillEvent,SelectionEvent,AC)

    SubmitButton:=button_loud{DefaultText:=S2M("Submit")}

    KillEvent:=KillEvent

    CandidateSelectionEvent:=SelectionEvent

NewVotingUI.Init()

return NewVotingUI

#This handles the entire UI menu

voting_ui:=class:

var Widget : widget = color_block{}

PromptTextBlock : text_block

CandidateWidgets : \[\]candidate_widget

SubmitButton : button_loud



KillEvent : event()

CandidateSelectionEvent : event(candidate_enum)



Init():void=

    set Widget = canvas:

        Slots:=array:

            canvas_slot:

                Widget:=PromptTextBlock

                Alignment:=vector2{X:=0.5,Y:=0.5}

                Anchors:=anchors{Minimum:=vector2{X:=0.5,Y:=0.1},Maximum:=vector2{X:=0.5,Y:=0.1}}

                SizeToContent:=true

            canvas_slot:

                Alignment:=vector2{X:=0.5,Y:=0.5}

                Anchors:=anchors{Minimum:=vector2{X:=0.5,Y:=0.5},Maximum:=vector2{X:=0.5,Y:=0.5}}

                SizeToContent:=true

                Widget:=stack_box:

                    Orientation:=orientation.Horizontal #ERROR should be horizontal

                    Slots:=for(CW:CandidateWidgets). stack_box_slot:

                        Widget:=CW.Widget

                        HorizontalAlignment:=horizontal_alignment.Center

                        VerticalAlignment:=vertical_alignment.Center

                        Padding:=margin{Left:=50.0,Right:=50.0}

            canvas_slot:

                Widget:=SubmitButton

                Alignment:=vector2{X:=0.5,Y:=0.5}

                Anchors:=anchors{Minimum:=vector2{X:=0.5,Y:=0.9},Maximum:=vector2{X:=0.5,Y:=0.9}}

                SizeToContent:=true

    spawn. HandleSelectionEvent() #ERROR: Forgot



HandleSelectionEvent()<suspends>:void=

    race:

        KillEvent.Await()

        loop:

            Candidate:=CandidateSelectionEvent.Await()

            for(CW:CandidateWidgets):

                if(CW.ActiveCandidate=Candidate): #Currently Selected

                    CW.BorderColorBlock.SetColor(SelectedColor)

                else. CW.BorderColorBlock.SetColor(UnselectedColor)



UpdateVotes(CurrVotes:\[candidate_enum\]int):void=

    for(CW:CandidateWidgets):

        CW.VoteButton.SetText(S2M("Vote: {CurrVotes\[CW.ActiveCandidate\] or 0}"))

black

UnselectedColor : color = color{}

SelectedColor : color = color{R:=1.0,G:=1.0}

S2M(S:string):message=“{S}”

MakeCandidateWidget(KillEvent:event(),CSE:event(candidate_enum),Candidate:voting_candidate):candidate_widget=

NewCandidateWidget:=candidate_widget:

    ActiveCandidate:=Candidate.Candidate

    KillEvent:=KillEvent

    CandidateSelectionEvent:=CSE

    BorderColorBlock:=color_block{DefaultColor:=UnselectedColor,DefaultDesiredSize:=vector2{X:=250.0,Y:=300.0}} #ERROR: Predefined Size

    InnerColorBlock:=color_block{DefaultColor:=color{B:=0.7}}

    TextureBlock:=texture_block{DefaultImage:=Candidate.Candidate.ToTexture(),DefaultDesiredSize:=vector2{X:=150.0,Y:=150.0}}

    TitleBlock:=text_block{DefaultText:=S2M(Candidate.Title),DefaultTextColor:=color{R:=1.0,G:=1.0,B:=1.0}}

    DescBlock:=text_block{DefaultText:=S2M(Candidate.Description),DefaultTextColor:=color{R:=1.0,G:=1.0,B:=1.0}}

    VoteButton:=button_loud{DefaultText:=S2M("VOTE")}

NewCandidateWidget.Init()

return NewCandidateWidget

#Handles individual candidates

candidate_widget:=class:

ActiveCandidate : candidate_enum

InnerPadding : float = 20.0

CenterPadding : float = 25.0



#This kills the event when its no longer needed

KillEvent : event()

CandidateSelectionEvent : event(candidate_enum)



var Widget : widget = color_block{}

#Widgets

BorderColorBlock : color_block

InnerColorBlock : color_block

TextureBlock : texture_block

TitleBlock : text_block

DescBlock : text_block

VoteButton : button_loud



Init():void=

    set Widget = overlay:

        Slots:=array:

            overlay_slot:

                Widget:=BorderColorBlock

                HorizontalAlignment:=horizontal_alignment.Fill

                VerticalAlignment:=vertical_alignment.Fill

            overlay_slot:

                Widget:=InnerColorBlock

                HorizontalAlignment:=horizontal_alignment.Fill

                VerticalAlignment:=vertical_alignment.Fill

                Padding:=margin{Top:=InnerPadding,Bottom:=InnerPadding,Left:=InnerPadding,Right:=InnerPadding}

            overlay_slot:

                HorizontalAlignment:=horizontal_alignment.Fill

                VerticalAlignment:=vertical_alignment.Fill

                Padding:=margin{Top:=CenterPadding,Bottom:=CenterPadding,Left:=CenterPadding,Right:=CenterPadding}

                Widget:=stack_box:

                    Orientation:=orientation.Vertical

                    Slots:=array:

                        stack_box_slot:

                            HorizontalAlignment:=horizontal_alignment.Center

                            VerticalAlignment:=vertical_alignment.Center

                            Widget:=TextureBlock

                        stack_box_slot:

                            Padding:=margin{Top:=5.0}

                            HorizontalAlignment:=horizontal_alignment.Center

                            VerticalAlignment:=vertical_alignment.Center

                            Widget:=TitleBlock

                        stack_box_slot:

                            Padding:=margin{Top:=5.0}

                            HorizontalAlignment:=horizontal_alignment.Center

                            VerticalAlignment:=vertical_alignment.Center

                            Widget:=DescBlock

                        stack_box_slot:

                            Padding:=margin{Top:=10.0}

                            HorizontalAlignment:=horizontal_alignment.Fill

                            VerticalAlignment:=vertical_alignment.Fill

                            Widget:=VoteButton

    spawn. HandleButton()



HandleButton()<suspends>:void=

    race:

        KillEvent.Await()

        loop:

            VoteButton.OnClick().Await()

            CandidateSelectionEvent.Signal(ActiveCandidate)

Spawners : \[\]player_spawner_device = array{}

if I’m being honest i have no real idea how code really works so you may have to explain this like I’m 5, Again my apologies and thank you kindly for your help

Hello again @Jams !

You are not annoying me! I’ll be checking your code and let you know when I find the issue!

Please be patient!

Hey @Jams how are you doing?

I’ve been checking your code, it is a bit confusing, but you are doing a great job! Don’t apologize, it is normal to feel lost when you are learning something new!

I have some questions about what you are doing so I can understand your process and the expected game flow:

  1. The code you shared is part of only one single device or you are creating multiple devices for this? If there are multiple devices, coould you tell me how to separate your shared code into those devices?

  2. Are you following only the tutorials I shared with you the last time?

  3. If you are using any other resources, could you tell me which ones and share the links?

  4. Are you using AI for coding or just tutorials?

  5. This one is really important: could you describe the exact game flow you want to achieve? (What happens in the pre-game? how the players select the map? how the UI should behave in that case? etc etc)

I’ll be waiting for your answers!

  1. i have most of the code in one array and i made other arrays for each map filling each of those arrays with spawners for each map i think I’ve connected them together put i don’t think there connected as when i tested it players spawn at random spawners at each map.

    1. i am indeed although Ive definitely missed something that I`m looking into that.
  2. i don`t think i am if i remember i will tell you as soon as i can.

    4. I try my best to go without ai i have used it when i was really stuck but i mainly looked back at what you told me for guidance.

    1. I`m trying to make it as smooth as possible so when people are in the pre game lobby its a smooth transition to voting and then murder and sheriff being picked and they all should spawn into one map at the same time as it picks the different roles.

I appreciate every thing you’ve done for me and thank you very much kindly for the help

I just realised that I forgot to tag you in it

@BRGJuanCruzMK my apologies for that

Hello again @Jams sorry for the delay!

I’ve been thinking about this case a lot and I think you are trying to develop a really complex set of interconnected systems in only one device. Let me help you re-structure the process a little bit.

I highly recommend you to slow down a bit and start thinking about the game you want to do in different parts. What does that means? That means it will be a lot easier for you if you divide the game in different systems and then work on them separately.

Also, if you’re still getting comfortable with Verse, I’d recommend starting with smaller systems and learning the fundamentals first before trying to build something this complex. Games like Murder Mystery involve many interconnected mechanics, so taking it step by step will make development much easier and more enjoyable.

Lets start with the separation of parts anyway!

You want people to start in a Lobby Room and wait for certain conditions to trigger the Map Voting Phase. The Lobby and those conditions should be managed with one device.

Then, when that condition is met, you want to start the Voting Phase and send the players to the corresponding map. This Map Voting Phase is a different device.

Once the players are on the voted map, you want to define who will be the murder and who will be the sheriff, which is a different device!

And lastly, you want another device to manage the round/gamplay.

My honest recommendation on this, is to start creating those devices one by one, and don’t start with the next until the one you are working on is completely done. Otherwise you will be carrying errors through all your code and never know what is happning.

There are a lot of tutorials about how to do each part of this game, I made some of them myself! You already have the voting system tutorials with the teleport to new maps. Let me share some other tutorials you can use:

  1. For the lobby, you can start the voting as simple as using a button device or you can create a logic that waits until a certain amount of players are ready as I show on this post: Assign AFK Players to a Team After Delay and Teleport All Players to Team Bases (UEFN Verse) - #2 by BRGJuanCruzMK
    You will need to modify some parts to make it work as you want.

  2. For the murder random selection you can use the same post where you commented the first time: Murder Mystery Style Random Selector - #2 by BRGJuanCruzMK
    You only need to modify it to add the “sheriff” role.

  3. And for the gameplay itself, it completely depends on what you want to do. You can use Round Manager devices with Timers and Item Spawners, or anything you want!.

The Key here is to think it and do it step by step!

And you can post in the forums whenever you have a doubt or need help, of course!

Edit: I completely forgot to mention you have Epic Developer Assistant ! You can ask for help to it and it will guide you! You should give it a try!

I shall try my best to do all of that ,I’ll try to update you along the way thank you for keeping my hopes up for this it’s been difficult and I really appreciate the help