Source Code

;; title: clarityrpg
;; version: 1.0.0
;; summary: On-chain RPG character system on Stacks - create heroes, level up, equip gear, and battle.
;; description: ClarityRPG stores every hero, stat, level, item, and battle result permanently on-chain.
;;              No centralized server. Your hero is forever yours.

;; ============================================================
;; TRAITS
;; ============================================================

;; ============================================================
;; ERROR CODES
;; ============================================================

(define-constant err-hero-not-found           (err u500))
(define-constant err-not-hero-owner           (err u501))
(define-constant err-invalid-class            (err u502))
(define-constant err-invalid-slot             (err u503))
(define-constant err-item-not-found           (err u504))
(define-constant err-not-item-owner           (err u505))
(define-constant err-slot-occupied            (err u506))
(define-constant err-slot-empty               (err u507))
(define-constant err-on-cooldown              (err u508))
(define-constant err-self-battle              (err u509))
(define-constant err-insufficient-xp          (err u510))
(define-constant err-insufficient-stat-points (err u511))
(define-constant err-stat-point-mismatch      (err u512))
(define-constant err-hero-limit-reached       (err u513))
(define-constant err-guild-not-found          (err u514))
(define-constant err-already-in-guild         (err u515))
(define-constant err-item-class-mismatch      (err u517))
(define-constant err-unauthorized             (err u518))

;; ============================================================
;; CONSTANTS
;; ============================================================

;; Battle cooldown in blocks (~100 minutes on Stacks)
(define-constant battle-cooldown-blocks u10)

;; Maximum heroes per address
(define-constant max-heroes-per-address u1)

;; XP awarded per battle outcome
(define-constant xp-win-base   u50)
(define-constant xp-loss       u10)

;; ============================================================
;; DATA VARS
;; ============================================================

;; Global ID counters
(define-data-var hero-nonce   uint u0)
(define-data-var item-nonce   uint u0)
(define-data-var battle-nonce uint u0)
(define-data-var guild-nonce  uint u0)

;; Utility counter (for testing - increment / decrement)
(define-data-var test-counter int 0)

;; ============================================================
;; DATA MAPS
;; ============================================================

;; --- Hero core data ---
(define-map heroes uint {
  name:          (string-utf8 32),
  class:         (string-ascii 16),
  owner:         principal,
  level:         uint,
  xp:            uint,
  xp-to-next:    uint,
  created-at:    uint,
  battle-count:  uint,
  win-count:     uint,
  loss-count:    uint,
  status:        (string-ascii 8),    ;; "active" | "retired"
  last-battle:   uint,                ;; block height of last battle
  guild-id:      (optional uint)
})

;; --- Hero stats ---
(define-map hero-stats uint {
  strength:          uint,
  dexterity:         uint,
  intelligence:      uint,
  vitality:          uint,
  luck:              uint,
  unallocated-points: uint
})

;; --- Equipment slots per hero ---
(define-map hero-equipment uint {
  weapon:    (optional uint),
  armor:     (optional uint),
  helmet:    (optional uint),
  boots:     (optional uint),
  accessory: (optional uint)
})

;; --- Items ---
(define-map items uint {
  name:            (string-utf8 32),
  slot:            (string-ascii 16),
  stat-bonus-type: (string-ascii 16),  ;; "strength" | "dexterity" | "intelligence" | "vitality" | "luck"
  stat-bonus-value: uint,
  rarity:          (string-ascii 16),  ;; "common" | "uncommon" | "rare" | "epic" | "legendary"
  owner:           principal
})

;; --- Battle log ---
(define-map battles uint {
  hero1:       uint,
  hero2:       uint,
  winner:      uint,
  loser:       uint,
  xp-awarded:  uint,
  stacks-block-height: uint
})

;; --- Guilds ---
(define-map guilds uint {
  name:     (string-utf8 32),
  motto:    (string-utf8 128),
  leader:   principal,
  guild-xp: uint,
  member-count: uint
})

;; --- Tracks how many heroes an address has created ---
(define-map address-hero-count principal uint)

;; ============================================================
;; PRIVATE HELPERS
;; ============================================================

;; Return base stats for a given class
(define-private (get-class-base-stats (class (string-ascii 16)))
  (if (is-eq class "warrior")
    (some { strength: u8, dexterity: u5, intelligence: u3, vitality: u7, luck: u2 })
  (if (is-eq class "ranger")
    (some { strength: u4, dexterity: u9, intelligence: u4, vitality: u5, luck: u3 })
  (if (is-eq class "mage")
    (some { strength: u2, dexterity: u4, intelligence: u10, vitality: u4, luck: u5 })
  (if (is-eq class "rogue")
    (some { strength: u5, dexterity: u8, intelligence: u3, vitality: u4, luck: u5 })
  (if (is-eq class "paladin")
    (some { strength: u6, dexterity: u3, intelligence: u5, vitality: u9, luck: u2 })
  (if (is-eq class "druid")
    (some { strength: u3, dexterity: u5, intelligence: u8, vitality: u6, luck: u3 })
  none))))))
)

;; Calculate XP required to reach (level + 1) from level
(define-private (xp-for-next-level (level uint))
  (if (<= level u0) u100
  (if (is-eq level u1) u100
  (if (is-eq level u2) u250
  (if (is-eq level u3) u500
  (if (is-eq level u4) u900
  (if (<= level u9)  (+ u900  (* (- level u4) u500))
  (if (<= level u19) (+ u3400 (* (- level u9) u1000))
  (if (<= level u49) (+ u13400 (* (- level u19) u2500))
  (+ u88400 (* (- level u49) u5000))))))))))
)

;; Stat points awarded when leveling up to a new level
(define-private (stat-points-for-level (new-level uint))
  (if (<= new-level u4)  u3
  (if (<= new-level u19) u5
  (if (<= new-level u49) u6
  u7)))
)

;; Validate that a slot string is one of the five valid slots
(define-private (is-valid-slot (slot (string-ascii 16)))
  (or
    (is-eq slot "weapon")
    (is-eq slot "armor")
    (is-eq slot "helmet")
    (is-eq slot "boots")
    (is-eq slot "accessory")
  )
)

;; Get the item currently in a given slot (returns optional uint)
(define-private (get-slot-item (equip { weapon: (optional uint), armor: (optional uint), helmet: (optional uint), boots: (optional uint), accessory: (optional uint) }) (slot (string-ascii 16)))
  (if (is-eq slot "weapon")    (get weapon equip)
  (if (is-eq slot "armor")     (get armor equip)
  (if (is-eq slot "helmet")    (get helmet equip)
  (if (is-eq slot "boots")     (get boots equip)
  (if (is-eq slot "accessory") (get accessory equip)
  none)))))
)

;; Set a specific slot in equipment record
(define-private (set-slot-item
    (equip { weapon: (optional uint), armor: (optional uint), helmet: (optional uint), boots: (optional uint), accessory: (optional uint) })
    (slot (string-ascii 16))
    (item-id (optional uint)))
  (if (is-eq slot "weapon")
    (merge equip { weapon: item-id })
  (if (is-eq slot "armor")
    (merge equip { armor: item-id })
  (if (is-eq slot "helmet")
    (merge equip { helmet: item-id })
  (if (is-eq slot "boots")
    (merge equip { boots: item-id })
  (merge equip { accessory: item-id })))))
)

;; Derive the total stat bonus from equipped items for a given stat type
(define-private (equipment-bonus-for-stat (hero-id uint) (stat-name (string-ascii 16)))
  (let (
    (equip (default-to { weapon: none, armor: none, helmet: none, boots: none, accessory: none }
            (map-get? hero-equipment hero-id)))
    (weapon-bonus    (get-item-bonus-if-match (get weapon equip) stat-name))
    (armor-bonus     (get-item-bonus-if-match (get armor equip) stat-name))
    (helmet-bonus    (get-item-bonus-if-match (get helmet equip) stat-name))
    (boots-bonus     (get-item-bonus-if-match (get boots equip) stat-name))
    (accessory-bonus (get-item-bonus-if-match (get accessory equip) stat-name))
  )
  (+ weapon-bonus armor-bonus helmet-bonus boots-bonus accessory-bonus))
)

;; If item-id-opt exists and the item's stat-bonus-type matches, return its bonus value
(define-private (get-item-bonus-if-match (item-id-opt (optional uint)) (stat-name (string-ascii 16)))
  (match item-id-opt
    item-id
      (match (map-get? items item-id)
        item
          (if (is-eq (get stat-bonus-type item) stat-name)
            (get stat-bonus-value item)
            u0)
        u0)
    u0)
)

;; Pseudo-random number - NOT cryptographically secure, used for battle tie-break only.
;; Uses a multiplicative hash of seed and stacks-block-height. Sufficient for game coin flips.
(define-private (pseudo-random (seed uint) (bh uint) (range uint))
  (mod (+ (* seed u6364136223846793005) (* bh u1442695040888963407)) range)
)

;; Compute effective attack power for a hero: (STR * 3) + (DEX * 1) + weapon-bonus
(define-private (effective-attack (hero-id uint))
  (let (
    (stats (default-to { strength: u0, dexterity: u0, intelligence: u0, vitality: u0, luck: u0, unallocated-points: u0 }
            (map-get? hero-stats hero-id)))
  )
  (+ (* (get strength stats) u3) (get dexterity stats) (equipment-bonus-for-stat hero-id "strength")))
)

;; Compute effective defense for a hero: (VIT * 2) + armor + helmet bonus
(define-private (effective-defense (hero-id uint))
  (let (
    (stats (default-to { strength: u0, dexterity: u0, intelligence: u0, vitality: u0, luck: u0, unallocated-points: u0 }
            (map-get? hero-stats hero-id)))
  )
  (+ (* (get vitality stats) u2) (equipment-bonus-for-stat hero-id "vitality")))
)

;; Compute max HP: (VIT * 10) + (STR * 2) + level * 5
(define-private (effective-hp (hero-id uint))
  (let (
    (hero  (default-to { name: u"", class: "", owner: tx-sender, level: u1, xp: u0, xp-to-next: u100, created-at: u0, battle-count: u0, win-count: u0, loss-count: u0, status: "active", last-battle: u0, guild-id: none }
            (map-get? heroes hero-id)))
    (stats (default-to { strength: u0, dexterity: u0, intelligence: u0, vitality: u0, luck: u0, unallocated-points: u0 }
            (map-get? hero-stats hero-id)))
  )
  (+ (* (get vitality stats) u10) (* (get strength stats) u2) (* (get level hero) u5)))
)

;; ============================================================
;; PUBLIC FUNCTIONS
;; ============================================================

;; --- create-hero ---
;; Mint a new hero with a chosen class. One hero per address by default.
(define-public (create-hero
    (name  (string-utf8 32))
    (class (string-ascii 16)))
  (let (
    (caller      tx-sender)
    (hero-count  (default-to u0 (map-get? address-hero-count caller)))
    (base-stats  (unwrap! (get-class-base-stats class) err-invalid-class))
    (new-id      (+ (var-get hero-nonce) u1))
  )
  ;; Enforce one-hero-per-address limit
  (asserts! (< hero-count max-heroes-per-address) err-hero-limit-reached)

  ;; Store hero core record
  (map-set heroes new-id {
    name:         name,
    class:        class,
    owner:        caller,
    level:        u1,
    xp:           u0,
    xp-to-next:   (xp-for-next-level u1),
    created-at:   stacks-block-height,
    battle-count: u0,
    win-count:    u0,
    loss-count:   u0,
    status:       "active",
    last-battle:  u0,
    guild-id:     none
  })

  ;; Store hero stats with 3 unallocated starting points
  (map-set hero-stats new-id {
    strength:          (get strength base-stats),
    dexterity:         (get dexterity base-stats),
    intelligence:      (get intelligence base-stats),
    vitality:          (get vitality base-stats),
    luck:              (get luck base-stats),
    unallocated-points: u3
  })

  ;; Initialize empty equipment slots
  (map-set hero-equipment new-id {
    weapon:    none,
    armor:     none,
    helmet:    none,
    boots:     none,
    accessory: none
  })

  ;; Update counters
  (var-set hero-nonce new-id)
  (map-set address-hero-count caller (+ hero-count u1))

  (ok new-id))
)

