// 0aa33bf5e6771002fb8313d9cc99dfaf5428190e9bccbb3ef04b0fb984e42730_o1 class Battle extends FyxJig { init(validator, rules, players, id, timestamp) { this.id = this.random = id; this.timestamp = timestamp; this.rules = rules; this.battlePlayers = players.map((player) => this.joinBattle(player)); this.battlegroundTier = rules.****; this.dice = new Dice(id); this.state = BattleUtils.buildBattleState(this.battlePlayers, this.dice); this.turnCount = 0; this.satoshis = rules.reward || 546; this.stateHash = Sha256.hashToHex(JSON.stringify(this.state)); this.status = Constants.Status.Open; this.stateHistory = []; this.actor = players[this.state.playerToAct].userId; this.stage = "created"; this.owner = this.validator = validator; const tempPlayerToAct = this.state.playerToAct; for (let i = 0; i < 2; i++) { this.state.playerToAct = i; let skills = this.battlePlayers[i].fighter.skills; if (skills.includes(Constants.SkillType.Shadowy)) { var playerName = BattleUtils.getPrettifiedPlayerName(this, this.state); let log = `${playerName} uses ${BattleUtils.parseSkillName(Constants.SkillType.Hide)}\n`; this.state.actionLogs.push( BattleUtils.abilityCheckAndApplyStatusEffect( this, this.state, this.dice, Constants.SkillType.Hide, Constants.Ability.Dexterity, Constants.Ability.Intelligence, Constants.StatusEffect.Hidden, 99, true, log ) ); this.state.fighterStates = BattleUtils.computeFighterStates( this, this.state ); } } this.state.playerToAct = tempPlayerToAct; } joinBattle(player) { const { userId, pubkey, owner, items, fighter, skills, tags } = player; if (this.rules.fee) { if (fighter.satoshis < this.rules.fee) throw new Error("Insufficient Fighter Satoshis"); fighter.setSatoshis(fighter.satoshis - this.rules.fee); } else { fighter.auth(); } items.forEach((item) => item && item.auth()); const [mainhand, offhand, armor, hat, disguise] = items.map( (i) => i && i.item && FyxClass.deepClone(i.item) ); return { userId, pubkey, owner, fighter, mainhand, offhand, armor, hat, disguise, skills, tags: tags || [], }; } begin(timeout) { if (this.stage !== "created") throw new Error("Invalid Stage"); this.timeout = timeout; delete this.stage; } resolve(random, timestamp, timeout, actionIndex, sig) { console.log("Resolve", this.location); if (this.status !== Constants.Status.Open) throw new Error("Invalid Status"); if (!BattleUtils.validateRandom(random, this.random)) throw new Error("Invalid Random"); this.sig = sig; this.random = random; this.stateHistory[this.turnCount] = this.getState(); const state = FyxClass.deepClone(this.state); state.actionLogs = []; this.dice = new Dice(random); if (timestamp < this.timeout) { if (actionIndex === -1 || actionIndex === undefined) { this.state = BattleUtils.skipTurn(this, state, this.dice, timestamp); } else { const attacker = this.battlePlayers[this.state.playerToAct]; const skill = attacker.skills[actionIndex]; if (!skill) throw new Error( `${attacker.fighter.displayName} used an invalid Skill ID: ${actionIndex}` ); this.state = skill.run(this, state, this.dice, timestamp); } } else { this.state = BattleUtils.skipTurn(this, state, this.dice, timestamp); } this.status = this.state.status; this.timestamp = timestamp; this.timeout = timeout; this._endTurn(); } simulate(state, random, actionIndex) { const attacker = this.battlePlayers[state.playerToAct]; const skill = attacker.skills[actionIndex]; state.actionLogs = []; if (!skill) throw new Error( `${attacker.fighter.displayName} used an invalid Skill ID: ${actionIndex}` ); let { turnCount } = state; state = skill.run(this, state, new Dice(random)); return { battleId: this.id, ...state, battleStatus: state.status, random, turnCount: turnCount + 1, actor: this.battlePlayers[state.playerToAct].userId, stateHash: Sha256.hashToHex(JSON.stringify(state)), location: this.origin, origin: this.origin, }; } forfeit(message, timestamp) { if (this.status !== Constants.Status.Open) throw new Error("Invalid Status"); this.stateHistory[this.turnCount] = this.getState(); const playerIndex = this.battlePlayers.findIndex( (p) => p.userId === message.from ); const player = this.battlePlayers[playerIndex]; const victorIndex = this.battlePlayers.findIndex( (p) => p.userId !== message.from ); const victor = this.battlePlayers[victorIndex]; const state = FyxClass.deepClone(this.state); state.victor = { pubkey: victor.pubkey, owner: victor.owner, fighter: victor.fighter, userId: victor.userId, }; state.actionLogs = [ { playerIndex: playerIndex, actionLogMessage: `${player.fighter.metadata.name.toUpperCase()} Forfeited`, }, ]; state.playerToAct = victorIndex; state.status = Constants.Status.Forfeit; this.state = state; this.status = this.state.status; this.timestamp = timestamp; this._endTurn(); } // _endTurn() { // this.turnCount++; // this.stateHash = Sha256.hashToHex(JSON.stringify(this.state)); // this.actor = this.battlePlayers[this.state.playerToAct].userId; // if (this.status !== Constants.Status.Open) { // this.victor = {...this.battlePlayers[this.state.playerToAct]}; // this.stateHistory[this.turnCount] = this.getState(); // const victor = this.victor; // const loser = this.battlePlayers.find(p => p.userId !== victor.userId); // this.xp = Battle.LevelXPReward[loser.fighter.level]; // if (!victor.tags.includes('bot')) { // const items = issueRewards(this.dice, this.battlegroundTier); // this.rewards = items.map(i => new FyxItem(victor.fighter.owner, i.metadata, i.item, i.satoshis)); // } // this.battlePlayers.forEach(player => new BattleToken(player.fighter.owner)); // this.owner = victor.fighter.owner; // this.status = Constants.Status.Finalized; // } // } _endTurn() { if (this.status !== Constants.Status.Open) { this.victor = { ...this.battlePlayers[this.state.playerToAct] }; } this.turnCount++; this.stateHash = Sha256.hashToHex(JSON.stringify(this.state)); this.actor = this.battlePlayers[this.state.playerToAct].userId; } finalize() { this.stateHistory[this.turnCount] = this.getState(); if ( ![Constants.Status.Complete, Constants.Status.Forfeit].includes( this.status ) ) throw new Error("Invalid Status"); const victor = this.victor; const loser = this.battlePlayers.find((p) => p.userId !== victor.userId); this.xp = Battle.LevelXPReward[loser.fighter.level]; if (!victor.tags.includes("bot")) { const items = issueRewards(this.dice, this.battlegroundTier); this.rewards = items.map( (i) => new FyxItem(victor.fighter.owner, i.metadata, i.item, i.satoshis) ); } this.battlePlayers.forEach( (player) => new BattleToken(player.fighter.owner) ); this.owner = victor.fighter.owner; this.status = Constants.Status.Finalized; } getState() { const state = { ...this.state, location: this.origin, origin: this.origin, actor: this.actor, battleId: this.id, random: this.random, stateHash: this.stateHash, timestamp: this.timestamp, turnCount: this.turnCount, timeout: this.timeout, battleStatus: this.status, }; return state; } } // {"LevelXPReward":[0,100,200,300,600,1200,2400,0,0,556,713,913,1170,1498,1919,2458,3148,4032,5164,6614,8472],"MaxRounds":100