completely restructured and refactored the front end.
							
								
								
									
										83
									
								
								web/assets/css/creatures.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#resultSection {
 | 
				
			||||||
 | 
					    font-family: Arial, sans-serif;
 | 
				
			||||||
 | 
					    font-size: 14pt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.nickname {
 | 
				
			||||||
 | 
					    background-color: #abf1f1;
 | 
				
			||||||
 | 
					    border-style: solid;
 | 
				
			||||||
 | 
					    border-width: 1px;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.house-note {
 | 
				
			||||||
 | 
					    background-color: rgba(246, 246, 167, 0.93);
 | 
				
			||||||
 | 
					    font-style: italic;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.container {
 | 
				
			||||||
 | 
					    display: grid;
 | 
				
			||||||
 | 
					    grid-template-columns: 1.1fr 1fr 0.9fr;
 | 
				
			||||||
 | 
					    grid-template-rows: 1.2fr 0.5fr 1.3fr;
 | 
				
			||||||
 | 
					    gap: 0 0;
 | 
				
			||||||
 | 
					    grid-auto-flow: row;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.container.android {
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    gap: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Container for each type (thinker, worker, warrior) */
 | 
				
			||||||
 | 
					.typeContainer {
 | 
				
			||||||
 | 
					    display: flex; /* Use flexbox for layout */
 | 
				
			||||||
 | 
					    justify-content: space-between; /* Space out the child elements evenly */
 | 
				
			||||||
 | 
					    margin-bottom: 20px; /* Add some bottom margin for separation between types */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Profile and abilities within each type */
 | 
				
			||||||
 | 
					.creature_id,
 | 
				
			||||||
 | 
					.creature_profile,
 | 
				
			||||||
 | 
					.creature_abilities {
 | 
				
			||||||
 | 
					    width: 45%; /* Give them each about half the container's width */
 | 
				
			||||||
 | 
					    height: 345px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_attacks {
 | 
				
			||||||
 | 
					    width: 40%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_mutations {
 | 
				
			||||||
 | 
					    width: 60%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_description {
 | 
				
			||||||
 | 
					    width: 90%;
 | 
				
			||||||
 | 
					    margin-top: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_id {
 | 
				
			||||||
 | 
					    grid-area: 1 / 1 / 2 / 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_profile {
 | 
				
			||||||
 | 
					    grid-area: 1 / 2 / 2 / 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_abilities {
 | 
				
			||||||
 | 
					    grid-area: 1 / 3 / 2 / 4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_attacks {
 | 
				
			||||||
 | 
					    grid-area: 2 / 1 / 3 / 4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_mutations {
 | 
				
			||||||
 | 
					    grid-area: 2 / 2 / 3 / 2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.creature_description {
 | 
				
			||||||
 | 
					    grid-area: 3 / 1 / 4 / 4;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB  | 
| 
		 Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB  | 
| 
		 Before Width: | Height: | Size: 412 KiB After Width: | Height: | Size: 412 KiB  | 
| 
		 Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB  | 
| 
		 Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB  | 
| 
		 Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB  | 
| 
		 Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB  | 
| 
		 Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 434 KiB  | 
| 
		 Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 382 KiB  | 
| 
		 Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 440 KiB  | 
| 
		 Before Width: | Height: | Size: 566 KiB After Width: | Height: | Size: 566 KiB  | 
| 
		 Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB  | 
| 
		 Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB  | 
| 
		 Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB  | 
| 
		 Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB  | 
| 
		 Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB  | 
| 
		 Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB  | 
| 
		 Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB  | 
| 
		 Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB  | 
| 
		 Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB  | 
| 
		 Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB  | 
| 
		 Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB  | 
| 
		 Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB  | 
| 
		 Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB  | 
| 
		 Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB  | 
| 
		 Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB  | 
| 
		 Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB  | 
| 
		 Before Width: | Height: | Size: 4.8 MiB After Width: | Height: | Size: 4.8 MiB  | 
| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB  | 
| 
		 Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB  | 
| 
		 Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB  | 
| 
		 Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB  | 
| 
		 Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB  | 
| 
		 Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB  | 
| 
		 Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB  | 
| 
		 Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 200 KiB  | 
| 
		 Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB  | 
| 
		 Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB  | 
| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB  | 
| 
		 Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB  | 
| 
		 Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB  | 
| 
		 Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB  | 
| 
		 Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB  | 
| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB  | 
| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB  | 
| 
		 Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB  | 
| 
		 Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB  | 
| 
		 Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB  | 
| 
		 Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB  | 
| 
		 Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB  | 
| 
		 Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB  | 
| 
		 Before Width: | Height: | Size: 636 KiB After Width: | Height: | Size: 636 KiB  | 
| 
		 Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB  | 
| 
		 Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB  | 
| 
		 Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB  | 
| 
		 Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB  | 
| 
		 Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB  | 
| 
		 Before Width: | Height: | Size: 8.8 MiB After Width: | Height: | Size: 8.8 MiB  | 
| 
		 Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB  | 
| 
		 Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB  | 
| 
		 Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB  | 
| 
		 Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB  | 
| 
		 Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB  | 
| 
		 Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB  | 
| 
		 Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB  | 
| 
		 Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB  | 
| 
		 Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB  | 
| 
		 Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB  | 
| 
		 Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB  | 
| 
		 Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB  | 
| 
		 Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB  | 
| 
		 Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB  | 
| 
		 Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB  | 
| 
		 Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB  | 
| 
		 Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB  | 
| 
		 Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB  | 
| 
		 Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB  | 
							
								
								
									
										47
									
								
								web/assets/js/androidResultTable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					import {createProfileSection} from "./createProfileSection.js";
 | 
				
			||||||
 | 
					import {createAbilitiesSection} from "./createAbilitiesSection.js";
 | 
				
			||||||
 | 
					import {createDescriptionSection} from "./createDescriptionSection.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function androidResultTable(data, creatureName) {
 | 
				
			||||||
 | 
					    let container = document.createElement('div');
 | 
				
			||||||
 | 
					    container.className = 'container android';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let creatureTitle = document.createElement('h2');
 | 
				
			||||||
 | 
					    creatureTitle.textContent = creatureName.toUpperCase();
 | 
				
			||||||
 | 
					    container.appendChild(creatureTitle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let image = document.createElement('img');
 | 
				
			||||||
 | 
					    image.src = '/assets/img/android.jpg';
 | 
				
			||||||
 | 
					    image.onerror = () => { image.src = '/assets/img/404.jpg' };
 | 
				
			||||||
 | 
					    image.style.width = '275px';
 | 
				
			||||||
 | 
					    image.style.height = '275px';
 | 
				
			||||||
 | 
					    container.appendChild(image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let description = createDescriptionSection(data);
 | 
				
			||||||
 | 
					    container.appendChild(description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Object.entries(data).forEach(([key, value]) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (key === 'thinker' || key === 'worker' || key === 'warrior') {
 | 
				
			||||||
 | 
					            let typeTitle = document.createElement('h2');
 | 
				
			||||||
 | 
					            typeTitle.textContent = key.toUpperCase();
 | 
				
			||||||
 | 
					            container.appendChild(typeTitle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Create a div for each type (thinker, worker, or warrior)
 | 
				
			||||||
 | 
					            let typeContainer = document.createElement('div');
 | 
				
			||||||
 | 
					            typeContainer.className = 'typeContainer'; // we'll use this in css
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let profile = createProfileSection(value);
 | 
				
			||||||
 | 
					            let abilities = createAbilitiesSection(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Append profile and abilities to the typeContainer, instead of the main container
 | 
				
			||||||
 | 
					            typeContainer.appendChild(profile);
 | 
				
			||||||
 | 
					            typeContainer.appendChild(abilities);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Finally, append the typeContainer to the main container.
 | 
				
			||||||
 | 
					            container.appendChild(typeContainer);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resultSection.appendChild(container);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								web/assets/js/bestiary.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import {loadingGif} from "./loading.js";
 | 
				
			||||||
 | 
					import {androidResultTable} from "./androidResultTable.js";
 | 
				
			||||||
 | 
					import {setCreatureTable} from "./setCreatureTable.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.getElementById('searchForm').addEventListener('submit', function (event) {
 | 
				
			||||||
 | 
					    event.preventDefault();
 | 
				
			||||||
 | 
					    const creatureName = document.getElementById('creature').value;
 | 
				
			||||||
 | 
					    const queryParams = new URLSearchParams({
 | 
				
			||||||
 | 
					        creature: creatureName,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Insert the loading.gif before making the fetch request
 | 
				
			||||||
 | 
					    let resultSection = document.getElementById('resultSection');
 | 
				
			||||||
 | 
					    let imgElement = loadingGif(resultSection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					        fetch(`${window.BASE_URL}/rules/creature?${queryParams}`)
 | 
				
			||||||
 | 
					            .then((response) => {
 | 
				
			||||||
 | 
					                if (!response.ok) {
 | 
				
			||||||
 | 
					                    throw response;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return response.json(); // we only get here if there is no error
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then((json) => {
 | 
				
			||||||
 | 
					                if (json === null) { // if json is null update the image and stop execution
 | 
				
			||||||
 | 
					                    imgElement.src = '/assets/img/404.jpg';
 | 
				
			||||||
 | 
					                    throw new Error('No data found'); // this will stop the execution and go to the catch block
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                resultSection.innerHTML = ''; // Clear previous content
 | 
				
			||||||
 | 
					                if (creatureName === 'android') {
 | 
				
			||||||
 | 
					                    androidResultTable(json, creatureName);
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    setCreatureTable(json, creatureName);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch((err) => {
 | 
				
			||||||
 | 
					                console.log(err);
 | 
				
			||||||
 | 
					                if (!resultSection.hasChildNodes()) { // Only update the image if it wasn't already updated
 | 
				
			||||||
 | 
					                    imgElement.src = '/assets/img/404.jpg';
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -4,5 +4,10 @@ if (window.location.hostname === 'localhost' || window.location.hostname === '12
 | 
				
			|||||||
} else {
 | 
					} else {
 | 
				
			||||||
    window.BASE_URL = 'https://gammaworld.gmgauthier.com';
 | 
					    window.BASE_URL = 'https://gammaworld.gmgauthier.com';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					window.IMG = "/assets/img";
 | 
				
			||||||
 | 
					window.CSS = "/assets/css";
 | 
				
			||||||
 | 
					window.JS = "/assets/js";
 | 
				
			||||||
 | 
					window.DOC = "/pages";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
console.log(window.location.hostname)
 | 
					console.log(window.location.hostname)
 | 
				
			||||||
console.log(window.BASE_URL)
 | 
					console.log(window.BASE_URL)
 | 
				
			||||||
							
								
								
									
										19
									
								
								web/assets/js/createAbilitiesSection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import {formatDiceMnemonic} from "./formatDiceMnemonic.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function createAbilitiesSection(data) {
 | 
				
			||||||
 | 
					    // Abilities section
 | 
				
			||||||
 | 
					    let abilities = document.createElement('div');
 | 
				
			||||||
 | 
					    abilities.className = 'creature_abilities';
 | 
				
			||||||
 | 
					    abilities.innerHTML = `
 | 
				
			||||||
 | 
					              <h3>Abilities</h3>
 | 
				
			||||||
 | 
					              <table>
 | 
				
			||||||
 | 
					                  <tr><td><b>MS</b></td> <td>${formatDiceMnemonic(data.ms)}</td></tr>
 | 
				
			||||||
 | 
					                  <tr><td><b>IN</b></td> <td>${formatDiceMnemonic(data.in)}</td></tr>
 | 
				
			||||||
 | 
					                  <tr><td><b>DX</b></td> <td>${formatDiceMnemonic(data.dx)}</td></tr>
 | 
				
			||||||
 | 
					                  <tr><td><b>CH</b></td> <td>${formatDiceMnemonic(data.ch)}</td></tr>
 | 
				
			||||||
 | 
					                  <tr><td><b>CN</b></td> <td>${formatDiceMnemonic(data.cn)}</td></tr>
 | 
				
			||||||
 | 
					                  <tr><td><b>PS</b></td> <td>${formatDiceMnemonic(data.ps)}</td></tr>
 | 
				
			||||||
 | 
					              </table>
 | 
				
			||||||
 | 
					            `;
 | 
				
			||||||
 | 
					    return abilities;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								web/assets/js/createAttacksSection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import {formatDiceMnemonic} from "./formatDiceMnemonic.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function createAttacksSection(data) {
 | 
				
			||||||
 | 
					    // Attacks section
 | 
				
			||||||
 | 
					    let attacks = document.createElement('div');
 | 
				
			||||||
 | 
					    attacks.className = 'creature_attacks';
 | 
				
			||||||
 | 
					    let attacksHTML = '<h3>Attacks</h3>';
 | 
				
			||||||
 | 
					    let attacksTable = '<table>';
 | 
				
			||||||
 | 
					    for (let attack in data.attacks) {
 | 
				
			||||||
 | 
					        let mnemonic_display;
 | 
				
			||||||
 | 
					        mnemonic_display = formatDiceMnemonic(data.attacks[attack]);
 | 
				
			||||||
 | 
					        if (mnemonic_display === "0d0") {
 | 
				
			||||||
 | 
					            mnemonic_display = 'See Description';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        attacksTable += `<tr><td><b>${attack}</b></td><td>${mnemonic_display}</td></tr>`
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    attacksTable += '</table>';
 | 
				
			||||||
 | 
					    attacks.innerHTML = attacksHTML + attacksTable;
 | 
				
			||||||
 | 
					    return attacks
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								web/assets/js/createDescriptionSection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					export function createDescriptionSection(data) {
 | 
				
			||||||
 | 
					    // Description section
 | 
				
			||||||
 | 
					    let description = document.createElement('div');
 | 
				
			||||||
 | 
					    description.className = 'creature_description';
 | 
				
			||||||
 | 
					    description.innerHTML = `
 | 
				
			||||||
 | 
					              <h3>Description</h3>
 | 
				
			||||||
 | 
					              ${data.description}
 | 
				
			||||||
 | 
					            `;
 | 
				
			||||||
 | 
					    return description;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								web/assets/js/createMutationsSection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					export function createMutationsSection(mutarray) {
 | 
				
			||||||
 | 
					    // Mutations section
 | 
				
			||||||
 | 
					    let mutations = document.createElement('div');
 | 
				
			||||||
 | 
					    mutations.className = 'creature_mutations';
 | 
				
			||||||
 | 
					    let mutationsHTML = '<h3>Mutations</h3>';
 | 
				
			||||||
 | 
					    let mutationsList = mutarray.reduce((result, mutation) => result + `<li>${mutation}</li>`, '');
 | 
				
			||||||
 | 
					    mutationsHTML += `<ul>${mutationsList}</ul>`;
 | 
				
			||||||
 | 
					    mutations.innerHTML = mutationsHTML
 | 
				
			||||||
 | 
					    return mutations
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								web/assets/js/createProfileSection.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import {formatDiceMnemonic} from "./formatDiceMnemonic.js";
 | 
				
			||||||
 | 
					import {formatSpeedMnemonic} from "./formatSpeedMnemonic.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function createProfileSection(data) {
 | 
				
			||||||
 | 
					    let profile = document.createElement('div');
 | 
				
			||||||
 | 
					    profile.className = 'creature_profile';
 | 
				
			||||||
 | 
					    let profileHTML = `
 | 
				
			||||||
 | 
					          <h3>Profile</h3>       
 | 
				
			||||||
 | 
					          <table>
 | 
				
			||||||
 | 
					              <tr><td><b>NUMBER</b></td> <td>${formatDiceMnemonic(data.number)}</td></tr>
 | 
				
			||||||
 | 
					              <tr><td><b>MORALE</b></td> <td>${formatDiceMnemonic(data.morale)}</td></tr>
 | 
				
			||||||
 | 
					              <tr><td><b>HIT DICE</b></td> <td>${formatDiceMnemonic(data['hit dice'])}</td></tr>
 | 
				
			||||||
 | 
					              <tr><td><b>ARMOUR</b></td> <td>${data.armour}</td></tr>
 | 
				
			||||||
 | 
					              <tr><td><b>ENVIRON</b></td> <td>${data.environ.join(', ')}</td></tr>
 | 
				
			||||||
 | 
					            `;
 | 
				
			||||||
 | 
					    if(data['land speed']){
 | 
				
			||||||
 | 
					        profileHTML += `<tr><td><b>LAND SPEED</b></td> <td>${formatSpeedMnemonic(data['land speed'])}</td></tr>`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(data['water speed']){
 | 
				
			||||||
 | 
					        profileHTML += `<tr><td><b>WATER SPEED</b></td> <td>${formatSpeedMnemonic(data['water speed'])}</td></tr>`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if(data['air speed']){
 | 
				
			||||||
 | 
					        profileHTML += `<tr><td><b>AIR SPEED</b></td> <td>${formatSpeedMnemonic(data['air speed'])}</td></tr>`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    profileHTML += '</table>';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    profile.innerHTML = profileHTML;
 | 
				
			||||||
 | 
					    return profile;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								web/assets/js/encounter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					import {loadingGif, setResultImage} from "./loading.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {setCreatureTable} from "./setCreatureTable.js";
 | 
				
			||||||
 | 
					import {androidResultTable} from "./androidResultTable.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					document.getElementById('terrainForm').addEventListener('submit', function (event) {
 | 
				
			||||||
 | 
					    event.preventDefault();
 | 
				
			||||||
 | 
					    const terrain = document.getElementById('terrainType').value;
 | 
				
			||||||
 | 
					    const queryParams = new URLSearchParams({
 | 
				
			||||||
 | 
					        terrain: terrain,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Insert the loading.gif before making the fetch request
 | 
				
			||||||
 | 
					    let resultSection = document.getElementById('resultSection');
 | 
				
			||||||
 | 
					    let imgElement = loadingGif(resultSection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					        fetch(`${window.BASE_URL}/gameplay/encounter?${queryParams}`)
 | 
				
			||||||
 | 
					            .then((response) => {
 | 
				
			||||||
 | 
					                if (!response.ok) {
 | 
				
			||||||
 | 
					                    throw response;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return response.json(); // we only get here if there is no error
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then((json) => {
 | 
				
			||||||
 | 
					                resultSection.innerHTML = ''; // Clear previous content
 | 
				
			||||||
 | 
					                if (Object.keys(json).length === 1) { // Short version of response
 | 
				
			||||||
 | 
					                    let name = json.name !== null ? json.name : 'No Encounter';
 | 
				
			||||||
 | 
					                    setResultImage(name);
 | 
				
			||||||
 | 
					                } else { // Long version of the response
 | 
				
			||||||
 | 
					                    if (json.name === 'android') {
 | 
				
			||||||
 | 
					                        androidResultTable(json, json.name);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        setCreatureTable(json, json.name);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch((err) => {
 | 
				
			||||||
 | 
					                err.text().then(() => {
 | 
				
			||||||
 | 
					                    imgElement.src = '/assets/img/404.jpg';
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										5
									
								
								web/assets/js/formatDiceMnemonic.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					export function formatDiceMnemonic(data) {
 | 
				
			||||||
 | 
					    return Array.isArray(data) ?
 | 
				
			||||||
 | 
					        data[0] + "d" + data[1] + (data[2] === 0 ? "" : (data[2] > 0 ? "+" : "") + data[2]) :
 | 
				
			||||||
 | 
					        data.toString();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								web/assets/js/formatSpeedMnemonic.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					export function formatSpeedMnemonic(data){
 | 
				
			||||||
 | 
					    if (data[0] === 0 && data[1] === 0 && data[2] === 0){
 | 
				
			||||||
 | 
					        return "Immobile";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (data[0] === 1 && data[1] === 1 && data[2] === 1) {
 | 
				
			||||||
 | 
					        return "See Description"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return data[0] + '/' + data[1] + '/' + data[2];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,9 +3,9 @@ export function loadingGif(resultSection) {
 | 
				
			|||||||
    // Insert the loading.gif before making the fetch request
 | 
					    // Insert the loading.gif before making the fetch request
 | 
				
			||||||
    resultSection.innerHTML = '';
 | 
					    resultSection.innerHTML = '';
 | 
				
			||||||
    let imgElement = document.createElement('img');
 | 
					    let imgElement = document.createElement('img');
 | 
				
			||||||
    imgElement.src = 'img/checking.gif';
 | 
					    imgElement.src = `/assets/img/checking.gif`;
 | 
				
			||||||
    imgElement.style.width = '500px';
 | 
					    imgElement.style.width = '275px';
 | 
				
			||||||
    imgElement.style.height = '500px';
 | 
					    imgElement.style.height = '275px';
 | 
				
			||||||
    imgElement.style.display = 'block';
 | 
					    imgElement.style.display = 'block';
 | 
				
			||||||
    imgElement.style.marginLeft = 'auto';
 | 
					    imgElement.style.marginLeft = 'auto';
 | 
				
			||||||
    imgElement.style.marginRight = 'auto';
 | 
					    imgElement.style.marginRight = 'auto';
 | 
				
			||||||
@ -15,10 +15,10 @@ export function loadingGif(resultSection) {
 | 
				
			|||||||
export function setResultImage(document, name) {
 | 
					export function setResultImage(document, name) {
 | 
				
			||||||
    let imgElement = document.createElement('img');
 | 
					    let imgElement = document.createElement('img');
 | 
				
			||||||
    let resultSection = document.getElementById('resultSection');
 | 
					    let resultSection = document.getElementById('resultSection');
 | 
				
			||||||
    imgElement.src = 'img/' + name + ".jpg";
 | 
					    imgElement.src = `/assets/img/` + name + ".jpg";
 | 
				
			||||||
    console.log(imgElement.src);
 | 
					    console.log(imgElement.src);
 | 
				
			||||||
    imgElement.onerror = function () {
 | 
					    imgElement.onerror = function () {
 | 
				
			||||||
        this.src = 'img/404.jpg';
 | 
					        this.src = `/assets/img/404.jpg`;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    resultSection.appendChild(imgElement);
 | 
					    resultSection.appendChild(imgElement);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								web/assets/js/setCreatureTable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import {createProfileSection} from "./createProfileSection.js";
 | 
				
			||||||
 | 
					import {createAbilitiesSection} from "./createAbilitiesSection.js";
 | 
				
			||||||
 | 
					import {createAttacksSection} from "./createAttacksSection.js";
 | 
				
			||||||
 | 
					import {createMutationsSection} from "./createMutationsSection.js";
 | 
				
			||||||
 | 
					import {createDescriptionSection} from "./createDescriptionSection.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function setCreatureTable(data, creatureName) {
 | 
				
			||||||
 | 
					    let container = document.createElement('div');
 | 
				
			||||||
 | 
					    container.className = 'container';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Creature ID section
 | 
				
			||||||
 | 
					    let creatureId = document.createElement('div');
 | 
				
			||||||
 | 
					    creatureId.className = 'creature_id';
 | 
				
			||||||
 | 
					    creatureId.innerHTML = `
 | 
				
			||||||
 | 
					                <h2>${creatureName.toUpperCase()}</h2>
 | 
				
			||||||
 | 
					                <img src='/assets/img/${creatureName}.jpg' onerror='this.src="/assets/img/404.jpg";' style='width: 275px; height: 275px;'>
 | 
				
			||||||
 | 
					            `;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let profile = createProfileSection(data);
 | 
				
			||||||
 | 
					    let abilities = createAbilitiesSection(data);
 | 
				
			||||||
 | 
					    let attacks = createAttacksSection(data);
 | 
				
			||||||
 | 
					    let mutations = createMutationsSection(data.mutations); // Notice the data difference
 | 
				
			||||||
 | 
					    let description = createDescriptionSection(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    container.appendChild(creatureId);
 | 
				
			||||||
 | 
					    container.appendChild(profile);
 | 
				
			||||||
 | 
					    container.appendChild(abilities);
 | 
				
			||||||
 | 
					    container.appendChild(attacks);
 | 
				
			||||||
 | 
					    container.appendChild(mutations);
 | 
				
			||||||
 | 
					    container.appendChild(description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resultSection.appendChild(container);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								web/assets/js/setResultImage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					export function setResultImage(name) {
 | 
				
			||||||
 | 
					    let imgElement = document.createElement('img');
 | 
				
			||||||
 | 
					    imgElement.src = '/assets/img/' + name + ".jpg";
 | 
				
			||||||
 | 
					    console.log(imgElement.src);
 | 
				
			||||||
 | 
					    imgElement.onerror = function () {
 | 
				
			||||||
 | 
					        this.src = '/assets/img/404.jpg';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    resultSection.appendChild(imgElement);
 | 
				
			||||||
 | 
					    return imgElement;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,98 +0,0 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html lang="en">
 | 
					 | 
				
			||||||
<head>
 | 
					 | 
				
			||||||
    <meta charset="UTF-8">
 | 
					 | 
				
			||||||
    <link rel="stylesheet" type="text/css" href="styles.css">
 | 
					 | 
				
			||||||
    <style>
 | 
					 | 
				
			||||||
        #resultSection {
 | 
					 | 
				
			||||||
            font-family: Arial, sans-serif;
 | 
					 | 
				
			||||||
            font-size: 14pt;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .nickname {
 | 
					 | 
				
			||||||
            background-color: #abf1f1;
 | 
					 | 
				
			||||||
            border-style: solid;
 | 
					 | 
				
			||||||
            border-width: 1px;
 | 
					 | 
				
			||||||
            font-weight: bold;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .house-note{
 | 
					 | 
				
			||||||
            background-color: rgba(246, 246, 167, 0.93);
 | 
					 | 
				
			||||||
            font-style: italic;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .container {
 | 
					 | 
				
			||||||
            display: grid;
 | 
					 | 
				
			||||||
            grid-template-columns: 1.1fr 1fr 0.9fr;
 | 
					 | 
				
			||||||
            grid-template-rows: 1.2fr 0.5fr 1.3fr;
 | 
					 | 
				
			||||||
            gap: 0px 0px;
 | 
					 | 
				
			||||||
            grid-auto-flow: row;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .container.android {
 | 
					 | 
				
			||||||
            display: flex;
 | 
					 | 
				
			||||||
            flex-direction: column;
 | 
					 | 
				
			||||||
            gap: 20px;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Container for each type (thinker, worker, warrior) */
 | 
					 | 
				
			||||||
        .typeContainer {
 | 
					 | 
				
			||||||
            display: flex; /* Use flexbox for layout */
 | 
					 | 
				
			||||||
            justify-content: space-between; /* Space out the child elements evenly */
 | 
					 | 
				
			||||||
            margin-bottom: 20px; /* Add some bottom margin for separation between types */
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Profile and abilities within each type */
 | 
					 | 
				
			||||||
        .creature_id,
 | 
					 | 
				
			||||||
        .creature_profile,
 | 
					 | 
				
			||||||
        .creature_abilities {
 | 
					 | 
				
			||||||
            width: 45%; /* Give them each about half the container's width */
 | 
					 | 
				
			||||||
            height: 345px;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .creature_attacks {
 | 
					 | 
				
			||||||
            width: 40%;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .creature_mutations {
 | 
					 | 
				
			||||||
            width: 60%;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .creature_description {
 | 
					 | 
				
			||||||
            width: 90%;
 | 
					 | 
				
			||||||
            margin-top: 5px;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .creature_id          { grid-area: 1 / 1 / 2 / 2; }
 | 
					 | 
				
			||||||
        .creature_profile     { grid-area: 1 / 2 / 2 / 3; }
 | 
					 | 
				
			||||||
        .creature_abilities   { grid-area: 1 / 3 / 2 / 4; }
 | 
					 | 
				
			||||||
        .creature_attacks     { grid-area: 2 / 1 / 3 / 4; }
 | 
					 | 
				
			||||||
        .creature_mutations   { grid-area: 2 / 2 / 3 / 2; }
 | 
					 | 
				
			||||||
        .creature_description { grid-area: 3 / 1 / 4 / 4; }
 | 
					 | 
				
			||||||
    </style>
 | 
					 | 
				
			||||||
    <title>Gamma World Bestiary</title>
 | 
					 | 
				
			||||||
    <script src="config.js"></script>
 | 
					 | 
				
			||||||
    <script type="module" src="bestiary.js" defer></script>
 | 
					 | 
				
			||||||
    <script type="module" src="catalog.js" defer></script>
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
<h2>Look Up A Creature</h2>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<form id="searchForm">
 | 
					 | 
				
			||||||
    <div class="form-row">
 | 
					 | 
				
			||||||
        <div class="form-field">
 | 
					 | 
				
			||||||
            <label for="creature">Beast</label>
 | 
					 | 
				
			||||||
            <input type="string" name="creature" id="creature">
 | 
					 | 
				
			||||||
            <button id="search-button" type="submit">Search</button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div class="form-field">
 | 
					 | 
				
			||||||
            <label for="catalog-button">Retrieve Catalog</label>
 | 
					 | 
				
			||||||
            <button id="catalog-button" type="button">Catalog</button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</form>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<hr/>
 | 
					 | 
				
			||||||
<div id="resultSection"></div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
							
								
								
									
										226
									
								
								web/bestiary.js
									
									
									
									
									
								
							
							
						
						@ -1,226 +0,0 @@
 | 
				
			|||||||
import {loadingGif} from "./loading.js";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
document.getElementById('searchForm').addEventListener('submit', function (event) {
 | 
					 | 
				
			||||||
    event.preventDefault();
 | 
					 | 
				
			||||||
    const creatureName = document.getElementById('creature').value;
 | 
					 | 
				
			||||||
    const queryParams = new URLSearchParams({
 | 
					 | 
				
			||||||
        creature: creatureName,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Insert the loading.gif before making the fetch request
 | 
					 | 
				
			||||||
    let resultSection = document.getElementById('resultSection');
 | 
					 | 
				
			||||||
    let imgElement = loadingGif(resultSection);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    setTimeout(() => {
 | 
					 | 
				
			||||||
        fetch(`${window.BASE_URL}/rules/creature?${queryParams}`)
 | 
					 | 
				
			||||||
            .then((response) => {
 | 
					 | 
				
			||||||
                if (!response.ok) {
 | 
					 | 
				
			||||||
                    throw response;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return response.json(); // we only get here if there is no error
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .then((json) => {
 | 
					 | 
				
			||||||
                if (json === null) { // if json is null update the image and stop execution
 | 
					 | 
				
			||||||
                    imgElement.src = 'img/404.jpg';
 | 
					 | 
				
			||||||
                    throw new Error('No data found'); // this will stop the execution and go to the catch block
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                resultSection.innerHTML = ''; // Clear previous content
 | 
					 | 
				
			||||||
                if (creatureName === 'android') {
 | 
					 | 
				
			||||||
                    androidResultTable(json);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    setCreatureTable(json);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .catch((err) => {
 | 
					 | 
				
			||||||
                console.log(err);
 | 
					 | 
				
			||||||
                if(!resultSection.hasChildNodes()) { // Only update the image if it wasn't already updated
 | 
					 | 
				
			||||||
                    imgElement.src = 'img/404.jpg';
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function setResultImage(name) {
 | 
					 | 
				
			||||||
            let imgElement = document.createElement('img');
 | 
					 | 
				
			||||||
            imgElement.src = 'img/' + name + ".jpg";
 | 
					 | 
				
			||||||
            console.log(imgElement.src);
 | 
					 | 
				
			||||||
            imgElement.onerror = function () {
 | 
					 | 
				
			||||||
                this.src = 'img/404.jpg';
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
            resultSection.appendChild(imgElement);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function formatDiceMnemonic(data) {
 | 
					 | 
				
			||||||
            return Array.isArray(data) ?
 | 
					 | 
				
			||||||
                data[0] + "d" + data[1] + (data[2] === 0 ? "" : (data[2] > 0 ? "+" : "") + data[2]) :
 | 
					 | 
				
			||||||
                data.toString();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function formatSpeedMnemonic(data){
 | 
					 | 
				
			||||||
            if (data[0] === 0 && data[1] === 0 && data[2] === 0){
 | 
					 | 
				
			||||||
                return "Immobile";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (data[0] === 1 && data[1] === 1 && data[2] === 1) {
 | 
					 | 
				
			||||||
                return "See Description"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return data[0] + '/' + data[1] + '/' + data[2];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function androidResultTable(data) {
 | 
					 | 
				
			||||||
            let container = document.createElement('div');
 | 
					 | 
				
			||||||
            container.className = 'container android';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let creatureTitle = document.createElement('h2');
 | 
					 | 
				
			||||||
            creatureTitle.textContent = creatureName.toUpperCase();
 | 
					 | 
				
			||||||
            container.appendChild(creatureTitle)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let image = document.createElement('img');
 | 
					 | 
				
			||||||
            image.src = 'img/android.jpg';
 | 
					 | 
				
			||||||
            image.onerror = () => { image.src = 'img/404.jpg' };
 | 
					 | 
				
			||||||
            image.style.width = '275px';
 | 
					 | 
				
			||||||
            image.style.height = '275px';
 | 
					 | 
				
			||||||
            container.appendChild(image);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let description = createDescriptionSection(data);
 | 
					 | 
				
			||||||
            container.appendChild(description);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Object.entries(data).forEach(([key, value]) => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (key === 'thinker' || key === 'worker' || key === 'warrior') {
 | 
					 | 
				
			||||||
                    let typeTitle = document.createElement('h2');
 | 
					 | 
				
			||||||
                    typeTitle.textContent = key.toUpperCase();
 | 
					 | 
				
			||||||
                    container.appendChild(typeTitle);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Create a div for each type (thinker, worker, or warrior)
 | 
					 | 
				
			||||||
                    let typeContainer = document.createElement('div');
 | 
					 | 
				
			||||||
                    typeContainer.className = 'typeContainer'; // we'll use this in css
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    let profile = createProfileSection(value);
 | 
					 | 
				
			||||||
                    let abilities = createAbilitiesSection(value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Append profile and abilities to the typeContainer, instead of the main container
 | 
					 | 
				
			||||||
                    typeContainer.appendChild(profile);
 | 
					 | 
				
			||||||
                    typeContainer.appendChild(abilities);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // Finally, append the typeContainer to the main container.
 | 
					 | 
				
			||||||
                    container.appendChild(typeContainer);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            resultSection.appendChild(container);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function createProfileSection(data) {
 | 
					 | 
				
			||||||
            let profile = document.createElement('div');
 | 
					 | 
				
			||||||
            profile.className = 'creature_profile';
 | 
					 | 
				
			||||||
            let profileHTML = `
 | 
					 | 
				
			||||||
          <h3>Profile</h3>       
 | 
					 | 
				
			||||||
          <table>
 | 
					 | 
				
			||||||
              <tr><td><b>NUMBER</b></td> <td>${formatDiceMnemonic(data.number)}</td></tr>
 | 
					 | 
				
			||||||
              <tr><td><b>MORALE</b></td> <td>${formatDiceMnemonic(data.morale)}</td></tr>
 | 
					 | 
				
			||||||
              <tr><td><b>HIT DICE</b></td> <td>${formatDiceMnemonic(data['hit dice'])}</td></tr>
 | 
					 | 
				
			||||||
              <tr><td><b>ARMOUR</b></td> <td>${data.armour}</td></tr>
 | 
					 | 
				
			||||||
              <tr><td><b>ENVIRON</b></td> <td>${data.environ.join(', ')}</td></tr>
 | 
					 | 
				
			||||||
            `;
 | 
					 | 
				
			||||||
            if(data['land speed']){
 | 
					 | 
				
			||||||
                profileHTML += `<tr><td><b>LAND SPEED</b></td> <td>${formatSpeedMnemonic(data['land speed'])}</td></tr>`;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(data['water speed']){
 | 
					 | 
				
			||||||
                profileHTML += `<tr><td><b>WATER SPEED</b></td> <td>${formatSpeedMnemonic(data['water speed'])}</td></tr>`;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(data['air speed']){
 | 
					 | 
				
			||||||
                profileHTML += `<tr><td><b>AIR SPEED</b></td> <td>${formatSpeedMnemonic(data['air speed'])}</td></tr>`;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            profileHTML += '</table>';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            profile.innerHTML = profileHTML;
 | 
					 | 
				
			||||||
            return profile;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function createAbilitiesSection(data) {
 | 
					 | 
				
			||||||
            // Abilities section
 | 
					 | 
				
			||||||
            let abilities = document.createElement('div');
 | 
					 | 
				
			||||||
            abilities.className = 'creature_abilities';
 | 
					 | 
				
			||||||
            abilities.innerHTML = `
 | 
					 | 
				
			||||||
              <h3>Abilities</h3>
 | 
					 | 
				
			||||||
              <table>
 | 
					 | 
				
			||||||
                  <tr><td><b>MS</b></td> <td>${formatDiceMnemonic(data.ms)}</td></tr>
 | 
					 | 
				
			||||||
                  <tr><td><b>IN</b></td> <td>${formatDiceMnemonic(data.in)}</td></tr>
 | 
					 | 
				
			||||||
                  <tr><td><b>DX</b></td> <td>${formatDiceMnemonic(data.dx)}</td></tr>
 | 
					 | 
				
			||||||
                  <tr><td><b>CH</b></td> <td>${formatDiceMnemonic(data.ch)}</td></tr>
 | 
					 | 
				
			||||||
                  <tr><td><b>CN</b></td> <td>${formatDiceMnemonic(data.cn)}</td></tr>
 | 
					 | 
				
			||||||
                  <tr><td><b>PS</b></td> <td>${formatDiceMnemonic(data.ps)}</td></tr>
 | 
					 | 
				
			||||||
              </table>
 | 
					 | 
				
			||||||
            `;
 | 
					 | 
				
			||||||
            return abilities;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function createAttacksSection(data) {
 | 
					 | 
				
			||||||
            // Attacks section
 | 
					 | 
				
			||||||
            let attacks = document.createElement('div');
 | 
					 | 
				
			||||||
            attacks.className = 'creature_attacks';
 | 
					 | 
				
			||||||
            let attacksHTML = '<h3>Attacks</h3>';
 | 
					 | 
				
			||||||
            let attacksTable = '<table>';
 | 
					 | 
				
			||||||
            for (let attack in data.attacks) {
 | 
					 | 
				
			||||||
                let mnemonic_display;
 | 
					 | 
				
			||||||
                mnemonic_display = formatDiceMnemonic(data.attacks[attack]);
 | 
					 | 
				
			||||||
                if (mnemonic_display === "0d0") {
 | 
					 | 
				
			||||||
                    mnemonic_display = 'See Description';
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                attacksTable += `<tr><td><b>${attack}</b></td><td>${mnemonic_display}</td></tr>`
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            attacksTable += '</table>';
 | 
					 | 
				
			||||||
            attacks.innerHTML = attacksHTML + attacksTable;
 | 
					 | 
				
			||||||
            return attacks
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function createMutationsSection(mutarray) {
 | 
					 | 
				
			||||||
            // Mutations section
 | 
					 | 
				
			||||||
            let mutations = document.createElement('div');
 | 
					 | 
				
			||||||
            mutations.className = 'creature_mutations';
 | 
					 | 
				
			||||||
            let mutationsHTML = '<h3>Mutations</h3>';
 | 
					 | 
				
			||||||
            let mutationsList = mutarray.reduce((result, mutation) => result + `<li>${mutation}</li>`, '');
 | 
					 | 
				
			||||||
            mutationsHTML += `<ul>${mutationsList}</ul>`;
 | 
					 | 
				
			||||||
            mutations.innerHTML = mutationsHTML
 | 
					 | 
				
			||||||
            return mutations
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function createDescriptionSection(data) {
 | 
					 | 
				
			||||||
            // Description section
 | 
					 | 
				
			||||||
            let description = document.createElement('div');
 | 
					 | 
				
			||||||
            description.className = 'creature_description';
 | 
					 | 
				
			||||||
            let descriptionHTML = `
 | 
					 | 
				
			||||||
              <h3>Description</h3>
 | 
					 | 
				
			||||||
              ${data.description}
 | 
					 | 
				
			||||||
            `;
 | 
					 | 
				
			||||||
            description.innerHTML = descriptionHTML;
 | 
					 | 
				
			||||||
            return description;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        function setCreatureTable(data) {
 | 
					 | 
				
			||||||
            let container = document.createElement('div');
 | 
					 | 
				
			||||||
            container.className = 'container';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Creature ID section
 | 
					 | 
				
			||||||
            let creatureId = document.createElement('div');
 | 
					 | 
				
			||||||
            creatureId.className = 'creature_id';
 | 
					 | 
				
			||||||
            creatureId.innerHTML = `
 | 
					 | 
				
			||||||
                <h2>${creatureName.toUpperCase()}</h2>
 | 
					 | 
				
			||||||
                <img src='img/${creatureName}.jpg' onerror='this.src="img/404.jpg";' style='width: 275px; height: 275px;'>
 | 
					 | 
				
			||||||
            `;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let profile = createProfileSection(data);
 | 
					 | 
				
			||||||
            let abilities = createAbilitiesSection(data);
 | 
					 | 
				
			||||||
            let attacks = createAttacksSection(data);
 | 
					 | 
				
			||||||
            let mutations = createMutationsSection(data.mutations); // Notice the data difference
 | 
					 | 
				
			||||||
            let description = createDescriptionSection(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            container.appendChild(creatureId);
 | 
					 | 
				
			||||||
            container.appendChild(profile);
 | 
					 | 
				
			||||||
            container.appendChild(abilities);
 | 
					 | 
				
			||||||
            container.appendChild(attacks);
 | 
					 | 
				
			||||||
            container.appendChild(mutations);
 | 
					 | 
				
			||||||
            container.appendChild(description);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            resultSection.appendChild(container);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }, 1000);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||