[SUPPORT] Roguelike Deckbuilder Toolkit

Get it on FAB

This asset contains all the components you need to create a full roguelike deckbuilder game! Inspired by classics in the genre, the toolkit provides a flexible and modular framework for creating complex and interactive game rules. Check out the feature trailer:

The asset is data driven and largely component based, letting you easily add new cards, minions and artifacts through data tables and defining their behavior through components. Game visuals are kept separate from game logic through composition and a custom Action Queue system, making it easy to swap out the visuals for your own. The toolkit is filled with example content to use as references for your own additions.

Features:

  • Data and component-based card creation system.
  • A complete example game, with saving, loading, level transitions win/loss states.
  • Deep UI system, including card widgets, status effect display, enemy intentions, tooltips and more.
  • Lots of example cards, minions, artifacts and status effects.
  • Custom Event Dispatcher system for creating complex interactions between blueprints.
  • Custom made card frame and UI. Card portraits are public domain (see technical details).
  • The Attack Pattern Component lets you define how AI minions select their abilities.
  • Reward manager for awarding cards and artifacts of set rarities.
  • Node map between combat encounters lets the player choose their own path. (note that this map is currently not randomized, but must be hand placed).
3 Likes

Changelog:

Full changelog can be found on my Trello, but here are the highlights:

v1.4 (live 29.04.24)

  • Added dev comments to all gameplay tags and removed unused tags
  • Added descriptions to all remaining classes
  • Created global function for adding to a status capped to its max value
  • Pressing RMB while dragging a card now returns it to hand
  • Friendly Name of heroes no longer need to match their row name for hero selection to function
  • “Spawn and Play Hero Card” from BPML_Card now applies appropriate modifications to the spawned card such as from Strength
  • FIXED: Card removal on hero minion death was not working properly
  • FIXED: Attempting to unbind an event that was not bound would still call some logic associated with unbinding
  • FIXED: Splash icon now rotates to face the camera if the camera moves.

v1.3 (live 13.09.23)

  • Split the Puppet UI into a top and bottom section. This allows their position to stay constant relative to the Puppet if you move the camera.
  • New card status that auto plays a card on draw and then draws a new card.
  • Removed blank gameplay tag variables and Game Instance being passed as payloads in Events as such dummy variables are no longer needed in UE5.3.
  • Removed unused TransferTag input from SpawnAndAddNewCard interface function.
  • The Draw Card function now returns the drawn card as output.
  • FIXED: Potential memory leak in “Access Targeting Class Lazy” in BP_Card.

v1.2.3 (live 14.05.23)

  • Cards are now shrunk and moved to the side out of the way when used.
  • “Get status value” interface function.
  • FIXED: If minions were killed by their own card it logged several warnings.
  • FIXED: If an invalid status widget was selected for displaying a status an error would get thrown. Now it is simply not shown instead, as intended.
  • FIXED: Attack pattern with a value of 0 would not advance.
  • FIXED: “ResolveCallEvent” always returned false if calling a specified actor.
  • FIXED: “AddNewCardToPile” with a higher effect value than 1 added multiple references to the exact same card instead of creating duplicated cards.

v1.2.2 (UE5.1, live 22.01.23)

  • FIXED: Playing in standalone crashes the game when opening node map (does not affect PIE or packaged projects).
  • FIXED: Sword puppet had collision profile set to Overlap instead of Pawn, causing card targeting not to work with it.
  • FIXED: Clicking on a card to drag it with no mana permanently disables the end turn button (until you click anywhere).
  • Simplified the stat cost use rule. It now only looks at the stat for that specific use rules and not other rules for the same card. This will also prevent use rule costs from multiplying for each use rule included.
  • Added Enhanced Input.
  • Event.Action.Draw is now again called when cards are visually drawn.
  • Defaulted all out attack to 99 mana (in practice only affects mana number color).
  • Parameterized card transfer frequency in card transfer component

v1.2.1 (UE5.1)

  • FIXED: Cards do not update frame lighting if they cannot be played until you try to play them (was new issue for UE5.1)
  • FIXED: Card glow would not reappear if the player gained enough mana to make the card playable again
  • FIXED: Cards without a type set their rarity to invalid instead of setting their type to invalid
  • Removed unused EventHolder interface from DispatcherHubComponent
  • Added card effect for opening a node map

