ENH: Initiative and licensing
							parent
							
								
									83a1c7b717
								
							
						
					
					
						commit
						f8265fc4ed
					
				
							
								
								
									
										11
									
								
								README.md
								
								
								
								
							
							
						
						
									
										11
									
								
								README.md
								
								
								
								
							|  | @ -1,11 +1,16 @@ | |||
| # Old School Essentials System for Foundry VTT | ||||
| 
 | ||||
| ## Installation | ||||
| You can now find this Foundry VTT game system within Foundry VTT in the system browser. | ||||
| 
 | ||||
| ## License | ||||
| Old-School Essentials is a trademark of Necrotic Gnome.  | ||||
| This Foundry VTT system requires Old-School Essentials Core Rules and does not contain any copyrighted material. | ||||
| This Foundry VTT system requires Old-School Essentials Core Rules that you can find here [here](https://necroticgnome.com). | ||||
| 
 | ||||
| This third party product is not affiliated with or approved by Necrotic Gnome. | ||||
| Old-School Essentials is a trademark of Necrotic Gnome.The trademark and Old-School Essentials logo are used with permission of Necrotic Gnome, under license | ||||
| 
 | ||||
| ## Contributions | ||||
| This system is currently under heavy development. | ||||
| This system is currently in Beta. | ||||
| Feel free to grab a TO DO issue from the gitlab board. You can then do a merge request on the `development` branch. | ||||
| 
 | ||||
| [](https://ko-fi.com/H2H21WMKA) | ||||
|  | @ -72,6 +72,7 @@ | |||
|     "OSE.HitDice": "Hit Dice", | ||||
|     "OSE.HitDiceShort": "HD", | ||||
|     "OSE.Movement": "Movement Rate", | ||||
|     "OSE.MovementDetails": "Movement Details", | ||||
|     "OSE.MovementEncounter": "Encounter Movement Rate", | ||||
|     "OSE.MovementEncounterShort": "En", | ||||
|     "OSE.MovementOverland": "Overland Movement Rate", | ||||
|  | @ -197,5 +198,13 @@ | |||
|     "OSE.messages.AttackFailure": "<b>Attack fails</b> ({bonus})", | ||||
|     "OSE.messages.InflictsDamage": "Inflicts damage!", | ||||
|     "OSE.ChatContextDamage": "Apply Damage", | ||||
|     "OSE.ChatContextHealing": "Apply Healing" | ||||
|     "OSE.ChatContextHealing": "Apply Healing", | ||||
| 
 | ||||
|     "OSE.colors.green": "Green", | ||||
|     "OSE.colors.red": "Red", | ||||
|     "OSE.colors.yellow": "Yellow", | ||||
|     "OSE.colors.purple": "Purple", | ||||
|     "OSE.colors.blue": "Blue", | ||||
|     "OSE.colors.orange": "Orange", | ||||
|     "OSE.colors.white": "White" | ||||
| } | ||||
|  | @ -110,7 +110,9 @@ export class OseActorSheetCharacter extends OseActorSheet { | |||
| 
 | ||||
|   _calculateMovement(data, weight) { | ||||
|     if (data.config.encumbrance == "detailed") { | ||||
|       if (weight > 800) { | ||||
|       if (weight > data.encumbrance.max) { | ||||
|         data.data.movement.base = 0; | ||||
|       } else if (weight > 800) { | ||||
|         data.data.movement.base = 30; | ||||
|       } else if (weight > 600) { | ||||
|         data.data.movement.base = 60; | ||||
|  |  | |||
|  | @ -80,7 +80,6 @@ export class OseActorSheetMonster extends OseActorSheet { | |||
|   } | ||||
| 
 | ||||
|   async _onCountChange(event) { | ||||
|     console.log("CHANGE", event); | ||||
|     event.preventDefault(); | ||||
|     const itemId = event.currentTarget.closest(".item").dataset.itemId; | ||||
|     const item = this.actor.getOwnedItem(itemId); | ||||
|  |  | |||
|  | @ -0,0 +1,85 @@ | |||
| import { OseDice } from "./dice.js"; | ||||
| 
 | ||||
| export class OseCombat { | ||||
|   static rollInitiative(combat, data, diff, id) { | ||||
|     // Check groups
 | ||||
|     data.combatants = []; | ||||
|     let groups = {}; | ||||
|     combat.data.combatants.forEach((cbt) => { | ||||
|       groups[cbt.flags.ose.group] = {present: true}; | ||||
|       data.combatants.push(cbt); | ||||
|     }); | ||||
|      | ||||
|     // Roll init
 | ||||
|     Object.keys(groups).forEach((group) => { | ||||
|         let roll = new Roll("1d6").roll(); | ||||
|         roll.toMessage({flavor: `${CONFIG.OSE.colors[group]} group rolls initiative`}); | ||||
|         groups[group].initiative = roll.total; | ||||
|     }) | ||||
|      | ||||
|     // Set init
 | ||||
|     for (let i = 0; i < data.combatants.length; ++i) { | ||||
|         data.combatants[i].initiative = groups[data.combatants[i].flags.ose.group].initiative; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static format(object, html, user) { | ||||
|     html.find('.combat-control[data-control="rollNPC"]').remove(); | ||||
|     html.find('.combat-control[data-control="rollAll"]').remove(); | ||||
|     html.find(".combatant").each((_, ct) => { | ||||
|       // Can't roll individual inits
 | ||||
|       $(ct).find(".roll").remove(); | ||||
| 
 | ||||
|       // Get group color
 | ||||
|       let cmbtant = object.combat.getCombatant(ct.dataset.combatantId); | ||||
|       let color = cmbtant.flags.ose.group; | ||||
| 
 | ||||
|       // Append colored flag
 | ||||
|       let controls = $(ct).find(".combatant-controls"); | ||||
|       controls.prepend( | ||||
|         `<a class='combatant-control flag' style='color:${color}' title="${CONFIG.OSE.colors[color]}"><i class='fas fa-flag'></i></a>` | ||||
|       ); | ||||
|     }); | ||||
|     OseCombat.addListeners(html); | ||||
|   } | ||||
| 
 | ||||
|   static addListeners(html) { | ||||
|     // Cycle through colors
 | ||||
|     html.find(".combatant-control.flag").click((ev) => { | ||||
|       let currentColor = ev.currentTarget.style.color; | ||||
|       let colors = Object.keys(CONFIG.OSE.colors); | ||||
|       let index = colors.indexOf(currentColor); | ||||
|       if (index + 1 == colors.length) { | ||||
|         index = 0; | ||||
|       } else { | ||||
|         index++; | ||||
|       } | ||||
|       let id = $(ev.currentTarget).closest(".combatant")[0].dataset.combatantId; | ||||
|       game.combat.updateCombatant({ | ||||
|         _id: id, | ||||
|         flags: { ose: { group: colors[index] } }, | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   static addCombatant(combat, data, options, id) { | ||||
|     let token = canvas.tokens.get(data.tokenId); | ||||
|     let color = "black"; | ||||
|     switch (token.data.disposition) { | ||||
|       case -1: | ||||
|         color = "red"; | ||||
|         break; | ||||
|       case 0: | ||||
|         color = "yellow"; | ||||
|         break; | ||||
|       case 1: | ||||
|         color = "green"; | ||||
|         break; | ||||
|     } | ||||
|     data.flags = { | ||||
|       ose: { | ||||
|         group: color, | ||||
|       }, | ||||
|     }; | ||||
|   } | ||||
| } | ||||
|  | @ -26,5 +26,14 @@ export const OSE = { | |||
|     light: "OSE.armor.light", | ||||
|     heavy: "OSE.armor.heavy", | ||||
|     shield: "OSE.armor.shield", | ||||
|   }, | ||||
|   colors: { | ||||
|     green: "OSE.colors.green", | ||||
|     red: "OSE.colors.red", | ||||
|     yellow: "OSE.colors.yellow", | ||||
|     purple: "OSE.colors.purple", | ||||
|     blue: "OSE.colors.blue", | ||||
|     orange: "OSE.colors.orange", | ||||
|     white: "OSE.colors.white" | ||||
|   } | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										41
									
								
								src/ose.js
								
								
								
								
							
							
						
						
									
										41
									
								
								src/ose.js
								
								
								
								
							|  | @ -10,6 +10,7 @@ import { registerSettings } from "./module/settings.js"; | |||
| import { registerHelpers } from "./module/helpers.js"; | ||||
| import * as chat from "./module/chat.js"; | ||||
| import * as macros from "./module/macros.js"; | ||||
| import { OseCombat } from "./module/combat.js"; | ||||
| 
 | ||||
| /* -------------------------------------------- */ | ||||
| /*  Foundry VTT Initialization                  */ | ||||
|  | @ -61,7 +62,7 @@ Hooks.once("init", async function () { | |||
|  */ | ||||
| Hooks.once("setup", function () { | ||||
|   // Localize CONFIG objects once up-front
 | ||||
|   const toLocalize = ["saves_short", "saves_long", "scores", "armor"]; | ||||
|   const toLocalize = ["saves_short", "saves_long", "scores", "armor", "colors"]; | ||||
|   for (let o of toLocalize) { | ||||
|     CONFIG.OSE[o] = Object.entries(CONFIG.OSE[o]).reduce((obj, e) => { | ||||
|       obj[e[0]] = game.i18n.localize(e[1]); | ||||
|  | @ -74,21 +75,37 @@ Hooks.once("ready", async () => { | |||
|   Hooks.on("hotbarDrop", (bar, data, slot) => | ||||
|     macros.createOseMacro(data, slot) | ||||
|   ); | ||||
|   const template = 'systems/ose/templates/chat/license.html'; | ||||
|   const template = "systems/ose/templates/chat/license.html"; | ||||
|   const html = await renderTemplate(template); | ||||
|   $('#settings .game-system').append(html); | ||||
|   $("#settings .game-system").append(html); | ||||
| }); | ||||
| 
 | ||||
| Hooks.on( | ||||
|   "preUpdateCombat", | ||||
|   async (combat, updateData, options, userId) => { | ||||
|     if (!updateData.round) { | ||||
|       return; | ||||
|     } | ||||
|     if (game.settings.get('ose', 'individualInit')) { | ||||
|     } | ||||
| Hooks.on("preCreateCombatant", (combat, data, options, id) => { | ||||
|   OseCombat.addCombatant(combat, data, options, id); | ||||
| }); | ||||
| 
 | ||||
| Hooks.on("preUpdateCombatant", (combat, combatant, data, diff, id) => { | ||||
|   if (data.initiative) { | ||||
|     let groupInit = data.initiative; | ||||
|     combat.combatants.forEach((ct) => { | ||||
|       if (ct.initiative && ct._id != data._id && ct.flags.ose.group == combatant.flags.ose.group) { | ||||
|         groupInit = ct.initiative; | ||||
|         data.initiative = parseInt(groupInit); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| ); | ||||
| }); | ||||
| 
 | ||||
| Hooks.on("renderCombatTracker", (object, html, data) => { | ||||
|   OseCombat.format(object, html, data); | ||||
| }); | ||||
| 
 | ||||
| Hooks.on("preUpdateCombat", async (combat, data, diff, id) => { | ||||
|   if (!data.round) { | ||||
|     return; | ||||
|   } | ||||
|   OseCombat.rollInitiative(combat, data, diff, id); | ||||
| }); | ||||
| 
 | ||||
| Hooks.on("renderChatLog", (app, html, data) => OseItem.chatListeners(html)); | ||||
| Hooks.on("getChatLogEntryContext", chat.addChatMessageContextOptions); | ||||
|  |  | |||
|  | @ -46,7 +46,8 @@ | |||
|           } | ||||
|         }, | ||||
|         "movement": { | ||||
|           "base": 120 | ||||
|           "base": 120, | ||||
|           "value": "" | ||||
|         }, | ||||
|         "initiative": { | ||||
|           "value": 0, | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ | |||
|             <h4 class="attribute-name box-title" title="{{localize 'OSE.Movement'}}">{{ localize "OSE.MovementShort" }} | ||||
|             </h4> | ||||
|             <div class="attribute-value"> | ||||
|                 <input name="data.movement.value" type="text" value="{{data.movement.value}}" placeholder="0" | ||||
|                 <input name="data.movement.base" type="text" value="{{data.movement.base}}" placeholder="0" | ||||
|                     data-dtype="Number" /> | ||||
|             </div> | ||||
|         </li> | ||||
|  | @ -138,8 +138,8 @@ | |||
|     {{!-- Saving throws --}} | ||||
|     <div class="attribute-group"> | ||||
|         <div class="attacks-description"> | ||||
|             <label>{{ localize "OSE.Attacks" }}</label> | ||||
|             <input name="data.att" type="text" value="{{data.att}}" data-dtype="String" /> | ||||
|             <label>{{ localize "OSE.MovementDetails" }}</label> | ||||
|             <input name="data.movement.value" type="text" value="{{data.movement.value}}" data-dtype="String" /> | ||||
|         </div> | ||||
|         <ul class="attributes"> | ||||
|             <li class="attribute saving-throw" data-save="death"> | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <div class="ose game-license"> | ||||
|   <p class="ose game-license"> | ||||
|     This fan-made system requires requires Old-School Essentials Core Rules that | ||||
|     This fan-made system requires Old-School Essentials Core Rules that | ||||
|     you can find <a href="https://necroticgnome.com">here</a>. | ||||
|   </p> | ||||
|   <p> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue