---
# System prepended metadata

title: ENG - MVP basic loop

---

# MVP Basic Loop

The MVP gameplay is simple:

DDL: 5/17


Task TODO (in Mandrin): https://www.notion.so/serenaletsgo/Infinite-seas-665eea190cb24393956aa1cc02509b57?pvs=4

Art Resources: https://drive.google.com/drive/u/0/folders/1HNU2rzwV5Vue0FCifjZbqJuGQ4RkU2ur

Art Figma: https://www.figma.com/design/Ihr5jqXPPY60egc6r4AxKO/Infinite-Seas-UI?node-id=0-1&t=4b63oUIhdQ9doEuS-1

MVP Doc (in English): https://hackmd.io/@SerenaTaN5/HyjXwyOU0

Game: game.infiniteseas.io


### Changelog
**Updated on 5/5**
- Updated the energy consumption for sailing: from 10 tokens per hour to 5 tokens per hour per ship.
- Changed the combat display on the front end: originally, combat was turn-based interaction where players decided strategies each round. Now, clicking "auto-attack" on the map directly shows the automatic battle result (jumping to the settlement page). The settlement page art is being updated, a sketch is shown below. Each round defaults to "normal attack"; the MVP temporarily cancels the swap and pass logic.
- Points change: from scoring per roster to scoring per ship; points are awarded for defeating the opponent's ship even if the battle is lost. Points calculation changes are shown below.

## Login
zklogins: https://docs.sui.io/concepts/cryptography/zklogin

→ User clicks a DApp that supports Zklogin  
→ Signs in via Google, Facebook, or Twitch  
→ A unique public address is created with a JWT token tied towards the salt service (dev parts lol)  
→ A txn is signed and the user is identified with a unique address.

## Energy Token
→ User gets 100000 Sui test tokens after connecting the wallet.

- Acquisition:  
User can start claiming Energy Tokens after connecting their wallet. First-time claiming is 500, and 200 every 24 hours after. Energy Token max capacity is 1000.
- Consumption:  
Resource gathering, shipbuilding, sailing, and combat all consume corresponding energy tokens. The consumption is as follows:

| Activity | Details | Energy Token Cost | Time |
|---|---|---|---|
| **Resource Gathering** | | | |
| Mine 1 copper ore | | 1 | 3 seconds |
| Cut 1 normal wood | | 1 | 3 seconds |
| Plant 1 seed | Yield: 5 cottons | 5 | 15 seconds |
| **Ship Building** | | | |
| Craft 1 ship | Requires: 15 resources (at least 3 coppers, 3 woods, 3 cottons) | 5 | 15 seconds |
| **Sailing** | | | |
| ~~1 hour sailing~~ 1 hr sailing per ship | | ~~10~~ 5| 1 hour |

## Map

### 1. Display Islands and Ships

