Utilizing LZN In Apocalypse
The Luzion Protocol (LZN) token will be utilized in our Apocalypse ecosystem game to ensure its perpetual sustainability through player buying and selling. During PVP and Battle Royale gameplay, players can use LZN by staking it as collateral. Each staking transaction will incur a transfer tax, but there will be no tax on winning withdrawals.
Players who create a PVP room can stake any desired amount of LZN, while players joining a PVP battle must match the stake of the room creator. In Battle Royale, the system sets a required amount of LZN that must be staked.
Utilization of LZN in Apocalypse PVP and Battle Royale generates a significant volume of transactions, complete with taxation, which ensures constant automated token burning and auto liquidity injection. The ecosystem and marketing wallets will also be replenished for future development and use cases.
As LZN is constantly rebasing, every LZN that enters the PVP or Battle Royale smart contracts will slightly increase in value after each epoch. To counteract this, any additional tokens will be transferred to the burn address, effectively stabilizing the inflation rate and increasing the black hole supply over time.
The player versus player (PVP) function is designed to facilitate combat between two players using their respective non-fungible tokens (NFTs) as avatars. The creator of the PVP room, which is located within the PVP smart contract, initiates a PVP transaction by inviting a second player to join the room. Once the second player accepts the invitation, the PVP is automatically triggered and both players receive their results, including any stake rewards, upon completion of the battle.
In addition to stake rewards, players also have the opportunity to receive an airdrop of NFT minerals upon losing a PVP battle. These airdrops, which are distributed on a chance basis, serve to compensate players for their losses and provide an additional incentive for participating in PVP. As a result, players are not solely reliant on stake rewards as a means of gain, but also have the potential to acquire valuable NFT minerals through the airdrop system.
- 1.A player creates a PVP room within the PVP smart contract by selecting their NFT character.
- 2.Another player is invited to join the PVP room and chooses their NFT character to participate in combat.
- 3.The PVP transaction is automatically triggered upon the second player accepting the invitation to join the room.
- 4.The PVP battle takes place, and both players receive their results, including any stake rewards, upon completion.
- 5.If a player loses the PVP battle, they have a chance to receive an airdrop of NFT minerals as compensation.
- 6.The process can be repeated as desired, with players able to create or join additional PVP rooms and engage in further combat.
- 7.Players have the ability to review their past win/loss data at any time at history tab.
1
/* PvP logic */
2
3
/**
4
* @dev Create a new PvP listing.
5
*/
6
function createPvPRoom(uint256 _charID, uint256 _price) external payable whenNotPaused nonReentrant {
7
8
uint256 _amount = checkPrice(minStake, rewardToken);
9
10
if (allowMultipleRoom == false) {
11
require(getCurrentPvPIDForCharacter[_charID] == 0 , "There's an active PvP room for this character!");
12
}
13
require(_price >= _amount, "Price must be greater than the minimum amount allowed!");
14
require(apocCharacter.ownerOf(_charID) == _msgSender(), "You are not the owner of this character!");
15
16
_pvpID.increment();
17
uint256 _getPvPID = _pvpID.current();
18
19
idToPvPInfo[_getPvPID] = pvpInfo(_getPvPID, _price, _charID, 0, false, payable(_msgSender()), payable(ZERO));
20
getCurrentPvPIDForCharacter[_charID] = _getPvPID;
21
22
rewardToken.transferFrom(_msgSender(), address(this), _price);
23
totalStake = totalStake.add(_price);
24
25
emit CreatePvPRoom(_getPvPID, _msgSender(), _amount);
26
}
27
28
/**
29
* @dev Join listed PvP room.
30
*/
31
function joinPvPRoom(uint256 _charID, uint256 _roomID) external payable whenNotPaused nonReentrant {
32
33
require(_roomID > 0 && _roomID <= _pvpID.current(), "This PvP fight does not exist!");
34
require(idToPvPInfo[_roomID].fight == false, "This PvP fight already ended!");
35
require(apocCharacter.ownerOf(_charID) == _msgSender(), "You are not the owner of this character!");
36
require(idToPvPInfo[_roomID].player1 != _msgSender(), "You cannot join the PvP room that you created!");
37
38
uint256 _amount = idToPvPInfo[_roomID].amountToStake;
39
40
rewardToken.transferFrom(_msgSender(), address(this), _amount);
41
totalStake = totalStake.sub(_amount);
42
43
idToPvPInfo[_roomID].player2 = payable(_msgSender());
44
idToPvPInfo[_roomID].charIDP2 = _charID;
45
46
emit JoinPvPRoom(_roomID, _msgSender(), _amount);
47
48
uint256 _tax = _amount.mul(rewardTax[0]).div(rewardTax[1]);
49
uint256 _winnerReward = (_amount.sub(_tax)).mul(2);
50
51
address _player1 = idToPvPInfo[_roomID].player1;
52
address _player2 = idToPvPInfo[_roomID].player2;
53
uint256 _status;
54
uint256 _drop;
55
(_status , _drop) = mixer(_player1, _player2);
56
57
if (_status == 0) {
58
IERC20Extended(rewardToken).transfer(_player1, _winnerReward);
59
fightWon[_player1] = fightWon[_player1] + 1;
60
dropMineral(_player2);
61
fightLost[_player2] = fightLost[_player2] + 1;
62
emit PvPCompleted(_roomID, _player1, _player2);
63
} else if (_status == 1) {
64
IERC20Extended(rewardToken).transfer(_player2, _winnerReward);
65
fightWon[_player2] = fightWon[_player2] + 1;
66
dropMineral(_player1);
67
fightLost[_player1] = fightLost[_player1] + 1;
68
emit PvPCompleted(_roomID, _player2, _player1);
69
}
70
71
idToPvPInfo[_roomID].fight = true;
72
_pvpFought.increment();
73
74
getCurrentPvPIDForCharacter[idToPvPInfo[_roomID].charIDP1] = 0;
75
76
if (allowPot == true) {
77
(address potWinnerAddress, bool distributeStatus) = apocPot.distributePot(_player1, _player2);
78
79
if (distributeStatus == true) {
80
emit PotDistributed(potWinnerAddress);
81
}
82
}
83
84
uint256 pot = rewardToken.balanceOf(address(this)).sub(totalStake).mul(potDistribution[0]).div(potDistribution[1]);
85
require(rewardToken.transferFrom(address(this), address(apocPot), pot));
86
87
}
88
89
/**
90
* @dev Cancel PvP room session.
91
*/
92
function cancelPvPRoom(uint256 _roomID) external payable nonReentrant {
93
94
uint256 _staked = idToPvPInfo[_roomID].amountToStake;
95
address _creator = idToPvPInfo[_roomID].player1;
96
address _competitor = idToPvPInfo[_roomID].player2;
97
bool _fight = idToPvPInfo[_roomID].fight;
98
99
require(_msgSender() == _creator, "You are not the creator for this PvP room session.");
100
require(_fight == false && _competitor == payable(ZERO), "This NFT has either been sold or the listing was already canceled");
101
102
idToPvPInfo[_roomID].player2 = payable(_msgSender());
103
_pvpCanceled.increment();
104
105
idToPvPInfo[_roomID].fight = true;
106
107
if (cancelTax[0] > 0) {
108
uint256 _tax = _staked.mul(cancelTax[0]).div(cancelTax[1]);
109
require(rewardToken.transferFrom(address(this), _msgSender(), _staked.sub(_tax)));
110
} else {
111
require(rewardToken.transferFrom(address(this), _msgSender(), _staked));
112
}
113
totalStake = totalStake.sub(_staked);
114
115
emit PvPCancelled(_roomID, _msgSender());
116
}
117
118
/**
119
* @dev Fetch all active PvP sessions.
120
*/
121
function fetchActivePvP() external view returns (pvpInfo[] memory) {
122
123
uint256 _pvpCount = _pvpID.current();
124
uint256 _activePvPCount = _pvpID.current() - _pvpFought.current() - _pvpCanceled.current();
125
uint256 _currentIndex = 0;
126
127
pvpInfo[] memory items = new pvpInfo[](_activePvPCount);
128
129
for (uint256 i = 0; i < _pvpCount; i++) {
130
if (idToPvPInfo[i + 1].player2 == ZERO) {
131
uint256 currentID = i + 1;
132
pvpInfo storage currentItem = idToPvPInfo[currentID];
133
items[_currentIndex] = currentItem;
134
_currentIndex += 1;
135
}
136
}
137
138
return items;
139
}
140
141
/**
142
* @dev Fetch all completed PvP sessions.
143
*/
144
function fetchCompletedPvP() external view returns (pvpInfo[] memory) {
145
146
uint256 _currentIndex = 0;
147
148
pvpInfo[] memory items = new pvpInfo[](_pvpFought.current());
149
150
for (uint256 i = 0; i < _pvpID.current(); i++) {
151
if (idToPvPInfo[i + 1].fight == true && idToPvPInfo[i + 1].player1 != idToPvPInfo[i + 1].player2) {
152
uint256 currentID = i + 1;
153
pvpInfo storage currentItem = idToPvPInfo[currentID];
154
items[_currentIndex] = currentItem;
155
_currentIndex += 1;
156
}
157
}
158
159
return items;
160
}
161
162
/**
163
* @dev Fetch all cancelled PvP sessions.
164
*/
165
function fetchCancelledPvP() external view returns (pvpInfo[] memory) {
166
167
uint256 _currentIndex = 0;
168
169
pvpInfo[] memory items = new pvpInfo[](_pvpCanceled.current());
170
171
for (uint256 i = 0; i < _pvpID.current(); i++) {
172
if (idToPvPInfo[i + 1].fight == true && idToPvPInfo[i + 1].player1 == idToPvPInfo[i + 1].player2) {
173
uint256 currentID = i + 1;
174
pvpInfo storage currentItem = idToPvPInfo[currentID];
175
items[_currentIndex] = currentItem;
176
_currentIndex += 1;
177
}
178
}
179
180
return items;
181
}
182
}