;; --- allocate-stat-points ---
;; Spend unallocated stat points. Total allocated must equal unallocated balance.
(define-public (allocate-stat-points
    (hero-id     uint)
    (str-pts     uint)
    (dex-pts     uint)
    (int-pts     uint)
    (vit-pts     uint)
    (lck-pts     uint))
  (let (
    (hero  (unwrap! (map-get? heroes hero-id) err-hero-not-found))
    (stats (unwrap! (map-get? hero-stats hero-id) err-hero-not-found))
    (total-allocated (+ str-pts dex-pts int-pts vit-pts lck-pts))
    (available (get unallocated-points stats))
  )
  (asserts! (is-eq (get owner hero) tx-sender) err-not-hero-owner)
  (asserts! (<= total-allocated available) err-insufficient-stat-points)
  (asserts! (is-eq total-allocated available) err-stat-point-mismatch)

  (map-set hero-stats hero-id {
    strength:          (+ (get strength stats) str-pts),
    dexterity:         (+ (get dexterity stats) dex-pts),
    intelligence:      (+ (get intelligence stats) int-pts),
    vitality:          (+ (get vitality stats) vit-pts),
    luck:              (+ (get luck stats) lck-pts),
    unallocated-points: u0
  })
  (ok true))
)

;; --- level-up ---
;; Level up hero once XP threshold is reached.
(define-public (level-up (hero-id uint))
  (let (
    (hero  (unwrap! (map-get? heroes hero-id) err-hero-not-found))
    (stats (unwrap! (map-get? hero-stats hero-id) err-hero-not-found))
    (current-level (get level hero))
    (new-level     (+ current-level u1))
    (pts-awarded   (stat-points-for-level new-level))
  )
  (asserts! (is-eq (get owner hero) tx-sender) err-not-hero-owner)
  (asserts! (>= (get xp hero) (get xp-to-next hero)) err-insufficient-xp)

  (map-set heroes hero-id (merge hero {
    level:      new-level,
    xp-to-next: (xp-for-next-level new-level)
  }))
  (map-set hero-stats hero-id (merge stats {
    unallocated-points: (+ (get unallocated-points stats) pts-awarded)
  }))
  (ok new-level))
)

;; --- equip-item ---
;; Equip an owned item to a hero slot.
(define-public (equip-item
    (hero-id uint)
    (item-id uint)
    (slot    (string-ascii 16)))
  (let (
    (hero   (unwrap! (map-get? heroes hero-id)  err-hero-not-found))
    (item   (unwrap! (map-get? items  item-id)   err-item-not-found))
    (equip  (default-to { weapon: none, armor: none, helmet: none, boots: none, accessory: none }
             (map-get? hero-equipment hero-id)))
  )
  (asserts! (is-eq (get owner hero) tx-sender)  err-not-hero-owner)
  (asserts! (is-eq (get owner item) tx-sender)  err-not-item-owner)
  (asserts! (is-valid-slot slot)                 err-invalid-slot)
  (asserts! (is-eq (get slot item) slot)         err-item-class-mismatch)
  (asserts! (is-none (get-slot-item equip slot)) err-slot-occupied)

  (map-set hero-equipment hero-id (set-slot-item equip slot (some item-id)))
  (ok true))
)