v1.2 (UE5.0)

  • “Story encounters” on the Node Map, where you are presented with a story and get to choose different outcomes. Five sample encounters included, demonstrating a variety of implementations (such as card removal, card upgrades, on map damage etc.)
  • Shop on the Node Map for buying cards.
  • Currencies as artifacts (coins included by default), with custom artifact bar.
  • Second “final” node map that is loaded after beating the spider boss
  • Added Paper Flipbook puppet (and new enemy minion making use of it).
  • Several new artifacts demonstrating new functionality (such as retaining mana, increasing card draw++).
  • Several new example cards demonstrating new functionality (such as retaining cards, using all remaining mana etc.)
  • Reshuffle animation when discard pile gets shuffled back into draw pile.
  • Object payloads and gameplay tag containers can now be passed through when calling an action, opening up more options for what can be done with events.
  • FIXED: Freshly spawned minions will slide in from the side of the map if they have no or a short entrance animation.
  • FIXED: Hand select screen cards do not use custom card visuals from data.

v1.1.2 (UE5.0)

  • FIXED: End game screen was not displayed after defeating the final boss in the UE5 version
  • FIXED: If adding multiple status indicators to layout, only the first was set up properly
  • FIXED: Reward cards that award multiple cards now works correctly.

v1.1.1 (UE4.26 and 4.27)

  • FIXED: Card Z order did not work properly in UE5 converted projects.
  • FIXED: Card offset on hover did not work properly in UE5 converted projects.
  • FIXED: Moving to chests on the artifact map don’t save your location.
  • Now displays “Blocked” text if an attack is blocked. Added an action for displaying splash text for this purpose.

v1.1 (UE4.26 and 4.27)

  • Added alternate hero with the default mannequin skeletal mesh.
  • FIXED: Attempting to draw with no cards in any piles causes infinite loop.
  • Exhaust hero’s card on death.
  • Killed heroes during combat set to 1 health on node map.
  • Display all heroes’ health on map.
  • Choosing heroes and decks in menu.
  • Allow for empty deck.

v1.01 (UE4.26 and 4.27)

  1. Fixed issue where card could be used while being exhausted or discarded if they were clicked quickly.
  2. Fixes issue where various event dispatchers would not unbind properly, creating a variety of issues.
  3. Fixes issue where getting multiple chest rewards in a row on the Node Map would cause artifact bonuses to multiply (related to issue 2 above)
  4. Fixed issue where cards in hand would glow even if they were not useable.
  5. Fixed issue where Final Blow would keep its previous mana cost reduction from another turn.
  6. Fixed an issue where AI Minions would lose their armor if using armor buffs two rounds in a row.

New update it out. This hotfix addresses a few issues in the initial release:

v1.01

  1. Fixed issue where card could be used while being exhausted or discarded if they were clicked quickly.
  2. Fixes issue where various event dispatchers would not unbind properly, creating a variety of issues.
  3. Fixes issue where getting multiple chest rewards in a row on the Node Map would cause artifact bonuses to multiply (related to issue 2 above)
  4. Fixed issue where cards in hand would glow even if they were not useable.
  5. Fixed issue where Final Blow would keep its previous mana cost reduction from another turn.
  6. Fixed an issue where AI Minions would lose their armor if using armor buffs two rounds in a row.

Yet a new update is out. Short time since the last one, but there were so many devs that wanted to have multiple heroes in their games that I felt the need to improve this functionality immediately. I also needed to fix one more game breaking bug. Here are the changes:

v.1.1

  1. Fixed bug where attempting to draw a card with no cards in either the draw or discard pile would cause an infinite loop.
  2. Refactored several parts of the code where a single hero was assumed, to allow for multiple heroes.
  3. Added option for selecting multiple heroes and multiple decks in the menu. Note, the existing cards and enemies are not designed with multiple heroes in mind, so even though it works it does not make sense gameplay wise. Intended as a starting point. Not enabled by default. Increase MaxHeroes in the WBP_HeroAddBox widget in WBP_MainMenu_RLDB to enable.
  4. Added Manny the mannequin as alternate hero.
  5. Cards belonging to a hero are exhausted on that hero’s death.

Hi Knut,

Recently picked up the RLDB, it’s awesome and very impressive. Managed to follow the tutorials over on Youtube and get some of the stuff working that I wanted to. There is however an issue I am facing personally, not sure if other people would be interested in the answer or not?

So I am a 2D artist, and I would really like to make this game in 2D, it seems like there is the functionality there to replace the 3D puppet with maybe a 3D widget? Then maybe change the camera to Orthographic or something like that.

I have tried to do this, by duplicating the existing parent puppet, adding a 3D widget, pointing it to a widget I made that just holds a texture.