![Island and Ship Map](https://hackmd.io/_uploads/B1YZwWZx0.jpg)

![Island and Ship Map](https://hackmd.io/_uploads/BkdZchieC.png)

**Action Queue**  
* When the player executes an action (mining, woodcutting, planting, crafting, sailing), the remaining duration will be listed in the queue on the left.

#### Islands
**Clicking on an island** displays:  
When the player owns an island, clicking on the island with the left mouse button will display the following information:  
→ **Owner:** 0xf3... wallet address; if the wallet address == the player's wallet address, it shows `owner: SELF`  
→ **Resource quantity:** wood: XXX, ore: XXX, seed: XXX  
→ **Number of ships:** ships: XXX  
→ **Points:** points: XXX  
This information is displayed in a small pop-up window.

**First Login**  
Displays unclaimed islands and their corresponding resource amounts, with a "claim button."  
A user can only have one island.

#### Ships
**Clicking on a ship** displays, if the ship is not yours:  
→ **Owner:** 0xf3... wallet address  
→ **HP:** xxx  
→ **Attack:** xxx  
→ **Protection:** xxx  
→ **Speed:** xxx  
→ **Inventory:** Shows 3 slots displaying the materials and quantities in the slots  
Displayed in a small pop-up window.

**Clicking on a ship** displays, if the ship is yours:  
→ **Owner:** self  
→ **HP:** xxx  
→ **Attack:** xxx  
→ **Protection:** xxx  
→ **Speed:** xxx  
→ **Inventory:** Shows 3 slots displaying the materials and quantities in the slots  
→ **Inventory button:** Clicking jumps to the ship's inventory  
Displayed in a small pop-up window.

### 2. Map Generation

**Grid shape:** The map grid is composed of equidistant perspective, all map grids are 45-degree rotated squares (rhombuses).  
**Implementation:** Although the map is infinite, only the part around the player is rendered for a given player, updating as the player moves.

**Block size:** When rendering the front end, the map is divided into multiple blocks, each block size is 1024x576 pixels.  
Using block rendering only shows the blocks within the player's current field of view.

**Dynamic loading:** The map blocks within the player's field of view will be loaded in real-time, and new adjacent blocks will be dynamically loaded as the player moves. Blocks the player leaves will be unloaded from the view.

#### Islands
**Island size:** The island size is estimated to be ~~(100x100)~~ pixels, including the island itself and the surrounding water space. Need to confirm the final size with the art team.

**Island density:** Based on block size and island estimated size, the number of islands is as many as possible and evenly distributed.

**Spacing:** There needs to be enough space between islands for ships to sail, avoiding overlap.

### 3. Resource Generation
→ :game_die: 3 kinds of resources on each island  
→ :game_die: 600 amount for the sum of all the 3 resources  
→ :game_die: The min of each resource is 150. The amount should be randomly generated.  
→ :game_die: After the random generation, the amount of seeds should be floor divided by 5 since the later planting function will grow 5 cottons out of 1 seed.

```javascript
function distributeResources() {
  const minAmount = 150;
  let wood = minAmount, ore = minAmount, seed = minAmount;
  let remaining = 150; // total is 600, 450 assigned, 150 left to distribute

  while (remaining > 0) {
    let choice = Math.floor(Math.random() * 3);
    if (choice === 0) wood++;
    else if (choice === 1) ore++;
    else seed++;
    remaining--;
  }

  // floor div by 5 to the amount of seed 
  // since the planting behavior will make 5 cottons out of 1 seed.
  seed = Math.floor(seed / 5) * 5;

  return { wood, ore, seed };
}

console.log(distributeResources());
```

## Island Management - All actions can be performed simultaneously

→ After clicking on the bottom right **"island" icon button**, different action icons show up at the bottom.  
→ Camera position is set back to the island center.  
<img src="https://hackmd.io/_uploads/SkOgAtdeC.jpg" width="600" alt="island-management">

### The following information is displayed:
- Island name, ID
- Amount of resources available for gathering on the island
- Whether occupied, if yes, related to the owner:
    - Owner ID
    - Number of ships
    - Collected resources and quantities
    - Ongoing actions (gathering/crafting and countdown)

### The following actions can be performed:
* **Can different actions be performed simultaneously?**:
    * Yes
* **Can the same actions be performed simultaneously?**: 
    * Except for sailing, other actions cannot be performed simultaneously: If a player is currently performing a mining action, the player cannot perform a new mining action until the first mining action is completed.

* **Resource Gathering**
    * Users can gather ore/wood or plant (cotton seeds).
    * Click the corresponding resource type, a pop-up window allows the user to choose the specific resource quantity and shows the estimated time. Click the pop-up window "woodcut button"/"mine" button to confirm execution.
    <img src="https://hackmd.io/_uploads/ryMPtZWgC.jpg" width="600" alt="resource-gathering">
    <img src="https://hackmd.io/_uploads/ryXGFbblR.jpg" width="600" alt="resource-gathering-popup">
    * Energy consumption:
        - Cut 1 normal tree costs 1 energy token, 3 seconds time duration.
        - Mine 1 copper ore costs 1 energy token, 3 seconds time duration.
        - Planting:
            - :game_die: There are 2 planting grids on each island, meaning players can grow 2 seeds simultaneously.
            - :game_die: Plant 1 cotton costs 5 energy tokens, 3 mins time duration, 5 outputs cotton balls.

* **Ship Building**
    * Users can use collected cotton/ore/wood to build ships.
    * The leftmost button is typo? should be "recipe"? selection, default is the small ship recipe (MVP only has a small ship).
    * Add or modify resources: The player clicks the slot for the resource to be added or modified, and the island inventory pops up on the right. The player clicks the resource in the inventory; the new resource is added to the middle recipe slot.
    * After the player places each resource, update the top right corner of the ship's three stats: attack/protection/speed.
    * After the player places 15 resources, click the craft button.
    * Clicking craft pops up a window, where the player selects the quantity, estimated energy token consumption (5 per ship), and time (15s per ship), then clicks confirm to execute the action.

![ship-building](https://hackmd.io/_uploads/SkyCrzqg0.png)

→ Min amount for each resource is 3. At least 3 ores, 3 woods, 3 plants; but the sum needs to reach 15 to craft the small ship. This means players can distribute a total of 6 resources.  
→ 1 ore = 1 attack; 1 wood = 1 protection; 1 plant = 1 speed.  
→ Crafting 1 small ship costs 5 energy tokens, 15 seconds time duration.  
→ For MVP, only small ship is available for craft; other recipes are locked.

```python
class Ship:
    def __init__(self, name="Ship", team="1", attack=3, protection=3, speed=3):
        self.name = name
        self.team = team
        self.hp = 20
        self.attack = attack
        self.protection = protection
        self.speed = speed
        # Points will be distributed by the player.
    
    def distribute_extra_points(self):
        extra_points = 6  # Players can distribute a total of 6 extra points.
        print(f"\nDistributing extra points for {self.name}: (Total extra points: {extra_points})")
        for attr in ['attack', 'protection', 'speed']:
            while True:
                try:
                    points = int(input(f"Enter extra points to add to {attr} (Remaining points: {extra_points}): "))
                    if points <= extra_points:
                        setattr(self, attr, getattr(self, attr) + points)
                        extra_points -= points
                        break
                    else:
                        print("You don't have enough points. Please try again.")
                except ValueError:
                    print("Invalid input. Please enter a number.")
        print(f"Final stats - HP: 20, Attack: {self.attack}, Protection: {self.protection}, Speed: {self.speed}")
```

### Island Inventory
→ Players will see an **"inventory" icon** on the bottom menu.  
→ After clicking on the "inventory" button, there will be a **popup window** to show all the resources/equipment the players have.  
→ There are 20 grids in total which means the inventory can store 20 different items. The same resources/equipment will be accumulated in one grid and count the amount.  
→ Ships built by the player will appear in the adjacent sea area of the island's beach.  
![image](https://hackmd.io/_uploads/rJpLZ2slR.png)

## Sail & Battle
## Ship Management
→ After clicking the **"ship icon"** button on the main page, players will be directed to the **ship management page**.

→ Displays the list of ship stats: ID, HP (total of 20 for small ship), Attack, Protection, Speed.

**Roster Buttons**
* There are 6 tabs: all, roster 1, roster 2, roster 3, roster 4, unassigned; clicking on a roster jumps to that roster.
* There are 4 rosters in total, each roster queue can have up to 4 ships.
* "All" displays all ships, "Roster 1" displays the ships in roster 1..., "unassigned" displays unassigned ships.
<img src="https://hackmd.io/_uploads/rysXK5l7A.png" width="600" alt="roster-tabs">

**Arrange ship order within Roster1-4**
* Players can arrange the order of ships by dragging and dropping.

**Remove ships within Roster1-4 button**
* When the roster returns to the island, ships in the roster can be removed.
* Players can click the “X” button to remove this ship from the roster, and the remaining ships move up to take the position; the removed ship joins the “unassigned” queue.

**Add ships within Roster1-4 button**
* When the roster returns to the island, ships can be added from the unassigned roster.
* If the roster has fewer than 4 ships, an empty slot will have a “+” button.
<img src="https://hackmd.io/_uploads/rJxLF5eQC.png" width="600" alt="add-ship-button">
* Players click the “+” button to jump to the “unassigned” roster, click on the ship, and add the ship to the roster.
<img src="https://hackmd.io/_uploads/BJabc5e7C.png" width="600" alt="unassigned-roster">

### Ship Inventory including inventory transfer function
* Ships in the same roster can transfer inventory between each other.
* Ships on the island can transfer inventory with the island inventory.
* When players are in roster1-4 or unassigned roster, each ship has a transfer inventory button on the right.
<img src="https://hackmd.io/_uploads/rJxLF5eQC.png" width="600" alt="transfer-inventory-button">

* Players click to jump to the following interface.
* The ship's inventory has 3 slots; the same kind of material can be stacked.
* ==This version will not have storage issues, as there are only three different resources.==
<img src="https://hackmd.io/_uploads/r1Evc9emR.png" width="600" alt="ship-inventory">
    * Ship transfer can only occur within the same roster.
    * If the ship returns to the island, the inventory of ships within the roster can also transfer with the island inventory.

### Sailing
* **Destination Selection**
    * When the player’s fleet has ≥ 1 ship, they can press the sail button in the bottom left to execute the sail action.
    * When the player presses the sail button, they jump to the sailing interface.
<img src="https://hackmd.io/_uploads/rJxLF5eQC.png" width="600" alt="sail-button">
    * Players can **left-click** on the coordinates on the map (sea, ship, island) to get corresponding information; the displayed information is consistent with the previously mentioned information.
    * Players can **right-click** on the coordinates on the map to select the destination position; after right-clicking, a pop-up window appears displaying the information shown below.
    * Clicking “Y” starts the ships’ sailing, with the destination being an adjacent grid; players arrive at the location without overlapping island elements.
    * Clicking “N” allows players to reselect the destination coordinates.
    * Clicking the “Back” button returns players to the ship management interface.
    * After setting the sailing destination, if players want to change the destination during the sail, they can re-enter the ship management roster page and click sail to choose a new destination.
<img src="https://hackmd.io/_uploads/r1reYdjx0.png" width="600" alt="destination-selection">

* **Sailing Speed and Energy Token Consumption**
→ :game_die: The energy token will be spent along with time and coordinates it moves.  
→ :game_die: The energy token cost = $10\times hrs$.  
→ :game_die: Assuming islands are evenly distributed on the map, sailing between adjacent islands (A to B) takes approximately 20 mins (for a ship with 5 cottons); each change in the number of cottons ± 2 mins; sailing speed is the average of all ships in the same roster.

### Ship Battle
* Attack pop-up window: ==When any ship is adjacent (within an adjacent range), an attack pop-up window will appear, which can be called “intercept.”== Interception challenges the entire roster. Battles are conducted by roster.
* After the player clicks the **"auto-attack"** button, they enter the battle page.
* If the player clicks the “X” button, they can exit the pop-up window.
<img src="https://hackmd.io/_uploads/B1YSlFje0.png" width="600" alt="attack-popup">
    * *no trade or steal for MVP*

### Battle Page
https://github.com/serenakeyitan/infinite-seas-ship-battle.git  
→ Run `shipbattle.py` to test out the combat loop.  
This code's combat does not implement strategy; each round, both sides perform a normal attack by default.

* **Brief**
    * Battles are 1 roster vs 1 roster; battles can be PvE or PvP; the logic for PvE and PvP is the same. ~~Whoever initiates the attack first is P (can choose strategy each round), the other is E (automatic combat: normal attack each round)~~ Both sides perform automatic combat (normal attack each round).
    * ~~The attack order for each round is determined by dice and speed variable. When it’s the player’s turn, the player has 10 seconds to choose: normal attack or swap position or pass. If no choice is made within 10 seconds, pass is executed. When all ships in one roster are defeated, loot is settled (specific attack values and logic are detailed below).~~
    * Ships that die in battle disappear, and the items in the ship’s inventory also disappear. The inventory items are settled based on win or loss (detailed winner rewards below).

#### ~~Regarding the bottom left ship information display~~
* ~~The panel below shows the information of the ship initiating the attack on our side. If there is a delay, it can be set to default to the first ship.~~
* ~~The panel below shows HP, attack, protection, and speed.~~

#### ~~Regarding the bottom right battle button and interface~~
* ~~When the player clicks on the “battle” button, the logic for displaying the enemy panel below is the same as for our ship. The only difference is if the mouse hovers over a particular enemy ship, it prioritizes displaying the stats of the hovered ship.~~

#### ~~Regarding the bottom right inventory button and interface~~
* ~~When the player clicks on the “Inventory” button, the inventory will display all the inventory of our ships.~~

#### Combat Phases: Values and Logic
→ **Initiation: Determine Battle Order**: Each round begins with the **calculation of turn order**, influenced by each ship's speed attribute and potentially modified by speed abilities.

```python
# random int from 1 to 8 + speed val
def generate_turn_order(ships):
    turn_order = []
    for ship in ships:
        if ship.hp > 0:  # Only consider ships that are still active
            initiative = random.randint(1, 8) + ship.speed
            turn_order.append((ship, initiative))
    # Sort ships by their initiative score, highest first
    turn_order.sort(key=lambda x: x[1], reverse=True)
    return [ship[0] for ship in turn_order]
```
→ **Action Phase: Player Attacks - Critical Hit and Miss**: Players issue commands by clicking "**normal attack**" button for their ships. Options include **attacking**, **strategic positioning**, or **passing**.
```python
# attack
        critical_hit_chance = 0.2  # 20% chance for a critical hit
        critical_miss_chance = 0.35  # 35% chance for a critical miss

# swap position
# pass
```
→ **Resolution: Opponent Takes Damage and Dodge Chance**: The outcomes of all actions are calculated, including damage dealt and received, and effects of special abilities (dodge).
```python
        # Damage calculation with base formula
        # Damage calc with opp. protection
        if self.attack < opponent.protection:
            damage = max(2, self.attack - (opponent.protection - self.attack) * 0.3)
        else:
            damage = self.attack - opponent.protection * 0.8

        damage = max(0, damage)  # Ensure damage is not negative
        # Dodge check: protection value matters
        dodge_chance = min(60, ((opponent.protection - self.attack) * 8 + 15)) if opponent.protection >= self.attack else 0
        if random.randint(1, 100) <= dodge_chance:
            print(f"{opponent.name} dodged the attack from {self.name}!")
            return
```

→ **Condition Checks: Check Conditions After Each Action**: After actions resolve, the game checks for conditions such as the sinking of ships, or victory conditions being met.  
→ **Round Conclusion: Game Win/Loss Condition Check After Each Round**: The round ends, and if no victory condition is met, a new round begins with updated game state information.

#### After clicking the auto-attack button, the automatic battle results are displayed, and the Winner Rewards calculation page is entered.

#### Winner Rewards Calculation
* The winner can collect 80% of the resources in the opponent's inventory, and 80% of the resources the opponent spent to craft all the ships in the roster.
* When the winning condition is met, either the "Victory window" or "Defeat window" will pop up as shown below.
* Victory will have the choice to "Take all" the loot or "cancel".
    * **Take all**: After the game ends, clicking take all will store the loot automatically to the last ship in the roster position; if the opponent wins, take all is chosen by default.
        * Each ship has its own inventory of 3 slots; the same type of material can be stacked; MVP will not have storage issues.
    * **Cancel**: The player clicks leave it, abandoning all loot.
<img src="https://hackmd.io/_uploads/HymgKTFzR.png" width="600" alt="victory-window">

* Defeat will have the choice to "Back to island" or "not".
    * Points calculation is based on how many ships are defeated; even if the player loses, they can still earn points for defeating 2 ships.
<img src="https://hackmd.io/_uploads/r137YpKfR.png" width="600" alt="defeat-window">

### Combat Targets - PVE & PVP
Combat targets are PvE ships that are randomly generated.

#### Level 1 Ship Rosters
* 4 ships in a roster and each ship is composed of 8 resources.
* Base resource: (2,2,2), the remaining 2 resources are randomly distributed in woods, ores, and cottons.
* Points: 2/ship
* Loot: Level 1 ship rosters `Inventory + crafting resources` floored by 1.25.

#### Level 2 Ship Rosters
* 4 ships in a roster and each ship is composed of 12 resources.
* Base resource: (3,3,3), the remaining 3 resources are randomly distributed in woods, ores, and cottons.
* Points: 3/ship
* Loot: Level 2 ship rosters `Inventory + crafting resources` floored by 1.25.

#### Level 3 Ship Rosters
* 4 ships in a roster and each ship is composed of 16 resources.
* Base resource: (3,3,3), the remaining 7 resources are randomly distributed in woods, ores, and cottons.
* Points: 6/ship
* Loot: Level 3 ship rosters `Inventory + crafting resources` floored by 1.25.

#### PVP Ship Rosters
* Points: 8/ship
* PvP ship rosters `Inventory + crafting resources` floored by 1.25.

## Leaderboard
Replace “ranking” with leaderboard.
- <img src="https://hackmd.io/_uploads/SkOgAtdeC.jpg" width="600" alt="leaderboard-button">
The button is the leftmost diamond button, which pops up the leaderboard.

## Quests
- [ ] Create wallet
- [ ] Claim island
- [ ] Cut 5 woods
- [ ] Mine 5 ores
- [ ] Plant 5 cottons
- [ ] Craft 1 ship
- [ ] Craft 4 ships
- [ ] Battle, and beat 1 PvE ship

## Admin Function
Generate island function;  
Generate PvE ships function; add ships to the island randomly for players to challenge (PvE);  
Claim energy token function;  
Claim Sui token function;
