Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 31 additions & 35 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,53 @@ name: Cairo-Dojo CI

on:
push:
branches: [ main, master ]
branches: [main]
pull_request:
branches: [ main, master ]
branches: [main]

env:
DOJO_VERSION: 1.6.1
SCARB_VERSION: 2.10.1
WORKING_DIRECTORY: ./backend/dojo_examples/combat_game
Copy link
Contributor Author

@okhaimie-dev okhaimie-dev Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future y'all just need to change the env variable to upgrade the dojo and scarb version no need to worry about asdf


jobs:
build-and-test:
name: Build and Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Install asdf
uses: asdf-vm/actions/setup@v2

- name: Verify asdf installation
run: asdf --version
uses: actions/checkout@v4

- name: Install Dojo plugin
- name: Download Dojo release artifact
run: |
asdf plugin add dojo https://github.com/dojoengine/asdf-dojo
asdf install dojo 1.2.1
asdf global dojo 1.2.1
asdf list dojo
which sozo || echo "sozo not found"
ls -la /home/runner/.config/.dojo/bin/ || echo "Directory not found"
curl -L -o dojo-linux-x86_64.tar.gz https://github.com/dojoengine/dojo/releases/download/v${{ env.DOJO_VERSION }}/dojo_v${{ env.DOJO_VERSION }}_linux_amd64.tar.gz
tar -xzf dojo-linux-x86_64.tar.gz
sudo mv sozo /usr/local/bin/

- name: Update PATH
run: echo "$HOME/.asdf/shims" >> $GITHUB_PATH

- name: Install Scarb plugin
run: |
asdf plugin add scarb
asdf install scarb 2.9.2
asdf global scarb 2.9.2
- name: Setup Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}

- name: Build contracts
working-directory: backend/dojo_examples/combat_game
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
sozo build
if [[ `git status --porcelain` ]]; then
echo "The git repo is dirty"
echo "Make sure to run 'sozo build' after changing Scarb.toml"
exit 1
fi

- name: Run tests
working-directory: backend/dojo_examples/combat_game
working-directory: ${{ env.WORKING_DIRECTORY }}
run: sozo test

- name: Check formatting
working-directory: backend/dojo_examples/combat_game
run: scarb fmt
check:
runs-on: ubuntu-latest
name: Check format
steps:
- uses: actions/checkout@v4
- uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}
- name: Format
working-directory: ${{ env.WORKING_DIRECTORY }}
run: scarb fmt --check
shell: bash
2 changes: 1 addition & 1 deletion backend/dojo_examples/combat_game/.tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
dojo v1.6.0-alpha.1
dojo 1.6.1
scarb 2.10.1
12 changes: 6 additions & 6 deletions backend/dojo_examples/combat_game/Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = 1
[[package]]
name = "achievement"
version = "0.0.0"
source = "git+https://github.com/cartridge-gg/arcade?tag=v1.6.0-alpha.1#0378ed6d9d8188fa6532e66c8db8729a27eb8a5f"
source = "git+https://github.com/cartridge-gg/arcade?tag=v1.6.1#6438a74b589c3cac19b9782709e3845215ec67d6"
dependencies = [
"dojo",
]
Expand All @@ -20,21 +20,21 @@ dependencies = [

[[package]]
name = "dojo"
version = "1.6.0-alpha.0"
source = "git+https://github.com/dojoengine/dojo?tag=v1.6.0-alpha.1#054623bbf939a3bf90786355bd9b081a2b1b3c3a"
version = "1.6.1"
source = "git+https://github.com/dojoengine/dojo?tag=v1.6.1#a4f9445cf925e999d97038f596806ec307981a9b"
dependencies = [
"dojo_plugin",
]

[[package]]
name = "dojo_cairo_test"
version = "1.6.0-alpha.0"
source = "git+https://github.com/dojoengine/dojo?tag=v1.6.0-alpha.1#054623bbf939a3bf90786355bd9b081a2b1b3c3a"
version = "1.6.1"
source = "git+https://github.com/dojoengine/dojo?tag=v1.6.1#a4f9445cf925e999d97038f596806ec307981a9b"
dependencies = [
"dojo",
]

[[package]]
name = "dojo_plugin"
version = "2.10.1"
source = "git+https://github.com/dojoengine/dojo?tag=v1.6.0-alpha.1#054623bbf939a3bf90786355bd9b081a2b1b3c3a"
source = "git+https://github.com/dojoengine/dojo?tag=v1.6.1#a4f9445cf925e999d97038f596806ec307981a9b"
14 changes: 7 additions & 7 deletions backend/dojo_examples/combat_game/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
cairo-version = "2.10.1"
name = "combat_game"
version = "0.1.0"
edition = "2023_11"
edition = "2024_07"

[cairo]
sierra-replace-ids = true
Expand All @@ -11,18 +11,18 @@ sierra-replace-ids = true
sepolia = "sozo --profile sepolia clean && sozo --profile sepolia build && sozo --profile sepolia migrate --account-address $DEPLOYER_ACCOUNT_ADDRESS --private-key $DEPLOYER_PRIVATE_KEY --fee strk"

[dependencies]
dojo = { git = "https://github.com/dojoengine/dojo", tag = "v1.6.0-alpha.1" }
achievement = { git = "https://github.com/cartridge-gg/arcade", tag = "v1.6.0-alpha.1" }
dojo = { git = "https://github.com/dojoengine/dojo", tag = "v1.6.1" }
achievement = { git = "https://github.com/cartridge-gg/arcade", tag = "v1.6.1" }

[[target.starknet-contract]]
build-external-contracts = [
"dojo::world::world_contract::world",
"achievement::events::index::e_TrophyCreation",
"achievement::events::index::e_TrophyProgression",
"achievement::events::index::e_TrophyCreation",
"achievement::events::index::e_TrophyProgression",
]

[dev-dependencies]
cairo_test = "2.10.1"
dojo_cairo_test = { git = "https://github.com/dojoengine/dojo", tag = "v1.6.0-alpha.1" }
dojo_cairo_test = { git = "https://github.com/dojoengine/dojo", tag = "v1.6.1" }

[profile.sepolia]
[profile.sepolia]
2 changes: 1 addition & 1 deletion backend/dojo_examples/combat_game/src/systems/battle.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod battle_system {
use combat_game::achievements::achievement::{Achievement, AchievementTrait};

use starknet::{get_caller_address, get_block_timestamp, ContractAddress};
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
use core::num::traits::zero::Zero;

use achievement::components::achievable::AchievableComponent;
Expand Down Expand Up @@ -316,4 +317,3 @@ pub mod battle_system {
}
}
}