I then went in to DT_Minions_Hero and duplicated the warrior and changed the “puppet” to the new puppet I had made and removed the 3D figure and all animations in the datable.

When I play the game all the data appears like health ETC, however there is no visual, the widget doesn’t appear. Also I had some issues when trying to play the attack card, my assumption is that the Action Queue is expecting a model to animate and can’t find one?

So I wondered if you could give me some help/advice on getting a “2D sprite” or a paper 2D sprite something like that to be the visual instead of a 3D model.

As an extended topic if you have time, what communications would need to be made in order to call an animation/flip book call in order to animate taking damage, death, ETC.

Thanks

1 Like

I noticed that there are no tool tips for the nodes on the node map, there is also no key for the map either.

So would it be straight forward enough to add the existing tooltip concept to the nodes? If so could you give some guidance on how one might go about doing that?

I would especially like to do this as I want to add nodes to the map that are not there currently, and I would like to give them some context, as they may not be as straight forward as combat, rest, ETC.

Thanks

Hi Maikeru Jackson, I’m happy to hear you like the asset! There are a lot of different questions in here and some of them are quite complex, so lets start with one and take it one step at a time.

So if you want to create 2D minions there are several ways to go about this. The Roguelike Deckbuilder Toolkit is designed so that the visuals of minions (called Puppets) are kept separate from BP_Minion, which takes care of the gameplay logic. One of my reasons for doing this was precisely to make it easier to swap out the visuals with something completely different, like 2D sprites. So here are the steps to setting up a simple sprite based minion:

First create your sprites. I used some I had made for ATBTT, another one of my assets:
image

Next, you need to modify the minion data tables so that they can hold sprite data, which are based on the FMinion struct. When changing values in blueprint sturcts Unreal Engine can sometimes be buggy and break some references that take time to set up again afterwards, but if you do the following you should have no issues:

  1. Save your project
  2. Open the struct you want to modify (FMinion in this case) and add the new value you want (a sprite variable in this case)
  3. save the struct and only this struct
  4. exit Unreal engine. Do not save anything else when prompted
  5. reopen Unreal Engine and all references to this struct will have updated appropriately

This is related to an engine issue with blueprint struct and is not specific to this project. Should save you some potential debugging headaches. Ok, after that digression let’s add a new Puppet.

Make a duplicate of BP_SkeletalPuppet. I’ve called mine BP_SpritePuppet.

Delete the skeletal mesh component. Add a new scene component (with a neutral transform) and add a sprite component to it. Change its transform until it looks right. Here is how I did it:

Next, add a node that sets the appearance based on the minion data:

Next I added a simple way to animate the sprite. Just a simple timeline that moves the minion up and down smoothly, triggering any animation events midway and signaling the end of the animation afterwards:


This is an extremely basic starting point, but should get you an idea of the events you need to call to have this interact properly with the action system.

There is a lot of stuff from the skeletal puppet that won’t work with the new paper puppet so we cut out a lot of stuff. The final event graph looks like this:

Next add some minions that use the new sprite puppet and have a sprite assigned (I added a similar one in DT_Minions_Heroes by duplicating Warrior and swapping the puppet and sprite):

Lastly add the following to the monster track. It will prevent a sliding animation at the start of combat:

Add your new minion and hero to the appropriate variables in the Game Instance and you can test the Arena map.

Let me know if this works for you and if it approaches what you have in mind. Then we can take it from there.

Hey,

Thanks for that, I have only tested it on the hero for the second, and it has worked out well.

I guess I would use the same function but off the exec pin do “whatever it takes” to animate the sprite via “sprite magic” (I’m not familiar with the working of paper 2D yet.) for an attack, cast, ETC?

Thanks for the help! I can now go test some bad guys and hopefully all will be good!

Great, happy to hear that!

By the way, regarding tooltips on the node map, it is not as straightforward as for the other tooltips in the kit, since the nodes are not widgets, and thus don’t have a built-in implementation for tooltips.

You would have to make your own my creating a new widget that follows the mouse and turns visible/updates appropriately when it detects that the mouse is over a node, such as through a line trace. Certainly doable, but takes a bit of work.

Have you considered doing what many games in the genre does and just use a map legend?

A map key/legend had occurred to me but I wasn’t sure aesthetically if it would be as good? In the short term as it is not a live or die moment for the game a key sounds like it would be the best thing maybe?

Not sure whether a widget would work, build a sort of map UI or slap an actor down on the map that just has all the icons in it?

Something to think about I guess. I did some custom widgets for a different project, I don’t remember it being super difficult, but I also don’t remember exactly how I did it either, so that might not be a good sign.

