Smart Contract

MMORPG7

A.b576a3926d239682.MMORPG7

Valid From

130,655,502

Deployed

1w ago
Feb 21, 2026, 02:43:05 PM UTC

Dependents

6 imports
1import FlowToken from 0x1654653399040a61
2import FungibleToken from 0xf233dcee88fe0abe
3
4access(all) contract MMORPG7 {
5
6  access(self) let FlowTokenVault: Capability<&{FungibleToken.Receiver}>
7  access(self) let info: Info
8  access(self) var totalGamePlayers: UInt // Player ID
9
10  access(all) entitlement ThiefAbility1
11  access(all) entitlement ThiefAbility2
12  access(all) entitlement WarriorAbility1
13  access(all) entitlement WarriorAbility2
14
15  access(all) event ESportsGamerInitiated(battleId: Int, player1Address: Address, player2Address: Address)
16
17  /* 構造体 */
18  access(all) struct Info {
19
20    /* fields */
21    access(contract) var battleQueue: [GameBattle]
22    access(contract) var basicAbility: {String: String}     // リソース別の基本アビリティ
23    access(contract) var basicAttackInfo: {String: [UInt8]} // システム側から通常攻撃トランザクションを行うための情報
24
25    /* setter  <Return: Battle ID> */
26    access(contract) fun newGameBattle(
27      player1Address: Address,
28      player2Address: Address,
29      lifeOfPlayer1: UInt8,
30      lifeOfPlayer2: UInt8,
31      reward: UFix64
32    ): Int {
33      var battle = GameBattle(
34        player1Address: player1Address,
35        player2Address: player2Address,
36        lifeOfPlayer1: lifeOfPlayer1,
37        lifeOfPlayer2: lifeOfPlayer2,
38        reward: reward
39      )
40      self.battleQueue.append(battle)
41      return self.battleQueue.length - 1
42    }
43
44    /* setter */
45    access(contract) fun updateGameBattle(
46      battleId: Int,
47      target: String?,
48      lifeChange: UInt8,
49      isDamage: Bool
50    ) {
51      if (target != nil) {
52        self.battleQueue[battleId]!.setPlayerLife(target: target!, lifeChange: lifeChange, isDamage: isDamage)
53      } else {
54        self.battleQueue[battleId]!.setEnemyLife(damage: lifeChange) // 敵への攻撃は全体攻撃しかない..
55      }
56    }
57
58    /* init */
59    init() {
60      self.battleQueue = []
61      self.basicAbility = {
62       "Warrior-BasicAttack": "Rage Attack",
63       "Warrior-ShareableAbility": "LargeRecoveryShield",
64       "Thief-BasicAttack": "Whip Attack",
65       "Thief-ShareableAbility": "PoisonMaking",
66       "Enemy-BasicAttack": "A Crushing Blow"
67      }
68      self.basicAttackInfo = {
69        "Warrior": [1, 3], // [GroupAttack?, damageVolume] (Rage Attack)
70        "Thief": [1, 1], // [GroupAttack?, damageVolume] (Whip Attack
71        "Enemy": [0, 4] // [GroupAttack?, damageVolume] (A Crushing Blow)
72      }
73    }
74  }
75
76  /* Info内の構造体 */
77  access(all) struct GameBattle {
78
79    /* fields */
80    access(all) let execTime: UFix64
81    access(all) let player1Address: Address
82    access(all) let player2Address: Address
83    access(all) var lifeOfPlayer1: UInt8
84    access(all) var lifeOfPlayer2: UInt8
85    access(all) var enemy1Life: UInt8
86    access(all) var enemy2Life: UInt8
87    access(all) let reward: UFix64
88
89    /* setter(ダメージまたは回復) */
90    access(contract) fun setPlayerLife(target: String, lifeChange: UInt8, isDamage: Bool) {
91      if (target == "TeamPlayer1") {
92        if (isDamage) {
93          self.lifeOfPlayer1 = self.lifeOfPlayer1 < lifeChange ? 0 : self.lifeOfPlayer1 - lifeChange
94        } else {
95          self.lifeOfPlayer1 = self.lifeOfPlayer1 + lifeChange
96        }
97      } else if (target == "TeamPlayer2") {
98        if (isDamage) {
99          self.lifeOfPlayer2 = self.lifeOfPlayer2 < lifeChange ? 0 : self.lifeOfPlayer2 - lifeChange
100        } else {
101          self.lifeOfPlayer2 = self.lifeOfPlayer2 + lifeChange
102        }
103      }
104    }
105    /* setter(敵への全体攻撃) */
106    access(contract) fun setEnemyLife(damage: UInt8) {
107      self.enemy1Life = self.enemy1Life < damage ? 0 : self.enemy1Life - damage
108      self.enemy2Life = self.enemy2Life < damage ? 0 : self.enemy2Life - damage
109    }
110
111    /* init */
112    init(player1Address: Address, player2Address: Address, lifeOfPlayer1: UInt8, lifeOfPlayer2: UInt8, reward: UFix64) {
113      let modulo: UInt8 = 3
114      self.execTime = getCurrentBlock().timestamp
115      self.player1Address = player1Address
116      self.player2Address = player2Address
117      self.lifeOfPlayer1 = lifeOfPlayer1
118      self.lifeOfPlayer2 = lifeOfPlayer2
119
120      // 両方戦士タイプなら悪魔を登場させる
121      if (lifeOfPlayer1 > 5 && lifeOfPlayer2 > 5) {
122        self.enemy2Life = 9 + revertibleRandom(modulo: modulo) // 9 ~ 11の整数
123      } else {
124        self.enemy2Life = 5 + revertibleRandom(modulo: modulo) // 5 ~ 7の整数
125      }
126      self.enemy1Life = 8 + revertibleRandom(modulo: modulo) // 8 ~ 10の整数
127      self.reward = reward
128    }
129  }
130
131  // GET
132  access(all) fun getInfo(): Info {
133    return self.info
134  }
135
136  // PUT
137  access(all) fun newGameBattle(
138    payment: @FlowToken.Vault,
139    player1Address: Address,
140    player2Address: Address,
141    lifeOfPlayer1: UInt8,
142    lifeOfPlayer2: UInt8
143  ) {
144    let battleId = self.info.newGameBattle(
145      player1Address: player1Address,
146      player2Address: player2Address,
147      lifeOfPlayer1: lifeOfPlayer1,
148      lifeOfPlayer2: lifeOfPlayer2,
149      reward: payment.balance * 2.0)
150
151    emit ESportsGamerInitiated(battleId: battleId, player1Address: player1Address, player2Address: player2Address)
152
153    // Game Feeをシステムアカウントに保存
154    self.FlowTokenVault.borrow()!.deposit(from: <- payment)
155  }
156
157  access(all) resource Thief {
158    access(all) let id: UInt
159    access(all) let maxLife: UInt8
160
161    access(ThiefAbility1) fun PoisonMaking(battleId: Int) {
162      MMORPG7.info.updateGameBattle(battleId: battleId, target: nil, lifeChange: 6, isDamage: true)
163    }
164    access(ThiefAbility2) fun WhipAttack(battleId: Int) {
165      MMORPG7.info.updateGameBattle(battleId: battleId, target: nil, lifeChange: 1, isDamage: true)
166    }
167    
168    init() {
169      MMORPG7.totalGamePlayers = MMORPG7.totalGamePlayers + 1
170      self.id = MMORPG7.totalGamePlayers
171      self.maxLife = 5
172    }
173  }
174
175  access(all) resource Warrior {
176    access(all) let id: UInt
177    access(all) let maxLife: UInt8
178
179    access(WarriorAbility1) fun LargeRecoveryShield(battleId: Int, target: String) {
180      MMORPG7.info.updateGameBattle(battleId: battleId, target: target, lifeChange: 4, isDamage: false)
181    }
182    access(WarriorAbility2) fun RageAttack(battleId: Int) {
183      MMORPG7.info.updateGameBattle(battleId: battleId, target: nil, lifeChange: 3, isDamage: true)
184    }
185
186    init() {
187      MMORPG7.totalGamePlayers = MMORPG7.totalGamePlayers + 1
188      self.id = MMORPG7.totalGamePlayers
189      self.maxLife = 8
190    }
191  }
192
193  access(all) resource Admin {
194    access(all) fun payRewards(recipient1: Address, recipient2: Address, reward: UFix64) {
195      // Pay the reward.
196      let reward1 <- MMORPG7.account
197        .storage
198        .borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>(from: /storage/flowTokenVault)!
199        .withdraw(amount: reward) as! @FlowToken.Vault
200
201      getAccount(recipient1)
202        .capabilities
203        .get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
204        .borrow()!.deposit(from: <- reward1)
205
206      let reward2 <- MMORPG7.account
207        .storage
208        .borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Provider}>(from: /storage/flowTokenVault)!
209        .withdraw(amount: reward) as! @FlowToken.Vault
210
211      getAccount(recipient2)
212        .capabilities
213        .get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
214        .borrow()!.deposit(from: <- reward2)
215    }
216
217    access(all) fun basicAttack(battleId: Int, target: String?, resourceName: String) {
218      MMORPG7.info.updateGameBattle(battleId: battleId, target: target, lifeChange: MMORPG7.info.basicAttackInfo[resourceName]![1], isDamage: true)
219    }
220  }
221
222  access(all) fun createWarriorResource(payment: @FlowToken.Vault): @MMORPG7.Warrior {
223    pre {
224      payment.balance == 5.0: "Cost of resource must be 5.0FLOW coin."
225    }
226    let _resource <- create Warrior() // resourceは予約語なので_をつけてます
227
228    MMORPG7.FlowTokenVault.borrow()!.deposit(from: <- payment) // 代金徴収
229    return <- _resource
230  }
231
232  access(all) fun createThiefResource(payment: @FlowToken.Vault): @MMORPG7.Thief {
233    pre {
234      payment.balance == 5.0: "Cost of resource must be 5.0FLOW coin."
235    }
236    let _resource <- create Thief()
237
238    MMORPG7.FlowTokenVault.borrow()!.deposit(from: <- payment) // 代金徴収
239    return <- _resource
240  }
241
242  init() {
243    self.info = Info()
244    self.FlowTokenVault = self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
245    self.totalGamePlayers = 0
246    self.account.storage.save( <- create Admin(), to: /storage/MMORPG7Admin)
247  }
248}
249