1 change: 1 addition & 0 deletions backend/dojo_examples/combat_game/src/systems/beast.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub trait IBeast<T> {
pub mod beast_system {
use super::{IBeast, BeastType, BeastStats};
use starknet::get_block_timestamp;
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
use combat_game::store::{StoreTrait};
use combat_game::models::beast_stats::BeastStatsActionTrait;

Expand Down
1 change: 1 addition & 0 deletions backend/dojo_examples/combat_game/src/systems/player.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod player_system {
use super::IPlayer;

use combat_game::models::player::{Player, PlayerAssert};
use starknet::storage::{StoragePointerWriteAccess};
use combat_game::store::{StoreTrait};

use starknet::{get_caller_address, get_block_timestamp};
Expand Down
84 changes: 51 additions & 33 deletions backend/dojo_examples/combat_game/src/tests/test_beast.cairo
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
#[cfg(test)]
mod beast_integration_tests {
use combat_game::{
models::{
beast::{BeastTrait},
beast_stats::{BeastStatsActionTrait},
},
types::{
beast_type::BeastType,
skill::SkillType,
status_condition::StatusCondition,
},
models::{beast::{BeastTrait}, beast_stats::{BeastStatsActionTrait}},
types::{beast_type::BeastType, skill::SkillType, status_condition::StatusCondition},
};
use starknet::{contract_address_const, ContractAddress};

Expand Down Expand Up @@ -46,15 +39,23 @@ mod beast_integration_tests {
#[available_gas(250000)]
fn test_beast_type_effectiveness_integration() {
// Test type effectiveness calculations (pure calculations)
let light_vs_shadow = BeastTrait::calculate_effectiveness(BeastType::Light, BeastType::Shadow);
let light_vs_magic = BeastTrait::calculate_effectiveness(BeastType::Light, BeastType::Magic);
let light_vs_light = BeastTrait::calculate_effectiveness(BeastType::Light, BeastType::Light);
let light_vs_shadow = BeastTrait::calculate_effectiveness(
BeastType::Light, BeastType::Shadow,
);
let light_vs_magic = BeastTrait::calculate_effectiveness(
BeastType::Light, BeastType::Magic,
);
let light_vs_light = BeastTrait::calculate_effectiveness(
BeastType::Light, BeastType::Light,
);

assert_eq!(light_vs_shadow, 150, "Light should be super effective against Shadow");
assert_eq!(light_vs_magic, 50, "Light should be not very effective against Magic");
assert_eq!(light_vs_light, 100, "Light should be normally effective against Light");

let magic_vs_light = BeastTrait::calculate_effectiveness(BeastType::Magic, BeastType::Light);
let magic_vs_light = BeastTrait::calculate_effectiveness(
BeastType::Magic, BeastType::Light,
);
assert_eq!(magic_vs_light, 150, "Magic should be super effective against Light");
}

Expand All @@ -65,12 +66,26 @@ mod beast_integration_tests {
let magic_beast = BeastTrait::new(PLAYER1(), 2, BeastType::Magic);

// Test skill type favoring
assert!(light_beast.is_favored_attack(SkillType::Beam), "Light beast should favor Beam attacks");
assert!(light_beast.is_favored_attack(SkillType::Slash), "Light beast should favor Slash attacks");
assert!(!light_beast.is_favored_attack(SkillType::Blast), "Light beast should NOT favor Blast attacks");
assert!(
light_beast.is_favored_attack(SkillType::Beam), "Light beast should favor Beam attacks",
);
assert!(
light_beast.is_favored_attack(SkillType::Slash),
"Light beast should favor Slash attacks",
);
assert!(
!light_beast.is_favored_attack(SkillType::Blast),
"Light beast should NOT favor Blast attacks",
);

assert!(magic_beast.is_favored_attack(SkillType::Blast), "Magic beast should favor Blast attacks");
assert!(!magic_beast.is_favored_attack(SkillType::Beam), "Magic beast should NOT favor Beam attacks");
assert!(
magic_beast.is_favored_attack(SkillType::Blast),
"Magic beast should favor Blast attacks",
);
assert!(
!magic_beast.is_favored_attack(SkillType::Beam),
"Magic beast should NOT favor Beam attacks",
);
}

#[test]
Expand All @@ -79,22 +94,16 @@ mod beast_integration_tests {
let light_beast = BeastTrait::new(PLAYER1(), 1, BeastType::Light);

// Test attack calculation with type effectiveness
let (damage, is_favored, is_effective) = light_beast.attack(
BeastType::Shadow,
SkillType::Beam,
1
);
let (damage, is_favored, is_effective) = light_beast
.attack(BeastType::Shadow, SkillType::Beam, 1);

assert!(damage > 0, "Attack should deal damage");
assert!(is_favored, "Beam should be favored by Light beast");
assert!(is_effective, "Light should be effective against Shadow");

// Test non-effective attack
let (damage2, is_favored2, is_effective2) = light_beast.attack(
BeastType::Magic,
SkillType::Beam,
1
);
let (damage2, is_favored2, is_effective2) = light_beast
.attack(BeastType::Magic, SkillType::Beam, 1);

assert!(damage2 > 0, "Attack should still deal damage");
assert!(is_favored2, "Beam should still be favored by Light beast");
Expand All @@ -115,7 +124,9 @@ mod beast_integration_tests {

// Validate initial state
assert_eq!(beast_stats.current_hp, beast_stats.max_hp, "Current HP should equal max HP");
assert_eq!(beast_stats.status_condition, StatusCondition::None, "Should start with no status");
assert_eq!(
beast_stats.status_condition, StatusCondition::None, "Should start with no status",
);
}

#[test]
Expand All @@ -141,13 +152,20 @@ mod beast_integration_tests {
let mut beast_stats = BeastStatsActionTrait::new_beast_stats(1, BeastType::Light, 1, 1000);

// Test initial state
assert_eq!(beast_stats.status_condition, StatusCondition::None, "Should start with no status");
assert_eq!(
beast_stats.status_condition, StatusCondition::None, "Should start with no status",
);
assert!(beast_stats.can_attack(), "Should be able to attack initially");

// Test applying status condition
beast_stats.apply_status(StatusCondition::Poisoned);
assert_eq!(beast_stats.status_condition, StatusCondition::Poisoned, "Should have poisoned status");
assert!(beast_stats.can_attack(), "Should still be able to attack when poisoned (only Stunned prevents attacking)");
assert_eq!(
beast_stats.status_condition, StatusCondition::Poisoned, "Should have poisoned status",
);
assert!(
beast_stats.can_attack(),
"Should still be able to attack when poisoned (only Stunned prevents attacking)",
);

// Test clearing status condition
beast_stats.clear_status();
Expand Down Expand Up @@ -175,7 +193,7 @@ mod beast_integration_tests {
// Each type should have different total stats due to modifiers
let light_total = light_stats.max_hp + light_stats.attack;
let magic_total = magic_stats.max_hp + magic_stats.attack;

// At least one comparison should be different due to type modifiers
assert!(light_total != magic_total, "Beast types should have different stat totals");
}
Expand Down
Loading
Loading