;; --- unequip-item ---
;; Remove an item from a hero slot.
(define-public (unequip-item
    (hero-id uint)
    (slot    (string-ascii 16)))
  (let (
    (hero  (unwrap! (map-get? heroes hero-id) err-hero-not-found))
    (equip (default-to { weapon: none, armor: none, helmet: none, boots: none, accessory: none }
            (map-get? hero-equipment hero-id)))
  )
  (asserts! (is-eq (get owner hero) tx-sender) err-not-hero-owner)
  (asserts! (is-valid-slot slot)               err-invalid-slot)
  (asserts! (is-some (get-slot-item equip slot)) err-slot-empty)

  (map-set hero-equipment hero-id (set-slot-item equip slot none))
  (ok true))
)

;; --- battle ---
;; Challenge another hero to a PvP battle. Uses block hash for randomness.
(define-public (battle
    (attacker-id uint)
    (defender-id uint))
  (let (
    (attacker     (unwrap! (map-get? heroes attacker-id) err-hero-not-found))
    (defender     (unwrap! (map-get? heroes defender-id) err-hero-not-found))
    (battle-id    (+ (var-get battle-nonce) u1))

    ;; Stats
    (atk-attack  (effective-attack attacker-id))
    (atk-defense (effective-defense attacker-id))
    (atk-hp      (effective-hp attacker-id))

    (def-attack  (effective-attack defender-id))
    (def-defense (effective-defense defender-id))
    (def-hp      (effective-hp defender-id))

    ;; Simulate: net damage each side deals per round
    (atk-damage  (if (> atk-attack def-defense) (- atk-attack def-defense) u1))
    (def-damage  (if (> def-attack atk-defense) (- def-attack atk-defense) u1))

    ;; Rounds each can survive
    (atk-rounds-survive (/ atk-hp (if (> def-damage u0) def-damage u1)))
    (def-rounds-survive (/ def-hp (if (> atk-damage u0) atk-damage u1)))

    ;; Tie-break via pseudo-random roll seeded by hero IDs
    (coin-flip   (pseudo-random (+ attacker-id defender-id) stacks-block-height u2))

    ;; Determine winner / loser IDs
    (attacker-wins
      (if (> atk-rounds-survive def-rounds-survive)
        true
      (if (< atk-rounds-survive def-rounds-survive)
        false
        (is-eq coin-flip u0))))   ;; draw -> coin flip

    (winner-id (if attacker-wins attacker-id defender-id))
    (loser-id  (if attacker-wins defender-id attacker-id))

    (xp-for-winner (+ xp-win-base (* (get level (if attacker-wins defender attacker)) u5)))
  )
  ;; Guard rails
  (asserts! (is-eq (get owner attacker) tx-sender) err-not-hero-owner)
  (asserts! (not (is-eq attacker-id defender-id))  err-self-battle)
  (asserts!
    (>= stacks-block-height (+ (get last-battle attacker) battle-cooldown-blocks))
    err-on-cooldown)

  ;; Log battle
  (map-set battles battle-id {
    hero1:        attacker-id,
    hero2:        defender-id,
    winner:       winner-id,
    loser:        loser-id,
    xp-awarded:   xp-for-winner,
    stacks-block-height: stacks-block-height
  })
  (var-set battle-nonce battle-id)

  ;; Update winner record
  (let ((w-hero (unwrap-panic (map-get? heroes winner-id))))
    (map-set heroes winner-id (merge w-hero {
      xp:           (+ (get xp w-hero) xp-for-winner),
      battle-count: (+ (get battle-count w-hero) u1),
      win-count:    (+ (get win-count w-hero) u1),
      last-battle:  stacks-block-height
    }))
  )

  ;; Update loser record
  (let ((l-hero (unwrap-panic (map-get? heroes loser-id))))
    (map-set heroes loser-id (merge l-hero {
      xp:           (+ (get xp l-hero) xp-loss),
      battle-count: (+ (get battle-count l-hero) u1),
      loss-count:   (+ (get loss-count l-hero) u1),
      last-battle:  stacks-block-height
    }))
  )

  (ok { battle-id: battle-id, winner: winner-id, loser: loser-id, xp-awarded: xp-for-winner }))
)