Hi again,

I created a new artefact and a new status action, I gave the player the artefact on start and loaded the game. The icon appears as it would for owning the artefact, and it is the icon I set up; there are however 2 issues.

  1. The action is not doing what I would like it to do.
  2. It is not working.

So what I wanted the artefact to do is to give X extra mana per turn as I wanted a character to start with high mana as part of their character setup. (Ideally would like to be able to set mana per character as part of their stats)

The way I have done it so far it adds 1 Mana at the start and end of every turn, it creates an icon and the number just keeps going up and up and up. I didn’t want it to be a continual growth of like 1 then 2 then 3 then 4, ETC…just say 1 extra per turn.

Even though I have a buff icon and the numbers are going up ETC, the mana never goes above 3, I can’t find where the mana is set and or stored, and I am not sure if there is a MAX limit that has been set as a default?

I would also like to create an artefact that allows the player to store unused mana for the rest of combat (only) so know how the mana system works or where to adjust it would be great.

Also I would like to create a card and artefact that allows the player to store block instead of having it go away each turn, and also to allow the player to keep their current hand at the end of the turn. So could you help or point me where I need to look in order to control these aspects of the game play? I have looked through what I thought might be the obvious places, like the instance, the character its self, the BP_Status_Mana, BP_Status, ETC; but alas have not found any reference to it.

Through cards and artefacts -

Increase Mana (decrease mana)
Store Mana for combat.
Store Block for turn (and/ or) combat.
Retain the current player hand.

Many Thanks.

If anyone reading this would like to do do an animated sprite, instead of making a sprite

Add a flip book variable and then in the character that you make add a flip book variable. Then when you are setting up the character instead of setting the sprite, set the flip book to a flip book animation. (You will need to have made a flip book animation before hand)

I now have my characters with a default flip book animation that they repeat over and over. (if you have a character that you don’t want to animate then simply add 1 frame to a flip book and set it the same way. It will work the same as just using a sprite)

I haven’t tested it yet, but I am going to be working on changing the flip book to an attack animation and back again when a card is played. In theory it is just a set on play and a set on end animation or at the end of the action.

Hey, sorry about the late answer. Christmas celebrations and finishing stuff up at work has taken a lot of time. I’ll answer them now:

Not saying it would be that difficult to add. I have made similar things before. Just that it is a bit more work than just adding a widget tooltip, since you have to add the functionality for checking the hovered node, setting the widget, setting visibility etc. yourself.

Essentially you could create a widget that is set to follow the cursor on tick. This function would be invisible by default and have tooltip text. When hovering over a node (using line traces, for instance) you could send a message with a text stored in the node to the widget and set the text.

Ok, so I should clarify a few things. In RLDB the hero and the card player is separate. The card player is what draws cards, has mana etc. The hero (or heroes) are the minons on the card player’s side, but they don’t themselves have card draw or mana by default, and these components do not immediately work if added to a hero.

So instead of altering things on the hero you should alter things on the card player. The heroes may still have a status that affects stuff on the card player, but then you will need to get a reference to it.

When it comes to mana and mana gain, those are two different statuses, both added to the Card Player by default. The Mana status effect says how much mana the player has currently. ManaGain sets how much mana is gained each turn. This is the one you want to modify for your mana gain effect.

With that explanation of how mana works perhaps it will be easier to add your changes. You have a lot of different things you want to achieve, so it is difficult to give answers to all of them, but if you could choose one specific one that you want to do first then I can give you an in-depth suggestion on how to achieve it. If you are able to implement that feature correctly we can move on to the next one.

Also, thanks for posting your method for setting up an animated sprite. That is how I would do it as well.

Hey,

Thanks for the reply, especially over Christmas.

I tried to lump together several things, because my assumption is they are all solved in relatively the same way. If I could understand when and where things are done, I could draw a line from start to finish and understand the flow of data. I could then far easier apply the same concept of mana to shield, to poison, or to something I add myself, ETC.

I also felt it might save retail space in terms of ask 1 question with 6 parts as opposed to ask 6 questions.

I will try to keep my questions simpler and more compartmentalised.

How is the number 3 derived for mana, where is this value/variable stored and set as the number? I can see things in BP_Status, BP_Status_Mana and BP_StatusManaGain, however no where can I se the number 3 declared in any of them.

As always any help is appreciate and thanks for your time.

Hi, don’t get me wrong. It is indeed useful that you lump the questions together as it gives me a better idea of what you want to achieve in total, which helps me in finding the best solutions for your particular use case. However, with a lot of different questions that all require a substantial amount of time to answer it is also useful to know which order you want to tackle them in.

