Welcome to the Jokers of Neon Modding Docs! This guide will help you create and customize mods to enhance gameplay, tweak game mechanics, and introduce new visuals.
With the mods, you can:
- Customize initial game configurations.
- Set up a personalized shop.
- Create unique deck setups.
- Design new special cards, rage cards, and loot boxes with distinct effects.
- Replace visual elements such as card designs, borders, and backgrounds.
- Dojo v1.1.2 Dojo docs (optional)
If you have a different version of Dojo, you can update it by running:
dojoup --version 1.1.2
The mods rely on a robust configuration system that allows you to modify various aspects of the game. These configuration files are located in: mods/<mod_name>/src/configs/
This folder contains the following key configuration files:
- Game Configuration: Defines gameplay rules and mechanics.
- Shop Configuration: Sets up the initial shop inventory.
Tip
Start by cloning this repo and navigate to mods/jokers_of_neon_template
to get familiar with the folder structure.
The Game Configuration file allows you to modify the foundational rules of the game. It’s located at:
mods/<mod_name>/src/configs/game.cairo
.
Here’s an example configuration:
GameConfig {
plays: 5, // Number of plays per round
discards: 5, // Number of discards allowed
specials_slots: 2, // Starting special card slots
max_special_slots: 7, // Maximum special card slots
power_up_slots: 4, // Starting power-up slots
max_power_up_slots: 4, // Maximum power-up slots
hand_len: 8, // Starting hand size
start_cash: 99999, // Starting cash amount
start_special_slots: 1, // Initial special slots available
}
The Shop Configuration file customizes the initial inventory available to players. It’s located at: mods/mod_name/src/configs/shop/config.cairo
.
Here’s an example configuration:
ShopConfig {
traditional_cards_quantity: 5, // Regular cards in shop
modifiers_cards_quantity: 3, // Modifier cards in shop
specials_cards_quantity: 3, // Special cards in shop
loot_boxes_quantity: 2, // Loot boxes in shop
power_ups_quantity: 2, // Power-ups in shop
poker_hands_quantity: 3, // Poker hand cards in shop
}
Special cards in Jokers of Neon introduce unique gameplay dynamics. They can grant or subtract points, multi, cash, and more. To streamline their behavior, we’ve implemented an abstract layer with predefined categories. Each category encapsulates fundamental methods to define and execute specific behaviors:
CardType::Hit
CardType::Discard
CardType::PowerUp
CardType::Round
CardType::PokerHand
CardType::Game
Below, we’ll explore each type, its use case, and implementation.
Description:
This card type is executed for every card in a player’s play. It uses the card’s Suit
and Value
properties to trigger effects.
Example:
Grant 100 points and 1 multi for every Joker in the play.
fn condition(self: @ContractState, context: GameContext, raw_data: felt252) -> bool {
let card: Card = raw_data.into();
card.suit == Suit::Joker
}
fn execute(ref self: ContractState, context: GameContext, raw_data: felt252) -> (i32, i32, i32) {
let joker_card: Card = raw_data.into();
((joker_card.points * 2).try_into().unwrap(), (joker_card.multi_add * 2).try_into().unwrap(), 0)
}
Tip
Suggested Use: Use this card type for effects tied to specific cards, such as rewarding certain suits or values.
Description:
This type of card is executed for each discarded card of a player. It uses the card’s Suit
and Value
properties to trigger effects.
Example:
Grant 500 cash for every discarded card.
fn condition(self: @ContractState, context: GameContext, raw_data: felt252) -> bool {
let card: Card = raw_data.into();
card.suit == Suit::Joker
}
fn execute(ref self: ContractState, context: GameContext, raw_data: felt252) -> (i32, i32, i32) {
(0, 0, 500)
}
Description:
This card type interacts with activated PowerUp
cards, leveraging their points
and multi
properties.
Example:
Double the points and multipliers of all activated PowerUps.
fn execute(ref self: ContractState, context: GameContext, raw_data: felt252) -> (i32, i32, i32) {
let power_up: PowerUp = raw_data.into();
((power_up.points * 2).try_into().unwrap(), (power_up.points * 2).try_into().unwrap(), 0)
}
Tip
Suggested Use: Amplify PowerUp effects or create synergy with specific PowerUp types.
Description:
This card type is triggered once per round and evaluates the state of the game, including player_score
, level_score
, remaining_plays
, and remaining_discards
.
Example:
Grant 100 points and 10 multiplier during the first play of the round.
fn execute(ref self: ContractState, context: GameContext, raw_data: felt252) -> (i32, i32, i32) {
if context.round.remaining_plays.into() == context.game.plays {
(100, 10, 0)
} else {
(0, 0, 0)
}
}
Tip
Suggested Use: Introduce strategic advantages based on the player’s progress within a round.
Description:
This card type triggers once per round and evaluates the poker hand formed during the play.
Example:
Grant 20 points and 4 multiplier for achieving a Two Pairs
poker hand.
fn execute(ref self: ContractState, context: GameContext, raw_data: felt252) -> (i32, i32, i32) {
if context.hand == PokerHand::TwoPair {
(20, 4, 0)
} else {
(0, 0, 0)
}
}
Tip
Suggested Use: Reward specific poker hands to add depth to hand-building strategies.
Description:
This card type modifies global game properties such as hand_len
, plays
, and discards
when equipped.
Example:
Increase the hand size by 2 cards when the card is equipped.
fn equip(ref self: ContractState, context: GameContext) -> GameContext {
let mut context = context;
context.game.hand_len += 2;
context
}
fn unequip(ref self: ContractState, context: GameContext) -> GameContext {
let mut context = context;
context.game.hand_len -= 2;
context
}
Tip
Suggested Use: Design cards that alter game rules for broader, long-term effects.
Tip
- Balance: Ensure the cards are neither too powerful nor too weak.
- Theme: Design cards that align with the Jokers of Neon universe.
- Testing: Verify that the conditions and executions work correctly in various scenarios.
- Documentation: Provide clear descriptions of each card’s effects for players.
Customize the appearance of special, traditional, neon, and modifier cards, along with game backgrounds and borders. You can also add new designs for newly implemented special cards.
Important
All modding resources must be placed in the directory: /public/mods/MOD_NAME/resources/
.
Replace MOD_NAME
with your mod's name.
You can modify existing card designs or add new ones. To replace a card, locate its specific ID and upload the image file to:
/public/mods/(MOD_NAME)/resources/Cards/{cardID}.png
Recommended size for cards is: 276 x 420 px
Category | Range | Details |
---|---|---|
Traditional Cards | 0-12 | Clubs (2 to Ace) |
13-25 | Diamonds (2 to Ace) | |
26-38 | Hearts (2 to Ace) | |
39-51 | Spades (2 to Ace) | |
52 | Joker | |
53 | Wildcard | |
Neon Cards | 200-212 | Clubs (2 to Ace) |
213-225 | Diamonds (2 to Ace) | |
226-238 | Hearts (2 to Ace) | |
239-251 | Spades (2 to Ace) | |
252 | Joker | |
253 | Wildcard | |
Other Cards | 300-400 | Special Cards |
401-600 | Rage Cards | |
601-700 | Modifier Cards |
Customize the game’s backgrounds by replacing the corresponding files in the /public/mods/(MOD_NAME)/resources/bg
folder:
game-bg.jpg
: Game backgroundhome-bg.jpg
: Home screen backgroundstore-bg.jpg
: Store screen background
To change the borders in your game, replace the following files in the /public/mods/(MOD_NAME)/resources/borders
folder :
bottom.png
bottom-rage.png
top.png
top-rage.png
You can also personalize the deck background by replacing the file located at:
/public/mods/(MOD_NAME)/resources/Cards/Backs/back.png
-
Clone this repo
-
Navigate to the
mods
folder in your game directory -
Copy the
jokers_of_neon_template
folder:cp -r jokers_of_neon_template your_mod_name
Important
Use underscores to separate words in the folder name
Every mod follows this basic structure:
└── mods/
└── MOD_NAME/
└── src/
├── configs/
│ ├── game/
│ └── shop/
├── specials/
│ ├── special_game_type/
│ ├── special_individual/
│ ├── special_poker_hand/
│ ├── special_power_up/
│ ├── special_round_state/
│ └── specials/
├── rages/
│ ├── game/
│ ├── round/
│ ├── silence/
│ └── rages/
├── lib.cairo
└── loot_box.cairo
└── public/mods/MOD_NAME/resources
This information is used to display your mod on the game's page.
Important
All files must be uploaded to your mod's resources folder: /public/mods/MOD_NAME/resources/
In the mod's resources folder, create a config.json
file containing essential details about your mod. Use the following structure:
{
"name": "My awesome JN Mod",
"description": "Brief description of your mod"
}
To customize the mod's preview image, upload an image named thumbnail.png
to the same directory as config.json
.
You can modify the initial game settings to create a more challenging experience while offering certain advantages. These parameters are defined in:
mods/(MOD_NAME)/src/configs/game.cairo.
Below is an example configuration with adjusted values for plays
, discards
, hand size
, and starting cash
:
GameConfig {
plays: 2, // Number of plays per round
discards: 7, // Number of discards allowed
max_special_slots: 5, // Maximum number of special slots
power_up_slots: 4, // Number of active power up slots
max_power_up_slots: 4, // Maximum number of power up slots
hand_len: 10, // Starting hand size
start_cash: 10000, // Starting cash amount
start_special_slots: 1, // Number of special card slots active at the start of the game
}
You can customize the shop to show more special cards and fewer traditional cards or loot boxes, tailoring the experience to your mod. The shop configuration is located in:
mods/mod_name/src/configs/shop.cairo
.
Example of a customized shop configuration:
ShopConfig {
traditional_cards_quantity: 2, // Regular cards in shop
modifiers_cards_quantity: 3, // Modifier cards in shop
specials_cards_quantity: 5, // Special cards in shop
loot_boxes_quantity: 1, // Loot boxes in shop
power_ups_quantity: 2, // Power ups in shop
poker_hands_quantity: 3 // Poker hands available to level up in shop
}
In this section, we’ll create a special card that rewards points
, multiplier
, and cash
when the player has a HighCard hand.
All special cards must be defined in mods/mod_name/src/specials/specials.cairo
, with each card assigned a unique ID between 300
and 400
.
Open mods/mod_name/src/specials/specials.cairo
and add the unique ID for your new Special Card:
const SPECIAL_HIGH_CARD_BOOSTER_ID: u32 = 309;
Add the new card id into the *specials_ids_all*
function :
fn specials_ids_all() -> Array<u32> {
array![
....,
SPECIAL_HIGH_CARD_BOOSTER_ID
]}
Assign the card to a group to make it purchasable in the shop. For example, add it to the SS group
:
Groups define the probability the card has for appearing in the shop and also its cost.
You can also adjust the probabilities and costs for each group. Ensure that the probabilities of all defined groups add up to 100.
let SS_SPECIALS = array![..., SPECIAL_HIGH_CARD_BOOSTER_ID].span();
Since this card is specific to PokerHand
functionality, its type will be CardType::PokerHand
. Navigate to the mods/mod_name/src/specials/poker_hand/
directory and create a new file named high_card_booster.cairo
. Add the implementation for your new card in this file.
After that whe should go to src/lib.cairo
and add this line to include our new module:
mod high_card_booster;
Below is an example of how to implement the HighCard Booster special card:
#[dojo::contract]
pub mod special_high_card_booster {
use jokers_of_neon_classic::specials::specials::SPECIAL_HIGH_CARD_BOOSTER_ID;
use jokers_of_neon_lib::interfaces::{base::ICardBase, cards::executable::ICardExecutable};
use jokers_of_neon_lib::models::{card_type::CardType, data::poker_hand::PokerHand, tracker::GameContext};
#[abi(embed_v0)]
impl HighCardBoostExecutable of ICardExecutable<ContractState> {
fn execute(ref self: ContractState, context: GameContext, raw_data: felt252) -> (i32, i32, i32) {
if context.hand == PokerHand::HighCard {
(100, 20, 500)
} else {
(0, 0, 0)
}
}
}
#[abi(embed_v0)]
impl HighCardBoostBase of ICardBase<ContractState> {
fn get_id(self: @ContractState) -> u32 {
SPECIAL_HIGH_CARD_BOOSTER_ID
}
fn get_types(self: @ContractState) -> Span<CardType> {
array![CardType::PokerHand].span()
}
}
}
get_id()
: Returns the unique ID of the card.get_type()
: Defines the card as a PokerHand type.execute()
: Implements the card’s effect. In this case:- HighCard Hand: Rewards 100 points, 20 multiplier, and 500 cash.
- Other Hands: Rewards 0 points, 0 multiplier, and 0 cash.
To ensure your special cards are accessible in the frontend, follow these steps:
Navigate to /public/mods/(MOD_NAME)/resources/
and update the specials.json
file to include the name and description of your special cards.
For example:
{
"CardID": {
"name": "Card Name",
"description": "Card Description"
},
"349": {
"name": "Random Diamond Joker",
"description": "Adds a number between -2 and 6 to the multiplier for each Diamonds-suited card played."
},
"355": {
"name": "Extra",
"description": "Demo"
}
}
Replace CardID with the unique ID of your card. For the card we implemented earlier, use
309
.
Upload an image for your special card to the following directory:
/public/mods/(MOD_NAME)/resources/Cards/{cardID}.png
Replace
{cardID}
with the unique ID of your card. For the example card, the image file should be named309.png
Once you have completed the implementation of your mod including frontend assets and cairo code, create a pull request to this repository.
Important
If you do not have Cairo installed, skip this step and comment your PR saying that you have skipped the deployment step, so that we can take care of it.
Rename the .env_example file to .env
Run the deploy command:
make deploy-mod mod_name=your_mod_name
Wait until your PR is merged. Once it is, you will be able to play your mod at modding.jokersofneon.com.