;; --- create-guild ---
;; Create a new guild. Caller becomes the guild leader.
(define-public (create-guild
    (name  (string-utf8 32))
    (motto (string-utf8 128)))
  (let (
    (new-id (+ (var-get guild-nonce) u1))
  )
  (map-set guilds new-id {
    name:         name,
    motto:        motto,
    leader:       tx-sender,
    guild-xp:     u0,
    member-count: u1
  })
  (var-set guild-nonce new-id)
  (ok new-id))
)

;; --- join-guild ---
;; Join an existing guild with your hero.
(define-public (join-guild
    (hero-id  uint)
    (guild-id uint))
  (let (
    (hero  (unwrap! (map-get? heroes hero-id)   err-hero-not-found))
    (guild (unwrap! (map-get? guilds guild-id)  err-guild-not-found))
  )
  (asserts! (is-eq (get owner hero) tx-sender) err-not-hero-owner)
  (asserts! (is-none (get guild-id hero))      err-already-in-guild)

  (map-set heroes hero-id (merge hero { guild-id: (some guild-id) }))
  (map-set guilds guild-id (merge guild {
    member-count: (+ (get member-count guild) u1)
  }))
  (ok true))
)

;; --- mint-item ---
;; Admin/Contract owner function to mint a new item into existence.
;; (For a full game this would be dropped from PvE or crafted)
(define-public (mint-item
    (recipient       principal)
    (name            (string-utf8 32))
    (slot            (string-ascii 16))
    (stat-bonus-type (string-ascii 16))
    (stat-bonus-value uint)
    (rarity          (string-ascii 16)))
  (let (
    (new-id (+ (var-get item-nonce) u1))
  )
  ;; Simplified: anyone can mint for now, or add an admin check
  ;; (asserts! (is-eq tx-sender contract-owner) err-unauthorized)
  
  (asserts! (is-valid-slot slot) err-invalid-slot)
  
  (map-set items new-id {
    name: name,
    slot: slot,
    stat-bonus-type: stat-bonus-type,
    stat-bonus-value: stat-bonus-value,
    rarity: rarity,
    owner: recipient
  })
  
  (var-set item-nonce new-id)
  (ok new-id))
)

;; ============================================================
;; READ-ONLY FUNCTIONS
;; ============================================================

;; Get full hero sheet
(define-read-only (get-hero (hero-id uint))
  (map-get? heroes hero-id)
)

;; Get a hero's stats record
(define-read-only (get-hero-stats (hero-id uint))
  (map-get? hero-stats hero-id)
)

;; Get a hero's effective (base + equipment) stats
(define-read-only (get-effective-stats (hero-id uint))
  (match (map-get? hero-stats hero-id)
    stats
      (some {
        strength:     (+ (get strength stats)     (equipment-bonus-for-stat hero-id "strength")),
        dexterity:    (+ (get dexterity stats)    (equipment-bonus-for-stat hero-id "dexterity")),
        intelligence: (+ (get intelligence stats) (equipment-bonus-for-stat hero-id "intelligence")),
        vitality:     (+ (get vitality stats)     (equipment-bonus-for-stat hero-id "vitality")),
        luck:         (+ (get luck stats)         (equipment-bonus-for-stat hero-id "luck")),
        attack-power: (effective-attack hero-id),
        defense:      (effective-defense hero-id),
        max-hp:       (effective-hp hero-id)
      })
    none)
)

;; Get a hero's equipped items
(define-read-only (get-equipment (hero-id uint))
  (map-get? hero-equipment hero-id)
)

;; Get item details
(define-read-only (get-item (item-id uint))
  (map-get? items item-id)
)

;; Get battle log entry
(define-read-only (get-battle (battle-id uint))
  (map-get? battles battle-id)
)

