JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

<button id='random-btn'>Random battle</button>
<div id='popup-battle'>
    <div id='pb-container'>";
        <button id='pb-close-btn'>Close</button>
        <!-- Containers for the 2 sides' sprites. -->
        <div id='pb-mythic-party'></div>
        <div id='pb-enemy-party'></div>
        
        <!-- Where names, turn order will be listed. -->
        <div id='pb-enemy-info-title'>Enemies</div>
        <div id='pb-mythic-info-title'>Your Party</div>
        <div id='pb-mythic-info' class='pb-info'></div>
        <div id='pb-enemy-info' class='pb-info'></div>
        
        <!-- Show report from last turn, or options for next turn. -->
        <div id='pb-middle'>
            <div id='pb-reports'></div>
            <div id='pb-options'>
            
                <!-- Name of griffin whose turn it is. -->
                <b><span id='pb-griffin-name'></span></b>
                <hr>
                Action: "<span id='pb-action-name'><i>Choose one!</i></span>
                <br>
                <!-- Name of targeted enemy, ally, or may change to 'All/None/Random/Battlefield' if certain action is selected. -->
                Target: <span id='pb-target-name'></span>
        
                <!-- Buttons to bring up menus to scroll through. -->
                <div id='pb-action-buttons'>
                    <!-- List griffin's non-magic abilities. -->
                    <button class='pb-action-btn' data-action='move'>Physical</button>
                    <!-- Only list spells if know any. -->
                    <button class='pb-action-btn' data-action='spell'>Magic</button>
                    <!-- Only list items if have any. -->
                    <button class='pb-action-btn' data-action='item'>Item</button>
                    <hr>
                    <div id='pb-confirm-action'>Confirm</div>
                </div>
                
            </div>
        </div>
        
        <!-- Menus to select a physical/magic ability, or item. Will...

CSS

div, img, p, button {
    box-sizing: border-box;
}

/* This popup battle window is used for monster battles as well as arena sparring with other mythics. Supports 1-4 mythics and 1-12 enemies. */

/* Appears in centre of page */
#popup-battle {
    width: 800px;
    height: 500px;
    border: 2px solid black;
    border-radius: 10px;
    background-color: #eee;
    
    background-image: url("https://mylivewallpapers.b-cdn.net/wp-content/uploads/Nature/thumb-Forest-Swamp.jpg");
    background-size: cover;
    
    position: fixed;
    top: calc(50% - 250px);
    left: calc(50% - 400px);
}

/* Fills #popup-battle, contains absolutely positioned content */
#pb-container {
    width: 100%;
    height: 100%;
    position: relative;
}

/* Two upper sections of battlefield, with lil sprites positioned around. */
#pb-mythic-party {
    width: 290px;
    height: 220px;
    position: absolute;
    top: 30px;
    right: 0;
    /*background-color: lightgreen;*/
    border: 1px solid lightgreen;
}
#pb-enemy-party {
    width: 500px;
    height: 220px;
    position: absolute;
    top: 30px;
    left: 0;
    /*background-color: lightpink;*/
    border: 1px solid red;
}

/* Enemies come in 3 sizes. Mythics in 2. 1v1 arena battles use large versions. */
#pb-container .pb-fighter {
    cursor: pointer;
    border: 1px dotted black;
    position: absolute;
}
#pb-container .pb-fighter:hover {
    border: 1px solid black;
}

#pb-container .pb-fighter-small {
    width: 80px;
    height: 60px;
}
#pb-container .pb-fighter-medium {
    width: 150px;
    height: 120px;
}
#pb-container .pb-fighter-large {
    width: 360px;
    height: 180px;
}

/* When an enemy or griffin is the intended target. */
.pb-crosshair-enemy {
    background:
    linear-gradient(to right, red 4px, transparent 4px) 0 0,
    linear-gradient(to right, red 4px, transparent 4px) 0 100%,
    linear-gradient(to left, red 4px, transparent 4px) 100% 0,
    linear-gradient(to left, red 4px, transparent 4px) 100% 100%,
 ...

JavaScript

const db = {

    // For generic enemy battles. Depending on number
    // of mythics in party, choose a formation, then
    // enemies of correct sizes to fit in it.
    // Generally, medium enemies are tougher than small,
    // and only parties of 3/4 should fight a huge one.
    battleFormations: [
        {
            id: 1, name: "Solo Small",
            about: "A single enemy, randomly positioned.",
            enemies: [
                {number: 1, positions: [
                    [95,36], [250,22], [178,88], [320,70],
                    [73,113], [233,137]
                ]},
                {number: 0},
                {number: 0}
            ]
        },
        {
            id: 2, name: "Solo Medium",
            about: "A single enemy.",
            enemies: [
                {number: 0},
                {number: 1, positions: [[167,50]]},
                {number: 0}
            ]
        },
        {
            id: 3, name: "Small Pair",
            about: "Two small enemies, positioned randomly.",
            enemies: [
                {number: 2, positions: [
                    [95,36], [250,22], [178,88], [320,70],
                    [73,113], [233,137]
                ]},
                {number: 0},
                {number: 0}
            ]
        },
        {
          id: 4, name: "Medium Pair",
            about: "Two medium enemies.",
            enemies: [
                {number: 0},
                {number: 2, positions: [
                    [78,50], [263,45]
                ]},
                {number: 0}
            ]
        },
        {
            id: 5, name: "Small Trio",
            about: "Three enemies, positioned randomly.",
            enemies: [
                {number: 3, positions: [
                    [95,36], [250,22], [178,88], [320,70],
                    [73,113], [233,137]
                ]},
                {number: 0},
                {number: 0}
            ]
        },
        {
            id: 6,...