Skip to content

Commit bb8ab3a

Browse files
committed
added combat persistence to ensure we dont end combat too soon
1 parent 764bc10 commit bb8ab3a

6 files changed

Lines changed: 68 additions & 50 deletions

File tree

src/battle-nads/Balances.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ abstract contract Balances is GasRelayWithScheduling, Instances {
170170
revert Errors.InvalidCaller(msg.sender);
171171
}
172172
if (_oldOwner != combatant.owner || combatant.owner != key.owner) {
173-
if (revertIfInvalid) {
173+
if (revertIfInvalid && !combatant.isDead()) {
174174
revert Errors.InvalidCaller(msg.sender);
175175
}
176176
_deactivateSessionKey(msg.sender);

src/battle-nads/Constants.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ contract Constants {
6969
uint8 internal constant NO_COMBAT_ZONE_SPACING = 5;
7070
uint256 internal constant RESERVED_BOSS_INDEX = 1;
7171

72-
uint256 internal constant DAMAGE_DILUTION_FACTOR = 620;
73-
uint256 internal constant ABILITY_DILUTION_FACTOR = 780;
74-
uint256 internal constant HEALING_DILUTION_FACTOR = 420;
72+
uint256 internal constant DAMAGE_DILUTION_FACTOR = 760;
73+
uint256 internal constant ABILITY_DILUTION_FACTOR = 880;
74+
uint256 internal constant HEALING_DILUTION_FACTOR = 460;
7575
uint256 internal constant DAMAGE_DILUTION_BASE = 1000;
7676

7777
// BALANCES

src/battle-nads/Handler.sol

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,6 @@ abstract contract Handler is Balances {
158158
monster = _loadExistingMonster(player, monsterIndex);
159159
}
160160

161-
// Flag for combat
162-
(monster, player) = _enterMutualCombatToTheDeath(monster, player);
163161
if (monster.isDead()) {
164162
player = _exitCombat(player);
165163
player.stats.nextTargetIndex = 0;
@@ -168,19 +166,23 @@ abstract contract Handler is Balances {
168166
return player;
169167
}
170168

169+
// Flag for combat
170+
(monster, player) = _enterMutualCombatToTheDeath(monster, player);
171+
171172
// Create tasks
172173
bool scheduledTask = false;
173174

174175
// Only create for monster if task doesn't already exist
175176
if (newMonster) {
176177
uint256 targetBlock = block.number + _cooldown(monster.stats) + COMBAT_COLD_START_DELAY_MONSTER;
177178
(monster, scheduledTask) = _createOrRescheduleCombatTask(monster, targetBlock);
178-
if (!scheduledTask) {
179-
monster.owner = _EMPTY_ADDRESS;
179+
if (scheduledTask) {
180+
monster.owner = player.owner;
180181
monster.tracker.updateOwner = true;
182+
} else {
181183
emit Events.TaskNotScheduledInHandler(3, monster.id, block.number, targetBlock);
182184
}
183-
} else {
185+
} else if (!monster.isDead()) {
184186
// If task is no longer active, start a new one
185187
(scheduledTask,) = _checkClearTasks(monster);
186188
if (!scheduledTask || !_isValidAddress(monster.owner)) {
@@ -316,19 +318,17 @@ abstract contract Handler is Balances {
316318
// Create tasks
317319
// Only create for attacker and defendant if tasks don't already exist
318320
(bool scheduledTask,) = _checkClearTasks(defender);
319-
if (defender.isMonster()) {
321+
if (defender.isMonster() && !defender.isDead()) {
320322
if (!scheduledTask || !_isValidAddress(defender.owner)) {
321-
if (!scheduledTask) {
322-
(defender, scheduledTask) =
323-
_createOrRescheduleCombatTask(defender, block.number + _cooldown(defender.stats));
324-
if (scheduledTask) {
325-
defender.owner = attacker.owner;
326-
defender.tracker.updateOwner = true;
327-
} else {
328-
emit Events.TaskNotScheduledInHandler(
329-
1, defender.id, block.number, block.number + _cooldown(defender.stats)
330-
);
331-
}
323+
(defender, scheduledTask) =
324+
_createOrRescheduleCombatTask(defender, block.number + _cooldown(defender.stats));
325+
if (scheduledTask) {
326+
defender.owner = attacker.owner;
327+
defender.tracker.updateOwner = true;
328+
} else {
329+
emit Events.TaskNotScheduledInHandler(
330+
1, defender.id, block.number, block.number + _cooldown(defender.stats)
331+
);
332332
}
333333
}
334334
}
@@ -533,13 +533,11 @@ abstract contract Handler is Balances {
533533
// If it's a monster, update defender's owner to n
534534
// Only do this if there was a funding issue with prev task
535535

536-
if (defender.isMonster() && !attacker.isMonster()) {
537-
if (defender.owner != attacker.owner && _isValidAddress(defender.owner)) {
538-
(bool hasActiveCombatTask,) = _checkClearTasks(defender);
539-
if (!hasActiveCombatTask) {
540-
defender.owner = _EMPTY_ADDRESS;
541-
defender.tracker.updateOwner = true;
542-
}
536+
if (!defender.isDead() && defender.isMonster() && !attacker.isMonster() && _isValidAddress(defender.owner)) {
537+
(bool hasActiveCombatTask,) = _checkClearTasks(defender);
538+
if (!hasActiveCombatTask && !defender.isDead()) {
539+
defender.owner = _EMPTY_ADDRESS;
540+
defender.tracker.updateOwner = true;
543541
}
544542
}
545543

@@ -554,13 +552,12 @@ abstract contract Handler is Balances {
554552
// This prevents the bug where the wrong player would be stored later
555553
if (
556554
_isValidID(newDefender.id) && newDefender.id != defender.id && newDefender.id != attacker.id
557-
&& !defender.isDead()
555+
&& !newDefender.isDead()
558556
) {
559-
defender = newDefender;
560-
} else {
561-
// Set defender to empty so we don't store it again at line 526
562-
defender.id = bytes32(0);
557+
_storeBattleNad(newDefender);
563558
}
559+
} else {
560+
_storeBattleNad(defender);
564561
}
565562

566563
// Handle health regen and storage, then return the necessary data
@@ -584,12 +581,6 @@ abstract contract Handler is Balances {
584581
// Store area
585582
_storeArea(area, attacker.stats.depth, attacker.stats.x, attacker.stats.y);
586583

587-
// Store defender (if valid)
588-
// Dead defenders were already stored in _processDeathDuringKillerTurn
589-
if (_isValidID(defender.id)) {
590-
_storeBattleNad(defender);
591-
}
592-
593584
return (attacker, reschedule, nextExecutionBlock);
594585
}
595586

@@ -743,7 +734,7 @@ abstract contract Handler is Balances {
743734
if (!attackerInCombat || !defenderInCombat) {
744735
(attacker, defender) = _enterMutualCombatToTheDeath(attacker, defender);
745736
}
746-
if (defender.isMonster() && !attacker.isMonster()) {
737+
if (!defender.isDead() && defender.isMonster() && !attacker.isMonster()) {
747738
if (!_isTask()) {
748739
(bool scheduledTask,) = _checkClearTasks(defender);
749740
if (!scheduledTask || !_isValidAddress(defender.owner)) {

src/battle-nads/MonsterFactory.sol

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,13 @@ abstract contract MonsterFactory is CharacterFactory {
3737

3838
// Most recent player to enter combat with the monster is its 'owner'
3939
address owner = owners[monster.id];
40+
monster.owner = owner;
41+
/*
4042
monster.owner = player.owner;
4143
if (monster.owner != owner) {
4244
monster.tracker.updateOwner = true;
4345
}
46+
*/
4447

4548
// Return monster
4649
return monster;
@@ -88,8 +91,11 @@ abstract contract MonsterFactory is CharacterFactory {
8891
monster.tracker.updateStats = true;
8992

9093
// Update the owner
91-
monster.owner = player.owner;
92-
owners[monster.id] = player.owner;
94+
// monster.owner = player.owner;
95+
// owners[monster.id] = player.owner;
96+
monster.owner = _EMPTY_ADDRESS;
97+
//monster.tracker.updateOwner = true;
98+
//owners[monster.id] = _EMPTY_ADDRESS;
9399
characterTasks[monster.id] = _NULL_ID;
94100
killMap[monster.id] = _UNKILLED;
95101

src/battle-nads/TaskHandler.sol

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,21 @@ contract TaskHandler is Handler, GeneralReschedulingTask {
6767
uint256 targetBlock;
6868
(attacker, reschedule, targetBlock) = _handleCombatTurn(attacker);
6969

70-
reschedule = _validatePersistOwnerDuringTask(attacker, false);
70+
// If attacker exited combat then the keys are invalidated at that point
71+
if (attacker.isInCombat()) {
72+
reschedule = _validatePersistOwnerDuringTask(attacker, false);
73+
}
7174

7275
// Set reschedule lock for reimbursement call afterwards
7376
if (reschedule) {
7477
(attacker, reschedule) = _createOrRescheduleCombatTask(attacker, targetBlock);
7578
if (!reschedule) {
7679
emit Events.TaskNotScheduledInTaskHandler(20, attacker.id, block.number, targetBlock);
80+
if (attacker.isMonster()) {
81+
attacker.owner = _EMPTY_ADDRESS;
82+
attacker.tracker.updateOwner = true;
83+
_clearActiveTask(characterID);
84+
}
7785
}
7886
} else {
7987
_clearActiveTask(characterID);
@@ -208,7 +216,11 @@ contract TaskHandler is Handler, GeneralReschedulingTask {
208216
returns (BattleNad memory, bool)
209217
{
210218
if (!_isValidAddress(combatant.owner)) {
211-
revert Errors.CharacterNotOwned(combatant.id);
219+
if (_isTask()) {
220+
return (combatant, false);
221+
} else if (!combatant.isMonster()) {
222+
revert Errors.CharacterNotOwned(combatant.id);
223+
}
212224
}
213225

214226
// Calculate the maximum payment
@@ -347,15 +359,22 @@ contract TaskHandler is Handler, GeneralReschedulingTask {
347359
return combatant;
348360
}
349361

362+
if (!_isValidAddress(combatant.owner)) {
363+
_clearActiveTask(combatant.id);
364+
if (!combatant.isMonster()) {
365+
AbilityTracker memory activeAbility = _loadAbility(combatant.id);
366+
if (_isValidAddress(activeAbility.taskAddress)) {
367+
combatant = _checkClearAbility(combatant);
368+
}
369+
}
370+
return combatant;
371+
}
372+
350373
bytes32 taskID = _loadActiveTaskID(combatant.id);
351374
address activeTask = address(uint160(uint256(taskID)));
352375

353376
combatant.activeTask.taskAddress = activeTask;
354377

355-
if (!_isValidAddress(combatant.owner)) {
356-
combatant.owner = _loadOwner(combatant.id);
357-
}
358-
359378
if (_isValidAddress(activeTask)) {
360379
_clearActiveTask(combatant.id);
361380
combatant.activeTask.taskAddress = _EMPTY_ADDRESS;
@@ -389,6 +408,8 @@ contract TaskHandler is Handler, GeneralReschedulingTask {
389408
return (hasActiveCombatTask, activeTask);
390409
}
391410

411+
if (!!_isValidAddress(combatant.owner)) { }
412+
392413
bytes32 taskID = _loadActiveTaskID(combatant.id);
393414
activeTask = address(uint160(uint256(taskID)));
394415

test/battle-nads/BattleNads.t.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ contract BattleNadsTest is BattleNadsBaseTest {
7979
_rollForward(1);
8080

8181
uint256 i = 0;
82-
while (i < 100) {
82+
while (i < 8) {
8383
uint256 remainder = i % 4;
8484

8585
if (remainder == 0) {
@@ -133,7 +133,7 @@ contract BattleNadsTest is BattleNadsBaseTest {
133133
vm.prank(userSessionKey3);
134134
battleNads.attack(character3, uint256(monster.stats.index));
135135

136-
while (i < 100) {
136+
while (i < 18) {
137137

138138
player = _battleNad(3);
139139
monster = _battleNad(opponentID);

0 commit comments

Comments
 (0)