;; Get hero win/loss record
(define-read-only (get-battle-record (hero-id uint))
  (match (map-get? heroes hero-id)
    hero (some {
      battle-count: (get battle-count hero),
      win-count:    (get win-count hero),
      loss-count:   (get loss-count hero)
    })
    none)
)

;; Get guild details
(define-read-only (get-guild (guild-id uint))
  (map-get? guilds guild-id)
)

;; Get leaderboard entry for a hero
(define-read-only (get-leaderboard-entry (hero-id uint))
  (match (map-get? heroes hero-id)
    hero (some {
      hero-name:  (get name hero),
      class:      (get class hero),
      level:      (get level hero),
      wins:       (get win-count hero),
      losses:     (get loss-count hero),
      total-xp:   (get xp hero),
      guild:      (get guild-id hero)
    })
    none)
)

;; Get total hero count
(define-read-only (get-hero-count)
  (var-get hero-nonce)
)

;; Check if a hero is on battle cooldown
(define-read-only (is-on-cooldown (hero-id uint))
  (match (map-get? heroes hero-id)
    hero (< stacks-block-height (+ (get last-battle hero) battle-cooldown-blocks))
    false)
)

;; Get a hero's unallocated stat points
(define-read-only (get-unallocated-points (hero-id uint))
  (match (map-get? hero-stats hero-id)
    stats (some (get unallocated-points stats))
    none)
)

;; ============================================================
;; UTILITY FUNCTIONS - Counter (for deployment testing only)
;; ============================================================
;; These functions are NOT part of the core game logic.
;; They expose a simple integer counter to verify that contract
;; calls work correctly after deployment.

;; Get current counter value
(define-read-only (get-counter)
  (var-get test-counter)
)

;; Increment counter by 1
(define-public (increment)
  (begin
    (var-set test-counter (+ (var-get test-counter) 1))
    (ok (var-get test-counter))
  )
)

;; Decrement counter by 1
(define-public (decrement)
  (begin
    (var-set test-counter (- (var-get test-counter) 1))
    (ok (var-get test-counter))
  )
)

;; Reset counter to 0 (convenience helper)
(define-public (reset-counter)
  (begin
    (var-set test-counter 0)
    (ok 0)
  )
)

Functions (35)

FunctionAccessArgs
get-class-base-statsprivateclass: (string-ascii 16
xp-for-next-levelprivatelevel: uint
stat-points-for-levelprivatenew-level: uint
is-valid-slotprivateslot: (string-ascii 16
equipment-bonus-for-statprivatehero-id: uint, stat-name: (string-ascii 16
get-item-bonus-if-matchprivateitem-id-opt: (optional uint
pseudo-randomprivateseed: uint, bh: uint, range: uint
effective-attackprivatehero-id: uint
effective-defenseprivatehero-id: uint
effective-hpprivatehero-id: uint
create-heropublicname: (string-utf8 32
allocate-stat-pointspublichero-id: uint, str-pts: uint, dex-pts: uint, int-pts: uint, vit-pts: uint, lck-pts: uint
level-uppublichero-id: uint
equip-itempublichero-id: uint, item-id: uint, slot: (string-ascii 16
unequip-itempublichero-id: uint, slot: (string-ascii 16
battlepublicattacker-id: uint, defender-id: uint
create-guildpublicname: (string-utf8 32
join-guildpublichero-id: uint, guild-id: uint
mint-itempublicrecipient: principal, name: (string-utf8 32
get-heroread-onlyhero-id: uint
get-hero-statsread-onlyhero-id: uint
get-effective-statsread-onlyhero-id: uint
get-equipmentread-onlyhero-id: uint
get-itemread-onlyitem-id: uint
get-battleread-onlybattle-id: uint
get-battle-recordread-onlyhero-id: uint
get-guildread-onlyguild-id: uint
get-leaderboard-entryread-onlyhero-id: uint
get-hero-countread-only
is-on-cooldownread-onlyhero-id: uint
get-unallocated-pointsread-onlyhero-id: uint
get-counterread-only
incrementpublic
decrementpublic
reset-counterpublic