In my experience, often some misunderstandings will appear as I’m coming up with solutions, and it is better to figure those out early rather than writing one massive answer where all my answers might be built upon a mistaken assumption.

I also have limited time to spend on support each day, so knowing which ones you have the most pressing need to solve is useful in that regard.

The number 3 is set as the default Status Value of the BP_Status_ManaGain component in BP_CardPlayer. In this component you will se that it sets Mana to its Status Value at the start of each turn. If you want to keep mana between turns you will want to use Add instead of Set.

BP_Status_Armor is a bit different. It is set to 0 at TurnStart, as you can see in its event graph.

Discarding the hand is handled in the BP_Status_Draw, also attached to BP_CardPlayer.

I totally understand, I appreciate all the help with understanding this.

Ahhhh I see it now.

It is in the card player, under the components, I was looking in the status component its self, then when you said in the card player I was looking for a function that set the value as opposed to looking at the components on the card player. Totally blind and misunderstood.

So if I wanted to change this per character, could I cast to Card player and access the BP status and change the value, or could I access the status directly somehow in order to change it? (the same thing for the card draw?)

Or is there an easier way to do it and I am overthinking it? I’d like to change the mana gain for each character, when selecting the character to play as.


Thanks for the info on the shield situation I have managed to make it stay between turns now, I haven’t made a specific new artifact to do it just yet, but got broken shield to act as a trigger for keeping the shield.

I haven’t worked out how to do it with a card just yet? As I would only want to store it for X number of turns as opposed to forever.

I have also managed to get the no hand discard working as well with an artifact, again not sure how I would do it with a card?

If you have any thoughts or advice on how I could set a number of turns via a card to store shield/hand/mana, I would appreciate it. I’ll keep working on it as it should be do-able right?

Thanks again for the help.

I don’t have any artefacts or starting artefacts and yet this is returning true, would you know why?

I did have this working; however, it stopped working; I think I figured out why, it was because I was using a loop and if there was more than one artefact in the array, there would be several outcomes. So when I was testing it as a solo artefact it was fine with the loop as soon as it was the 3rd one in the array I had issues.

I did this to solve it, however even though I never put anything in my starting artefact array this returns as true.

I am assuming the get artefacts from instance function that is being called here is just pulling “all” the artefacts in the DT_Artifacts table? It is the only reason I could think that this would return true if the array is empty?

However I tested this:

and it still returned as true even though I do not have that item in the array?

Any thoughts?

Thanks

Ahhhh I see it now.

It is in the card player, under the components, I was looking in the status component its self, then when you said in the card player I was looking for a function that set the value as opposed to looking at the components on the card player. Totally blind and misunderstood.

So if I wanted to change this per character, could I cast to Card player and access the BP status and change the value, or could I access the status directly somehow in order to change it? (the same thing for the card draw?)

Or is there an easier way to do it and I am overthinking it? I’d like to change the mana gain for each character, when selecting the character to play as.

There are multiple ways you can do this, but accessing the card player and the status is pretty simple to do and should work fine. I’ve added a utility function in a function library that lets you access the CardPlayer from anywhere (GetCardPlayer) and from there you can use the AddToStatus/SetStatus etc. interface functions to modify it.

Glad you were able to set up the armor retain like you wanted to :slight_smile: If you want some effect to keep going for several turns, I suggest using a status. You can have the status value as a timer, decrement it by one each turn and remove the effect once it reaches 0. I do this in the Fear status, so you can take a look there for inspiration.

What you’re seeing is because you’re not actually searching through the elements of the array here. You are getting a reference to the entire data table and seeing if the entry exists anywhere in the data table (which it does, naturally). Instead, when you break the DataTableRow struct compare the RowName with the name of your specified artifact instead and you should get the desired result.

Hope that helps!

This is what I had previously:

Is this what you mean, because this didn’t give me the correct result either?

Also if I am going through the “StartingArtifacts” array why would it be searching the entire datatable? Surely this array would only store the items added to it, wouldn’t it? Or am I misunderstanding that array?

Yep, a small misunderstanding. The Artifacts and StartingArtifacts arrays are made up of DataTableRowHandle structs. These structs contain two values: 1) A reference to the data table the data table row is in and 2) The row name of the specific row. All of the default artifacts are in DT_Artifacts, so if you access any of them the data table reference will point to DT_Artifacts. If you use that reference you get the entire data table. So if you want to do some specific behaviour based on some specific artifact you’re searching for in an array you can do this instead: