diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/assets/default/armor.svg b/assets/default/armor.svg new file mode 100644 index 0000000..744d93a --- /dev/null +++ b/assets/default/armor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/herb_or_poison.svg b/assets/default/herb_or_poison.svg new file mode 100644 index 0000000..e6c839c --- /dev/null +++ b/assets/default/herb_or_poison.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/language.svg b/assets/default/language.svg new file mode 100644 index 0000000..6f23946 --- /dev/null +++ b/assets/default/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/skill.svg b/assets/default/skill.svg new file mode 100644 index 0000000..7c14647 --- /dev/null +++ b/assets/default/skill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/skill_category.svg b/assets/default/skill_category.svg new file mode 100644 index 0000000..cfa29a4 --- /dev/null +++ b/assets/default/skill_category.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/spell.svg b/assets/default/spell.svg new file mode 100644 index 0000000..fe3dc5b --- /dev/null +++ b/assets/default/spell.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/transport.svg b/assets/default/transport.svg new file mode 100644 index 0000000..fda2257 --- /dev/null +++ b/assets/default/transport.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/default/weapon.svg b/assets/default/weapon.svg new file mode 100644 index 0000000..4321b18 --- /dev/null +++ b/assets/default/weapon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..65e056a --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,18 @@ +var gulp = require('gulp'); +var less = require('gulp.less'); + +gulp.task('less', function (cb) { + gulp + .src('less/rmss.less') + .pipe(less()) + .pipe(gulp.dest("./")); + cb(); +}); + +gulp.task( + 'default', + gulp.series('less', function(cb) { + gulp.watch('less/*.less', gulp.series('less')); + cb(); + }) +); \ No newline at end of file diff --git a/lang/en.json b/lang/en.json new file mode 100644 index 0000000..721dad9 --- /dev/null +++ b/lang/en.json @@ -0,0 +1,265 @@ +{ + "rmss": { + "player_character": { + "name": "Name:", + "level": "Level:", + "experience": "XP:", + "resources": { + "hits": "Hits", + "exhaustion_points": "Exhaustion Points", + "power_points": "Power Points" + }, + "attribute_headers": { + "stat": "Stat", + "temp": "Temp", + "pot": "Potential", + "basic_bonus": "Basic Bonus", + "racial_bonus": "Racial Bonus", + "special_bonus": "Special Bonus", + "stat_bonus": "Stat Bonus" + }, + "attribute": { + "agility": "Agility", + "agility_short": "Ag", + "constitution": "Constitution", + "memory": "Memory", + "reasoning": "Reasoning", + "self_discipline": "Self Discipline", + "empathy": "Empathy", + "intuition": "Intuition", + "presence": "Presence", + "quickness": "Quickness", + "strength": "Strength", + "stat_total": "Total" + } + }, + "pc_sheet": { + "import_skillcat": "Import" + }, + "pc_sheet_tabs": { + "record": "Record", + "skill_categories": "Skill Categories", + "skills": "Skills", + "equipment": "Equipment", + "spells": "Spells", + "status_record": "Status Record", + "experience_points": "Experience Points" + }, + "pc_sheet_fixed_info": { + "race": "Race:", + "profession": "Profession:", + "training_packages": "Training Packages:", + "realm": "Realm:" + }, + "pc_sheet_armor_info": { + "armor_type": "Armor Type:", + "mmp": "MMP:", + "weight_penalty": "Weight Penalty:", + "missile_penalty": "Missile Penalty:", + "quickness_penalty": "Quickness Penalty:", + "quickness_bonus": "Quickness Bonus:", + "adrenal_defense": "Adrenal Defence:", + "shield_bonus": "Shield Bonus:", + "magic": "Magic (Spells, Items, etc.):", + "total_db": "Total DB:" + }, + "pc_sheet_resistances": { + "channeling": "Channeling", + "essence": "Essence", + "mentalism": "Mentalism", + "chann_ess": "Chann/Ess", + "chann_ment": "Chann/Ment", + "ess_ment": "Ess/Ment", + "arcane": "Arcane", + "poison_disease": "Poison/Disease", + "fear": "Fear" + }, + "pc_sheet_race_stat_fixed_info": { + "soul_departure": "Soul Departs in X Rounds:", + "recovery_multiplier": "Recovery Multiplier:", + "body_dev_progression": "Body Development Progression:", + "pp_dev_progression": "PP Development Progression:", + "recover_hits_per_hour": "Recover X hits/hour resting:", + "recover_hits_per_sleep_cycle": "Recover X hits/sleep cycle:", + "recover_pp_per_hour": "Recover X PP/hour resting:", + "recover_pp_per_sleep_cycle": "Recover X PP/sleep cycle:" + }, + "pc_sheet_role_traits": { + "appearance": "Appearance:", + "sex": "Sex:", + "skin": "Skin:", + "apparent_age": "Apparent Age:", + "actual_age": "Actual Age:", + "height": "Height:", + "weight": "Weight:", + "hair": "Hair:", + "eyes": "Eyes:", + "personality": "Personality:", + "motivations": "Motivations:", + "alignment": "Alignment:" + }, + "pc_sheet_background_info": { + "nationality": "Nationality:", + "home_town": "Home Town:", + "deity": "Deity:", + "patron": "Patron:", + "parents": "Parents:", + "spouse": "Spouse", + "children": "Children:", + "other": "Other:" + }, + "pc_sheet_skills": { + "favorite": "Favorite?", + "skill_name": "Skill Name", + "ranks": "# Ranks", + "new_ranks": "New Ranks", + "rank_bonus": "Rank Bonus", + "category_bonus": "Category Bonus", + "item_bonus": "Item Bonus", + "special_bonus": "Special Bonus", + "total_bonus": "Total Bonus", + "add_skill": "Add Skill" + }, + "pc_sheet_skill_categories": { + "skillcat_name": "Skill Category Name", + "applicable_stats": "Applicable Stats", + "dev_cost": "Dev Cost", + "ranks": "# Ranks", + "new_ranks": "New Ranks", + "rank_bonus": "Rank Bonus", + "stat_bonus": "Stat Bonus", + "prof_bonus": "Prof Bonus", + "special_bonus": "Special Bonus", + "total_bonus": "Total Bonus", + "import_skillcat": "Import Skill Categories" + }, + "pc_sheet_items": { + "equipped": "Equipped", + "worn": "Worn", + "favorite": "Favorite", + "quantity": "Quantity", + "item_name": "Item Name", + "weight": "Weight", + "cost": "Cost", + "add_item": "Add Item" + }, + "pc_sheet_spell": { + "favorite": "Favorite", + "level": "Level", + "name": "Name", + "spell_list": "Spell List", + "area_of_effect": "Area of Effect", + "duration": "Duration", + "range": "Range", + "type": "Type" + }, + "pc_sheet_language": { + "name": "Name", + "spoken": "Spoken", + "written": "Written" + }, + "entity_sheet": { + "spell": "RMSS Spell", + "weapon": "RMSS Weapon", + "item": "RMSS Armor", + "armor": "RMSS Item", + "herb_or_poison": "RMSS Herb or Poison", + "transport": "RMSS Transport", + "skill": "RMSS Skill", + "skill_category": "RMSS Skill Category", + "player_characrer": "RMSS Player Character", + "npc": "RMSS NPC", + "creature": "RMSS Creature" + }, + "currency_type": { + "mp": "Mithril Pieces", + "pp": "Platinum Pieces", + "gp": "Gold Pieces", + "sp": "Silver Pieces", + "bp": "Bronze Pieces", + "cp": "Copper Pieces" + }, + "item": { + "worn": "Worn", + "description": "Other Notes", + "quantity": "Quantity", + "weight": "Weight", + "cost": "Cost", + "prod_time": "Production Time", + "equipped": "Equipped" + }, + "armor": { + "at": "AT", + "weight": "Weight", + "cost": "Cost", + "prod_time": "Production Time" + }, + "weapon": { + "cost": "Cost", + "type": "Type", + "prod_time": "Production Time", + "weight": "Weight", + "breakage_range": "B#s", + "strength": "Str", + "fumble_range": "Fumble", + "equipped": "Equipped" + }, + "herb_or_poison": { + "codes": "Codes", + "weight": "Weight", + "form_and_prep": "Form/Prep", + "cost": "Cost", + "af": "AF" + }, + "transport": { + "cost": "Cost", + "feet_per_round": "ft/rnd", + "miles_per_hour": "mi/hr", + "maneuver": "Man", + "height": "Height", + "weight": "Weight", + "capacity": "Capacity", + "offensive_bonus": "OB" + }, + "spell": { + "favorite": "Favorite", + "spell_list": "Spell List", + "level": "Level", + "area_of_effect": "Area of Effect", + "duration": "Duration", + "range": "Range", + "type": "Type", + "description": "Description" + }, + "skill_category": { + "applicable_stats": "Applicable Stats:", + "development_cost" : "Development Cost:", + "ranks": "Ranks:", + "new_ranks": "New Ranks:", + "rank_bonus": "Rank Bonus:", + "stat_bonus": "Stat Bonus:", + "prof_bonus": "Prof Bonus:", + "special_bonus_1": "Special Bonus 1:", + "special_bonus_2": "Special Bonus 2:", + "total_bonus": "Total Bonus:", + "description": "Description:" + }, + "skill": { + "favorite": "Favorite?", + "ranks": "Ranks:", + "new_ranks": "New Ranks:", + "rank_bonus": "Rank Bonus:", + "category_bonus": "Category Bonus:", + "item_bonus": "Item Bonus:", + "special_bonus_1": "Special Bonus 1:", + "special_bonus_2": "Special Bonus 2:", + "total_bonus": "Total Bonus:", + "description": "Description:" + }, + "language": { + "spoken": "Spoken", + "written": "Written", + "description": "Description" + } + } +} \ No newline at end of file diff --git a/less/actor-sheet.less b/less/actor-sheet.less new file mode 100644 index 0000000..a2c0176 --- /dev/null +++ b/less/actor-sheet.less @@ -0,0 +1,153 @@ +// General Elements + +.container { + display: flex; + } + +// Header CSS + +.actor-icon { + flex-shrink: 1; + } + + +.header-container { + flex-grow: 2; + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.header-text { + display: flex; + flex-direction: row; + justify-content: center; + } + +// Resource Elements in Headers + +.resource-container { + display: flex; + flex-direction: row; + flex-grow: 3; + text-align: -webkit-center; +} + +.resource-container > * { + flex: 1 1 0; +} + +.resource-entry { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.resource-entry input{ + width: 50px; + border: none; +} + +.stat-container { + flex-direction: column; + flex-shrink: 1; + } + +.equipment-container { + flex-direction: column; + flex-grow: 1; + } + +.stat-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.stat-name, .money-name { + width: 75px; + border: none; + font-family: Signika, sans-serif; + font-size: 12px; +} + +.stat-name input { + border: none; +} + +.stat-header { + font-family: Signika, sans-serif; + font-size: 12px; +} + +// Fixed Info CSS + +.fixed-info-container { + flex-grow: 3; + flex-direction: row; + font-family: Signika, sans-serif; + font-size: 12px; +} + +.fixed-info-section { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.armor-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.race-stat-fixed-info-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.role-traits-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.background-info-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.resistance-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +// Debugging + +.red { + background-color: orangered; +} + +.blue { + background-color: lightblue; +} + +.grey { + background-color: lightgrey; +} + +.green { + background-color: lightseagreen; +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-armor.less b/less/actor-sheet/actor-sheet-armor.less new file mode 100644 index 0000000..e65941f --- /dev/null +++ b/less/actor-sheet/actor-sheet-armor.less @@ -0,0 +1,44 @@ +.armor-grid-container { + display: grid; + grid-template-columns: [name] 30% [equipped] 12% [at] 12% [quantity] 12% [weight] 12% [cost] 12% [controls] 10%; +} + +.armor-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} + +.armor-grid-container > div:nth-child(14n+1), +.armor-grid-container > div:nth-child(14n+2), +.armor-grid-container > div:nth-child(14n+3), +.armor-grid-container > div:nth-child(14n+4), +.armor-grid-container > div:nth-child(14n+5), +.armor-grid-container > div:nth-child(14n+6), +.armor-grid-container > div:nth-child(14n+7) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.armor-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-herbs.less b/less/actor-sheet/actor-sheet-herbs.less new file mode 100644 index 0000000..04ad2f1 --- /dev/null +++ b/less/actor-sheet/actor-sheet-herbs.less @@ -0,0 +1,44 @@ +.herbs-grid-container { + display: grid; + grid-template-columns: [name] 30% [quantity] 11% [codes] 12% [af] 12% [weight] 12% [cost] 11% [controls] 12%; +} + +.herbs-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} + +.herbs-grid-container > div:nth-child(14n+1), +.herbs-grid-container > div:nth-child(14n+2), +.herbs-grid-container > div:nth-child(14n+3), +.herbs-grid-container > div:nth-child(14n+4), +.herbs-grid-container > div:nth-child(14n+5), +.herbs-grid-container > div:nth-child(14n+6), +.herbs-grid-container > div:nth-child(14n+7) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.herbs-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-items.less b/less/actor-sheet/actor-sheet-items.less new file mode 100644 index 0000000..e89c01b --- /dev/null +++ b/less/actor-sheet/actor-sheet-items.less @@ -0,0 +1,43 @@ +.items-grid-container { + display: grid; + grid-template-columns: [worn] 10% [name] 30% [quantity] 15% [weight] 15% [cost] 15% [controls] 15%; +} + +.items-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} + +.items-grid-container > div:nth-child(12n+1), +.items-grid-container > div:nth-child(12n+2), +.items-grid-container > div:nth-child(12n+3), +.items-grid-container > div:nth-child(12n+4), +.items-grid-container > div:nth-child(12n+5), +.items-grid-container > div:nth-child(12n+6) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.items-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-money.less b/less/actor-sheet/actor-sheet-money.less new file mode 100644 index 0000000..9403788 --- /dev/null +++ b/less/actor-sheet/actor-sheet-money.less @@ -0,0 +1,9 @@ +.money-column { + flex-direction: column; +} + +.money-container { + flex-direction: column; + flex-shrink: 1; + padding-left: 10px; + } \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-resistances.less b/less/actor-sheet/actor-sheet-resistances.less new file mode 100644 index 0000000..67f83cf --- /dev/null +++ b/less/actor-sheet/actor-sheet-resistances.less @@ -0,0 +1,18 @@ +.resistances-grid-container { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; + display: grid; + grid-template-columns: [Name] 40% [Value] 20% [Race_Mod] 20% [Total] 20%; +} + +.resistances-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.resistance-input { + width: 50% +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-skillcat.less b/less/actor-sheet/actor-sheet-skillcat.less new file mode 100644 index 0000000..c3794e6 --- /dev/null +++ b/less/actor-sheet/actor-sheet-skillcat.less @@ -0,0 +1,49 @@ +.skillcat-grid-container { + display: grid; + grid-template-columns: [skill-category-name] 10% [applicable-stats] 10% [dev-cost] 8% [num-ranks] 8% [new-ranks] 8% [rank-bonus] 8% [stat-bonus] 8% [prof-bonus] 8% [special-bonus-1] 8% [special-bonus-2] 8% [total-bonus] 8% [controls] 8%; +} + +.skillcat-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} + +.skillcat-grid-container > div:nth-child(24n+1), +.skillcat-grid-container > div:nth-child(24n+2), +.skillcat-grid-container > div:nth-child(24n+3), +.skillcat-grid-container > div:nth-child(24n+4), +.skillcat-grid-container > div:nth-child(24n+5), +.skillcat-grid-container > div:nth-child(24n+6), +.skillcat-grid-container > div:nth-child(24n+7), +.skillcat-grid-container > div:nth-child(24n+8), +.skillcat-grid-container > div:nth-child(24n+9), +.skillcat-grid-container > div:nth-child(24n+10), +.skillcat-grid-container > div:nth-child(24n+11), +.skillcat-grid-container > div:nth-child(24n+12) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.skillcat-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-skills.less b/less/actor-sheet/actor-sheet-skills.less new file mode 100644 index 0000000..090627f --- /dev/null +++ b/less/actor-sheet/actor-sheet-skills.less @@ -0,0 +1,48 @@ +.skills-grid-container { + display: grid; + grid-template-columns: [favorite] 9% [skill-name] 11% [num-ranks] 9% [new-ranks] 9% [rank-bonus] 9% [category-bonus] 9% [item-bonus] 9% [special-bonus-1] 9% [special-bonus-2] 9% [total-bonus] 9% [controls] 8%; +} + +.skills-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} + +.skills-grid-container > div:nth-child(22n+1), +.skills-grid-container > div:nth-child(22n+2), +.skills-grid-container > div:nth-child(22n+3), +.skills-grid-container > div:nth-child(22n+4), +.skills-grid-container > div:nth-child(22n+5), +.skills-grid-container > div:nth-child(22n+6), +.skills-grid-container > div:nth-child(22n+7), +.skills-grid-container > div:nth-child(22n+8), +.skills-grid-container > div:nth-child(22n+9), +.skills-grid-container > div:nth-child(22n+10), +.skills-grid-container > div:nth-child(22n+11) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.skills-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-spells.less b/less/actor-sheet/actor-sheet-spells.less new file mode 100644 index 0000000..b75825a --- /dev/null +++ b/less/actor-sheet/actor-sheet-spells.less @@ -0,0 +1,46 @@ +.spell-grid-container { + display: grid; + grid-template-columns: [favorite] 9% [level] 8% [name] 30% [spell_list] 9% [area_of_effect] 9% [duration] 9% [range] 9% [type] 9% [controls] 8%; +} + +.spell-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} + +.spell-grid-container > div:nth-child(18n+1), +.spell-grid-container > div:nth-child(18n+2), +.spell-grid-container > div:nth-child(18n+3), +.spell-grid-container > div:nth-child(18n+4), +.spell-grid-container > div:nth-child(18n+5), +.spell-grid-container > div:nth-child(18n+6), +.spell-grid-container > div:nth-child(18n+7), +.spell-grid-container > div:nth-child(18n+8), +.spell-grid-container > div:nth-child(18n+9) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.spell-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet-weapons.less b/less/actor-sheet/actor-sheet-weapons.less new file mode 100644 index 0000000..91426e9 --- /dev/null +++ b/less/actor-sheet/actor-sheet-weapons.less @@ -0,0 +1,46 @@ +.weapons-grid-container { + display: grid; + grid-template-columns: [name] 30% [equipped] 8% [breakage_range] 9% [fumble_range] 9% [strength] 9% [quantity] 9% [weight] 9% [cost] 9% [controls] 8%; +} + +.weapons-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} + +.weapons-grid-container > div:nth-child(18n+1), +.weapons-grid-container > div:nth-child(18n+2), +.weapons-grid-container > div:nth-child(18n+3), +.weapons-grid-container > div:nth-child(18n+4), +.weapons-grid-container > div:nth-child(18n+5), +.weapons-grid-container > div:nth-child(18n+6), +.weapons-grid-container > div:nth-child(18n+7), +.weapons-grid-container > div:nth-child(18n+8), +.weapons-grid-container > div:nth-child(18n+9) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.weapons-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} \ No newline at end of file diff --git a/less/actor-sheet/actor-sheet.less b/less/actor-sheet/actor-sheet.less new file mode 100644 index 0000000..9d410ba --- /dev/null +++ b/less/actor-sheet/actor-sheet.less @@ -0,0 +1,166 @@ +// General Elements + +.container { + display: flex; + } + +// Header CSS + +.actor-icon { + flex-shrink: 1; + } + +.favorite-container { + padding: 5px; +} +.header-container { + flex-grow: 2; + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.header-text { + display: flex; + align-items: center; + padding: 1px; + } + +.settings-button, .playersheet-settings { + font-family: Signika, sans-serif; + font-size: 12px; + margin-right: 6px +} + +// Resource Elements in Headers + +.resource-container { + display: flex; + flex-direction: row; + flex-grow: 3; + text-align: -webkit-center; +} + +.resource-container > * { + flex: 1 1 0; +} + +.resource-entry { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.resource-entry input{ + width: 50px; + border: none; +} + +.stat-container { + flex-direction: column; + flex-shrink: 1; + } + +.stat-row { + align-items: center; +} + +.equipment-container { + flex-direction: column; + flex-grow: 1; + } + +.stat-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.stat-name, .money-name { + width: 75px; + border: none; + font-family: Signika, sans-serif; + font-size: 12px; +} + +.stat-name input { + border: none; +} + +.stat-header { + font-family: Signika, sans-serif; + font-size: 12px; +} + +// Fixed Info CSS + +.fixed-info-container { + flex-grow: 3; + flex-direction: row; + font-family: Signika, sans-serif; + font-size: 12px; +} + +.fixed-info-section { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.armor-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.race-stat-fixed-info-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.role-traits-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +.background-info-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +// Remove Me +.resistance-block { + outline: 1px solid; /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} + +// Debugging + +.red { + background-color: orangered; +} + +.blue { + background-color: lightblue; +} + +.grey { + background-color: lightgrey; +} + +.green { + background-color: lightseagreen; +} \ No newline at end of file diff --git a/less/grid.less b/less/grid.less new file mode 100644 index 0000000..ed43414 --- /dev/null +++ b/less/grid.less @@ -0,0 +1,118 @@ +.skillcat-grid-container { + display: grid; + grid-template-columns: [skill-category-name] 10% [applicable-stats] 10% [dev-cost] 8% [num-ranks] 8% [new-ranks] 8% [rank-bonus] 8% [stat-bonus] 8% [prof-bonus] 8% [special-bonus-1] 8% [special-bonus-2] 8% [total-bonus] 8% [controls] 8%; +} + +.skillcat-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} + +.skillcat-grid-container > div:nth-child(24n+1), +.skillcat-grid-container > div:nth-child(24n+2), +.skillcat-grid-container > div:nth-child(24n+3), +.skillcat-grid-container > div:nth-child(24n+4), +.skillcat-grid-container > div:nth-child(24n+5), +.skillcat-grid-container > div:nth-child(24n+6), +.skillcat-grid-container > div:nth-child(24n+7), +.skillcat-grid-container > div:nth-child(24n+8), +.skillcat-grid-container > div:nth-child(24n+9), +.skillcat-grid-container > div:nth-child(24n+10), +.skillcat-grid-container > div:nth-child(24n+11), +.skillcat-grid-container > div:nth-child(24n+12) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.skillcat-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + + + +.skills-grid-container { + display: grid; + grid-template-columns: [favorite] 9% [skill-name] 11% [num-ranks] 9% [new-ranks] 9% [rank-bonus] 9% [category-bonus] 9% [item-bonus] 9% [special-bonus-1] 9% [special-bonus-2] 9% [total-bonus] 9% [controls] 8%; +} + +.skills-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} + +.skills-grid-container > div:nth-child(22n+1), +.skills-grid-container > div:nth-child(22n+2), +.skills-grid-container > div:nth-child(22n+3), +.skills-grid-container > div:nth-child(22n+4), +.skills-grid-container > div:nth-child(22n+5), +.skills-grid-container > div:nth-child(22n+6), +.skills-grid-container > div:nth-child(22n+7), +.skills-grid-container > div:nth-child(22n+8), +.skills-grid-container > div:nth-child(22n+9), +.skills-grid-container > div:nth-child(22n+10), +.skills-grid-container > div:nth-child(22n+11) +{ + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.skills-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} + +.applicable-stats-grid-container { + display: grid; + grid-template-columns: [app-stat-1] 33% [app-stat-2] 33% [dapp-stat-3] 33%; +} + +.applicable-stats-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} \ No newline at end of file diff --git a/less/item-sheet.less b/less/item-sheet.less new file mode 100644 index 0000000..208c65e --- /dev/null +++ b/less/item-sheet.less @@ -0,0 +1,14 @@ +.sheet { + form { + display: flex; + flex-direction: column; + } + .sheet-content { + height: 100%; + display: flex; + flex-direction: column; + .editor { + height: 100% + } + } +} \ No newline at end of file diff --git a/less/money-sheet.less b/less/money-sheet.less new file mode 100644 index 0000000..78d18ce --- /dev/null +++ b/less/money-sheet.less @@ -0,0 +1,8 @@ +.money-column { + flex-direction: column; +} + +.money-container { + flex-direction: column; + flex-shrink: 1; + } \ No newline at end of file diff --git a/less/rmss.less b/less/rmss.less new file mode 100644 index 0000000..93ac91f --- /dev/null +++ b/less/rmss.less @@ -0,0 +1,20 @@ + +// Actor Sheet +@import "./actor-sheet/actor-sheet-skillcat.less"; +@import "./actor-sheet/actor-sheet.less"; +@import "./actor-sheet/actor-sheet-skills.less"; +@import "./actor-sheet/actor-sheet-money.less"; +@import "./actor-sheet/actor-sheet-items.less"; +@import "./actor-sheet/actor-sheet-weapons.less"; +@import "./actor-sheet/actor-sheet-armor.less"; +@import "./actor-sheet/actor-sheet-herbs.less"; +@import "./actor-sheet/actor-sheet-spells.less"; +@import "./actor-sheet/actor-sheet-resistances.less"; + +//Skill Category Sheet + +@import "./skillcat-sheet/skillcat-sheet.less"; +@import "./skillcat-sheet/applicable-stats-grid.less"; + +// Generics +@import "./item-sheet.less"; \ No newline at end of file diff --git a/less/skillcat-sheet.less b/less/skillcat-sheet.less new file mode 100644 index 0000000..0399a73 --- /dev/null +++ b/less/skillcat-sheet.less @@ -0,0 +1,23 @@ +.skillcat-name, .skill-name, .item-name { + font-family: Signika, sans-serif; + font-size: 12px; + font-weight: bold; + text-align: center; +} + +.skillcat-entry, .skill-entry, .item-entry { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} + +.skillcat-headeritem, .skill-headeritem, .item-headeritem { + text-align: center; + font-weight: bold; +} + +.skillcat-controls, .skill-controls, .item-controls { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} \ No newline at end of file diff --git a/less/skillcat-sheet/applicable-stats-grid.less b/less/skillcat-sheet/applicable-stats-grid.less new file mode 100644 index 0000000..c6fa27f --- /dev/null +++ b/less/skillcat-sheet/applicable-stats-grid.less @@ -0,0 +1,19 @@ + + +.applicable-stats-grid-container { + display: grid; + grid-template-columns: [app-stat-1] 33% [app-stat-2] 33% [app-stat-3] 33%; +} + +.applicable-stats-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} \ No newline at end of file diff --git a/less/skillcat-sheet/skillcat-sheet.less b/less/skillcat-sheet/skillcat-sheet.less new file mode 100644 index 0000000..48139e6 --- /dev/null +++ b/less/skillcat-sheet/skillcat-sheet.less @@ -0,0 +1,23 @@ +.skillcat-name, .skill-name, .item-name, .spell-name, .equipable-name { + font-family: Signika, sans-serif; + font-size: 12px; + font-weight: bold; + text-align: center; +} + +.skillcat-entry, .skill-entry, .item-entry, .spell-entry, .equipable-entry { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} + +.skillcat-headeritem, .skill-headeritem, .item-headeritem, .spell-headeritem, .equipable-headeritem { + text-align: center; + font-weight: bold; +} + +.skillcat-controls, .skill-controls, .item-controls { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} \ No newline at end of file diff --git a/less/table.less b/less/table.less new file mode 100644 index 0000000..56b0738 --- /dev/null +++ b/less/table.less @@ -0,0 +1,19 @@ +.table-font { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} + +.table-bold { + font-weight: bold; +} + +.table-center { + text-align: center; +} + +.table-controls { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} \ No newline at end of file diff --git a/module/config.js b/module/config.js new file mode 100644 index 0000000..7def4bb --- /dev/null +++ b/module/config.js @@ -0,0 +1,60 @@ +export const rmss = {}; + +rmss.curreny_type = { + mp: "rmss.curreny_type.mp", + pp: "rmss.curreny_type.pp", + gp: "rmss.curreny_type.gp", + sp: "rmss.curreny_type.sp", + bp: "rmss.curreny_type.bp", + cp: "rmss.curreny_type.cp" +}; + +rmss.stats = { + agility: { + fullname: "Agility", + shortname: "Ag" + }, + constitution: { + fullname: "Constitution", + shortname: "Co" + }, + memory: { + fullname: "Memory", + shortname: "Me" + }, + reasoning: { + fullname: "Reasoning", + shortname: "Re" + }, + self_discipline: { + fullname: "Self Discipline", + shortname: "SD" + }, + empathy: { + fullname: "Empathy", + shortname: "Em" + }, + intuition: { + fullname: "Intuition", + shortname: "In" + }, + presence: { + fullname: "Presence", + shortname: "Pr" + }, + quickness: { + fullname: "Quickness", + shortname: "Qu" + }, + strength: { + fullname: "Strength", + shortname: "St" + } +}; + +rmss.skill_designations = { + None: "None", + Occupational: "Occupational", + Everyman: "Everyman", + Restricted: "Restricted" +}; diff --git a/module/documents/actor.js b/module/documents/actor.js new file mode 100644 index 0000000..23e47d6 --- /dev/null +++ b/module/documents/actor.js @@ -0,0 +1,248 @@ +export class RMSSActor extends Actor { + + /** @override */ + prepareData() { + // Prepare data for the actor. Calling the super version of this executes + // the following, in order: data reset (to clear active effects), + // prepareBaseData(), prepareEmbeddedDocuments() (including active effects), + // prepareDerivedData(). + super.prepareData(); + } + + prepareDerivedData() { + const actorData = this; + const systemData = actorData.system; + const flags = actorData.flags.rmss || {}; + + // Make separate methods for each Actor type (character, npc, etc.) to keep + // things organized. + this._prepareCharacterData(actorData); + this._prepareNpcData(actorData); + } + + /** + * Prepare Character specific data. + * @param {Actor} actorData The NPC Object to prepare data for + */ + _prepareCharacterData(actorData) { + if (actorData.type !== "character") return; + + // Calculate Stat Bonuses for the Actor + this.calculateStatBonuses(actorData); + + // Calculate Resistance Rolls for the Actor + this.calculateResistanceRolls(actorData); + + // Iterate through and apply Stat bonuses for Skill Category Items + this.calculateSkillCategoryStatBonuses(); + + // Iterate through and apply Skill Category Bonuses for Skill items + this.calculateSkillBonuses(); + } + + /** + * Prepare NPC specific data. + * @param {Actor} actorData The NPC Object to prepare data for + */ + _prepareNpcData(actorData) { + if (actorData.type !== "npc") return; + + // Make modifications to data here. For example: + const data = actorData.data; + } + + // Tally each stat bonus and populate the total field. + calculateStatBonuses(actorData) { + const systemData = actorData.system; + + actorData.system.stats.agility.stat_bonus = Number(systemData.stats.agility.racial_bonus) + + Number(systemData.stats.agility.special_bonus) + + Number(systemData.stats.agility.basic_bonus); + + actorData.system.stats.constitution.stat_bonus = Number(systemData.stats.constitution.racial_bonus) + + Number(systemData.stats.constitution.special_bonus) + + Number(systemData.stats.constitution.basic_bonus); + + actorData.system.stats.memory.stat_bonus = Number(systemData.stats.memory.racial_bonus) + + Number(systemData.stats.memory.special_bonus) + + Number(systemData.stats.memory.basic_bonus); + + actorData.system.stats.reasoning.stat_bonus = Number(systemData.stats.reasoning.racial_bonus) + + Number(systemData.stats.reasoning.special_bonus) + + Number(systemData.stats.reasoning.basic_bonus); + + + actorData.system.stats.self_discipline.stat_bonus = Number(systemData.stats.self_discipline.racial_bonus) + + Number(systemData.stats.self_discipline.special_bonus) + + Number(systemData.stats.self_discipline.basic_bonus); + + actorData.system.stats.empathy.stat_bonus = Number(systemData.stats.empathy.racial_bonus) + + Number(systemData.stats.empathy.special_bonus) + + Number(systemData.stats.empathy.basic_bonus); + + actorData.system.stats.intuition.stat_bonus = Number(systemData.stats.intuition.racial_bonus) + + Number(systemData.stats.intuition.special_bonus) + + Number(systemData.stats.intuition.basic_bonus); + + actorData.system.stats.presence.stat_bonus = Number(systemData.stats.presence.racial_bonus) + + Number(systemData.stats.presence.special_bonus) + + Number(systemData.stats.presence.basic_bonus); + + actorData.system.stats.quickness.stat_bonus = Number(systemData.stats.quickness.racial_bonus) + + Number(systemData.stats.quickness.special_bonus) + + Number(systemData.stats.quickness.basic_bonus); + + actorData.system.stats.strength.stat_bonus = Number(systemData.stats.strength.racial_bonus) + + Number(systemData.stats.strength.special_bonus) + + Number(systemData.stats.strength.basic_bonus); + } + + // Calculate each Resistance Roll with the formula on the character sheet. + calculateResistanceRolls(actorData) { + const systemData = actorData.system; + + actorData.system.resistance_rolls.essence.value = Number(systemData.stats.empathy.stat_bonus * 3); + + actorData.system.resistance_rolls.channeling.value = Number(systemData.stats.intuition.stat_bonus * 3); + + actorData.system.resistance_rolls.mentalism.value = Number(systemData.stats.presence.stat_bonus * 3); + + actorData.system.resistance_rolls.fear.value = Number(systemData.stats.self_discipline.stat_bonus * 3); + + actorData.system.resistance_rolls.poison_disease.value = Number(systemData.stats.constitution.stat_bonus * 3); + + actorData.system.resistance_rolls.chann_ess.value = Number(systemData.stats.intuition.stat_bonus) + + Number(systemData.stats.empathy.stat_bonus); + + actorData.system.resistance_rolls.chann_ment.value = Number(systemData.stats.intuition.stat_bonus) + + Number(systemData.stats.presence.stat_bonus); + + actorData.system.resistance_rolls.ess_ment.value = Number(systemData.stats.empathy.stat_bonus) + + Number(systemData.stats.presence.stat_bonus); + + actorData.system.resistance_rolls.arcane.value = Number(systemData.stats.empathy.stat_bonus) + + Number(systemData.stats.intuition.stat_bonus) + + Number(systemData.stats.presence.stat_bonus); + + actorData.system.resistance_rolls.essence.total = actorData.system.resistance_rolls.essence.value + + actorData.system.resistance_rolls.essence.race_mod; + + actorData.system.resistance_rolls.channeling.total = actorData.system.resistance_rolls.channeling.value + + actorData.system.resistance_rolls.channeling.race_mod; + + actorData.system.resistance_rolls.mentalism.total = actorData.system.resistance_rolls.mentalism.value + + actorData.system.resistance_rolls.mentalism.race_mod; + + actorData.system.resistance_rolls.fear.total = actorData.system.resistance_rolls.fear.value + + actorData.system.resistance_rolls.fear.race_mod; + + actorData.system.resistance_rolls.poison_disease.total = actorData.system.resistance_rolls.poison_disease.value + + actorData.system.resistance_rolls.poison_disease.race_mod; + + actorData.system.resistance_rolls.chann_ess.total = actorData.system.resistance_rolls.chann_ess.value + + actorData.system.resistance_rolls.chann_ess.race_mod; + + actorData.system.resistance_rolls.chann_ment.total = actorData.system.resistance_rolls.chann_ment.value + + actorData.system.resistance_rolls.chann_ment.race_mod; + + actorData.system.resistance_rolls.ess_ment.total = actorData.system.resistance_rolls.ess_ment.value + + actorData.system.resistance_rolls.ess_ment.race_mod; + + actorData.system.resistance_rolls.arcane.total = actorData.system.resistance_rolls.arcane.value + + actorData.system.resistance_rolls.arcane.race_mod; + } + + calculateSkillBonuses() { + for (const item of this.items) { + if (item.type === "skill") { + console.log(`rmss | actor.js | Calculating skill bonus for Skill: ${item.name}`); + console.log(`rmss | actor.js | Updating Skill Category Bonus for Skill: ${item.name}`); + item.calculateSelectedSkillCategoryBonus(item); + console.log(`rmss | actor.js | Updating Skill Total Bonus for Skill: ${item.name}`); + item.calculateSkillTotalBonus(item); + } + } + } + + // Tallys the bonus for each Stat that is applicable to the Skill Category and then updates the total + calculateSkillCategoryStatBonuses() { + for (const item of this.items) { + if (item.type === "skill_category") { + + console.log(`rmss | actor.js | Calculating Skill Category Stat Bonuses for: ${item.name}`); + // Get all the applicable stats for this skill category + let app_stat_1 = item.system.app_stat_1; + let app_stat_2 = item.system.app_stat_2; + let app_stat_3 = item.system.app_stat_3; + + // If the first one is None we don't need to do anything further + if (app_stat_1 === "None") { + continue; + } + else + { + let applicable_stat_bonus = 0; + + let app_stat_1_found = false; + let app_stat_2_found = false; + let app_stat_3_found = false; + + // Iterate through the applicable stats and find their full names + for (const stat in CONFIG.rmss.stats) { + // If the configured App Stat matches the one of the stats in config + if (app_stat_1 === CONFIG.rmss.stats[stat].shortname) { + app_stat_1_found = true; + // Get the Stat Bonus + applicable_stat_bonus = applicable_stat_bonus + this.system.stats[stat].stat_bonus; + } + if (app_stat_2 === CONFIG.rmss.stats[stat].shortname) { + app_stat_2_found = true; + applicable_stat_bonus = applicable_stat_bonus + this.system.stats[stat].stat_bonus; + } + if (app_stat_3 === CONFIG.rmss.stats[stat].shortname) { + app_stat_3_found = true; + applicable_stat_bonus = applicable_stat_bonus + this.system.stats[stat].stat_bonus; + } + } + + if (app_stat_1_found === true && app_stat_2_found === true && app_stat_3_found === true) { + // Apply the update if we found stat bonuses for every applicable stat + item.system.stat_bonus = applicable_stat_bonus; + + // Update the total in the Item + item.calculateSkillCategoryTotalBonus(item); + } + else if (app_stat_1_found === true && app_stat_2_found === true && app_stat_3_found === false) { + // Apply the update if we found stat bonuses for the first two applicable stats + item.system.stat_bonus = applicable_stat_bonus; + + // Update the total in the Item + item.calculateSkillCategoryTotalBonus(item); + } + else if (app_stat_1_found === true && app_stat_2_found === false && app_stat_3_found === false) { + // Apply the update if we found stat bonuses for the first applicable stat + item.system.stat_bonus = applicable_stat_bonus; + + // Update the total in the Item + item.calculateSkillCategoryTotalBonus(item); + } + } + } + } + } + + // For each skill category return an object in this format. + // {{ _id: "skill category name"}} + // This is the format that the select helper on the skill sheet needs + + getOwnedItemsByType(item_type) { + let ownedItems = {None: "None"}; + console.log(`rmss | actor.js | Getting owned ${item_type} for: ${this.name}`); + for (const item of this.items) { + if (item.type === item_type) { + ownedItems[item._id] = item.name; + } + } + return (ownedItems); + } +} diff --git a/module/documents/item.js b/module/documents/item.js new file mode 100644 index 0000000..f447c97 --- /dev/null +++ b/module/documents/item.js @@ -0,0 +1,118 @@ +export class RMSSItem extends Item { + + /** @override */ + prepareData() { + // Prepare data for the item. Calling the super version of this executes + // the following, in order: data reset (to clear active effects), + // prepareBaseData(), prepareEmbeddedDocuments() (including active effects), + // prepareDerivedData(). + console.log(`rmss | item.js | prepareData for: ${this.name}`); + super.prepareData(); + } + + // Set the icon images for newly created images. + async _preCreate(data, options, userId) { + await super._preCreate(data, options, userId); + + // Do not set on copied items if they have a custom Icon. + if (!data.name.includes("(Copy)")) + { + if (this.type === "armor") { + await this.updateSource({img: "systems/rmss/assets/default/armor.svg"}); + } + else if (this.type === "weapon") { + await this.updateSource({img: "systems/rmss/assets/default/weapon.svg"}); + } + else if (this.type === "skill") { + await this.updateSource({img: "systems/rmss/assets/default/skill.svg"}); + } + else if (this.type === "skill_category") { + await this.updateSource({img: "systems/rmss/assets/default/skill_category.svg"}); + } + else if (this.type === "spell") { + await this.updateSource({img: "systems/rmss/assets/default/spell.svg"}); + } + else if (this.type === "herb_or_poison") { + await this.updateSource({img: "systems/rmss/assets/default/herb_or_poison.svg"}); + } + else if (this.type === "transport") { + await this.updateSource({img: "systems/rmss/assets/default/transport.svg"}); + } + } + } + + prepareDerivedData() { + const itemData = this; + const systemData = itemData.system; + const flags = itemData.flags.rmss || {}; + + // Make separate methods for each item type to keep things organized. + + if (itemData.type === "skill") { + this._prepareSkillCategoryData(itemData); + } + + if (itemData.type === "skill") { + this._prepareSkillData(itemData); + } + } + + _prepareSkillCategoryData(itemData) { + if (itemData.type !== "skill_category") return; + console.log(`rmss | item.js | Preparing Skill Category Data for: ${itemData.name}`); + // Calculate Skill Category Total Bonus + this.calculateSkillCategoryTotalBonus(itemData); + } + + _prepareSkillData(itemData) { + if (itemData.type !== "skill") return; + console.log(`rmss | item.js | Preparing Skill Data for: ${itemData.name}`); + // Make modifications to data here. For example: + // const systemData = itemData.system; + // Calculate Skill Category Bonus + this.calculateSelectedSkillCategoryBonus(itemData); + // Calculate Skill Total Bonus + this.calculateSkillTotalBonus(itemData); + } + + calculateSkillCategoryTotalBonus(itemData) { + if (this.type === "skill_category") { + console.log(`rmss | item.js | Calculating Skill Category Total Bonus for: ${itemData.name}`); + const systemData = itemData.system; + itemData.system.total_bonus = Number(systemData.rank_bonus) + + Number(systemData.stat_bonus) + + Number(systemData.prof_bonus) + + Number(systemData.special_bonus_1) + + Number(systemData.special_bonus_2); + } + } + + calculateSkillTotalBonus(itemData) { + if (this.type === "skill") { + const systemData = itemData.system; + console.log(`rmss | item.js | Calculating Skill Total Bonus for: ${itemData.name}`); + itemData.system.total_bonus = Number(systemData.rank_bonus) + + Number(systemData.category_bonus) + + Number(systemData.item_bonus) + + Number(systemData.special_bonus_1) + + Number(systemData.special_bonus_2); + } + } + + calculateSelectedSkillCategoryBonus(itemData) { + if (this.isEmbedded === null) { + console.log(`rmss | item.js | Skill ${this.name} has no owner. Not calculating Skill Category bonus`); + } + else + { + const items = this.parent.items; + console.log(`rmss | item.js | Skill ${this.name} has owner, calculating skill category bonus.`); + for (const item of items) { + if (item.type === "skill_category" && item._id === itemData.system.category) { + console.log(`rmss | item.js | Calculating Skill Category bonus for skill: ${this.name}`); + this.system.category_bonus = item.system.total_bonus; + } + } + } + } +} diff --git a/module/sheets/actors/rmss_player_sheet.js b/module/sheets/actors/rmss_player_sheet.js new file mode 100644 index 0000000..283ac2f --- /dev/null +++ b/module/sheets/actors/rmss_player_sheet.js @@ -0,0 +1,390 @@ +export default class RMSSPlayerSheet extends ActorSheet { + + // Override Default Options, Set CSS Classes, Set Default Sheet, Set up Sheet Tabs + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 860, + height: 780, + template: "systems/rmss/templates/sheets/actors/rmss-character-sheet.html", + classes: ["rmss", "sheet", "actor"], + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "features" }] + }); + } + + // Make the data available to the sheet template + async getData() { + const context = super.getData(); + + // Use a safe clone of the actor data for further operations. + const actorData = this.actor.toObject(false); + + let enrichedDescription = await TextEditor.enrichHTML(this.actor.system.description, {async: true}); + + // Add the actor's data to context.data for easier access, as well as flags. + context.system = actorData.system; + context.flags = actorData.flags; + context.enrichedDescription = enrichedDescription; + + // Prepare character data and items. + if (actorData.type === "character") { + this._prepareItems(context); + this._prepareCharacterData(context); + } + + // Prepare NPC data and items. + if (actorData.type === "npc") { + this._prepareItems(context); + } + return context; + } + + // Override this method to check for duplicates when things are dragged to the sheet + // We don't want duplicate skills and skill categories. + async _onDropItem(event, data) { + + // Reconstruct the item from the event + const newitem = await Item.implementation.fromDropData(data); + const itemData = newitem.toObject(); + + // To Do: Seperate Skills and Skill Categories. Increment Counts for items + if (itemData.type === "skill_category") { + + // Get the already owned Items from the actor and push into an array + const owneditems = this.object.getOwnedItemsByType("skill_category"); + + let ownedskillcatlist = Object.values(owneditems); + + // Check if the dragged item is not in the array and not owned + if (!ownedskillcatlist.includes(itemData.name)) { + console.log("Not Owned!"); + super._onDropItem(event, data); + } + } else if ( itemData.type === "skill") { + // Get the already owned Items from the actor and push into an array + const owneditems = this.object.getOwnedItemsByType("skill"); + + let ownedskilllist = Object.values(owneditems); + + // Check if the dragged item is not in the array and not owned + if (!ownedskilllist.includes(itemData.name)) { + console.log("Not Owned!"); + super._onDropItem(event, data); + } + } + else { + super._onDropItem(event, data); + } + } + + _prepareCharacterData(context) { + // Calculate Power Point Exhaustion + let powerpointPercentage = (Number(context.system.attributes.power_points.current) / Number(context.system.attributes.power_points.max)) * 100; + + console.log(true); + + switch (true) { + case (powerpointPercentage < 25): + context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: -30 "; + break; + case (powerpointPercentage < 50): + context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: -20 "; + break; + case (powerpointPercentage < 75): + console.log("Less than 75"); + context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: -10 "; + break; + default: + console.log("Setting Default"); + context.system.attributes.power_points.modifier = "PP Exhaustion Penalty: 0 "; + } + + // Calculate Exhaustion Point Penalty + let exhaustionPercentage = (Number(context.system.attributes.exhaustion_points.current) / Number(context.system.attributes.exhaustion_points.max)) * 100; + + console.log(true); + + switch (true) { + case (exhaustionPercentage < 1): + context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -100 "; + break; + case (exhaustionPercentage < 10): + context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -60 "; + break; + case (exhaustionPercentage < 25): + context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -30 "; + break; + case (exhaustionPercentage < 50): + context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -15 "; + break; + case (exhaustionPercentage < 75): + console.log("Less than 75"); + context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: -5 "; + break; + default: + console.log("Setting Default"); + context.system.attributes.exhaustion_points.modifier = "Exhaustion Penalty: 0 "; + } + + } + + _prepareItems(context) { + console.log(`rmss | rmss_player_sheet.js | Preparing items for: ${this.name}`); + // Initialize containers. + const gear = []; + const playerskill= []; + const skillcat = []; + const weapons = []; + const armor = []; + const herbs = []; + const spells = []; + const equipables = []; + + // Iterate through items, allocating to containers + for (let i of context.items) { + i.img = i.img || DEFAULT_TOKEN; + // Append to gear. + if (i.type === "item") { + gear.push(i); + } + else if (i.type === "weapon") { + weapons.push(i); + } + else if (i.type === "herb_or_poison") { + herbs.push(i); + } + // Append to skill categories. + else if (i.type === "skill_category") { + skillcat.push(i); + } + // Append to playerskill + else if (i.type === "skill") { + playerskill.push(i); + } + else if (i.type === "armor") { + armor.push(i); + } + else if (i.type === "spell") { + spells.push(i); + } + } + + + // Sort Skill/Skillcat Arrays + skillcat.sort(function(a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + + playerskill.sort(function(a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + + // Assign and return + context.gear = gear; + context.skillcat = skillcat; + context.playerskill = playerskill; + context.weapons = weapons; + context.armor = armor; + context.herbs = herbs; + context.spells = spells; + } + + async renderCharacterSettings(data) { + console.log(data); + const configSheet = await renderTemplate("systems/rmss/templates/sheets/actors/dialogs/actor-settings.html", data); + return (configSheet); + } + + activateListeners(html) { + super.activateListeners(html); + + // Render the item sheet for viewing/editing prior to the editable check. + html.find(".item-edit").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + item.sheet.render(true); + }); + + // ------------------------------------------------------------- + // Everything below here is only needed if the sheet is editable + if (!this.isEditable) return; + + // Add Item + html.find(".item-create").click(this._onItemCreate.bind(this)); + + // Delete Item + html.find(".item-delete").click(ev => { + console.log(ev.currentTarget.getAttribute("data-item-id")); + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + item.delete(); + }); + + // Show Sheet Settings + html.find(".import-skillcats").click(async ev => { + + let selectOptions = {}; + for (const pack of game.packs) { + selectOptions[pack.metadata.id] = pack.metadata.label; + } + + new game.rmss.applications.RMSSActorSheetConfig(selectOptions, this.actor).render(true); + }); + + // Check/Uncheck Favorite Skill + html.find(".skill-favorite").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + console.log(item); + console.log(`Before change: ${item.system.favorite}`); + if (item.system.favorite === true) { + console.log("Setting False"); + item.update({system: {favorite: false}}); + } else { + console.log("Setting True"); + item.update({system: {favorite: true}}); + } + console.log(`After change: ${item.system.favorite}`); + }); + + // Check/Uncheck Favorite Spell + html.find(".spell-favorite").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + console.log(item); + console.log(`Before change: ${item.system.favorite}`); + if (item.system.favorite === true) { + console.log("Setting False"); + item.update({system: {favorite: false}}); + } else { + console.log("Setting True"); + item.update({system: {favorite: true}}); + } + console.log(`After change: ${item.system.favorite}`); + }); + + // Equip/Unequip Weapon/Armor + html.find(".equippable").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + console.log(item); + console.log(`Before change: ${item.system.equipped}`); + if (item.system.equipped === true) { + console.log("Setting False"); + item.update({system: {equipped: false}}); + } else { + console.log("Setting True"); + item.update({system: {equipped: true}}); + } + console.log(`After change: ${item.system.equipped}`); + }); + + // Wear/Remove Item + html.find(".wearable").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + console.log(item); + console.log(`Before change: ${item.system.equipped}`); + if (item.system.worn === true) { + console.log("Setting False"); + item.update({system: {worn: false}}); + } else { + console.log("Setting True"); + item.update({system: {worn: true}}); + } + console.log(`After change: ${item.system.equipped}`); + }); + + // Change New Ranks value when clicked in player sheet. From 0-3. + html.find(".skill-newrank").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + + console.log("Firing in the Player Sheet"); + console.log(ev.currentTarget.getAttribute("value")); + console.log(ev.currentTarget.getAttribute("data-item-id")); + + switch (ev.currentTarget.getAttribute("value")) { + case "0": + console.log("Skill NewRanks is 0 setting to 1"); + item.update({system: {new_ranks: { value: 1 }}}); + break; + + case "1": + console.log("Skill NewRanks is 1 setting to 2"); + item.update({system: {new_ranks: { value: 2 }}}); + break; + + case "2": + console.log("Skill NewRanks is 2 setting to 3"); + item.update({system: {new_ranks: { value: 3 }}}); + break; + + case "3": + console.log("Skill NewRanks is 3 setting to 0"); + item.update({system: {new_ranks: { value: 0 }}}); + break; + } + }); + + // Change New Ranks value when clicked in player sheet. From 0-3. + html.find(".skillcategory-newrank").click(ev => { + const item = this.actor.items.get(ev.currentTarget.getAttribute("data-item-id")); + + console.log("Firing in the Player Sheet"); + console.log(ev.currentTarget.getAttribute("value")); + console.log(ev.currentTarget.getAttribute("data-item-id")); + + switch (ev.currentTarget.getAttribute("value")) { + case "0": + console.log("Skill Category NewRanks is 0 setting to 1"); + item.update({system: {new_ranks: { value: 1 }}}); + break; + + case "1": + console.log("Skill Category NewRanks is 1 setting to 2"); + item.update({system: {new_ranks: { value: 2 }}}); + break; + + case "2": + console.log("Skill Category NewRanks is 2 setting to 3"); + item.update({system: {new_ranks: { value: 3 }}}); + break; + + case "3": + console.log("Skill Category NewRanks is 3 setting to 0"); + item.update({system: {new_ranks: { value: 0 }}}); + break; + } + }); + } + + async _onItemCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + + // Get the type of item to create. + const type = header.dataset.type; + + // Grab any data associated with this control. + const data = duplicate(header.dataset); + + // Initialize a default name. + const name = `New ${type.capitalize()}`; + + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data + }; + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data.type; + // Finally, create the item! + return await Item.create(itemData, {parent: this.actor}); + } +} diff --git a/module/sheets/actors/rmss_player_sheet_config.js b/module/sheets/actors/rmss_player_sheet_config.js new file mode 100644 index 0000000..8906fc2 --- /dev/null +++ b/module/sheets/actors/rmss_player_sheet_config.js @@ -0,0 +1,55 @@ +export default class RMSSActorSheetConfig extends FormApplication { + + constructor(selectOptions, character) { + super(); + this.selectOptions = selectOptions; + this.character = character; + } + + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + classes: ["form"], + popOut: true, + template: "systems/rmss/templates/sheets/actors/apps/actor-settings.html" + }); + } + + getData() { + // Send data to the template + return { + selectOptions: this.selectOptions + }; + } + + activateListeners(html) { + super.activateListeners(html); + } + + async _updateObject(event, formData) { + console.log("Deleting Old Skill Categories."); + for (const item of this.character.items) { + if (item.type === "skill_category") { + item.delete(); + } + } + + const pack = game.packs.get(formData.selectOptions); + const skillCategoryData = await pack.getIndex(); + + console.log("Importing New Skill Categories."); + + for (const sc of skillCategoryData) { + const newitem = await pack.getDocument(sc._id); + + let newDocuments = []; + if (newitem.type === "skill_category") { + console.log(newitem); + newDocuments.push(newitem); + } + if (newDocuments.length > 0) { + await Item.createDocuments(newDocuments, {parent: this.character}); + } + } + } +} + diff --git a/module/sheets/items/rmss_armor_sheet.js b/module/sheets/items/rmss_armor_sheet.js new file mode 100644 index 0000000..0d4cbe6 --- /dev/null +++ b/module/sheets/items/rmss_armor_sheet.js @@ -0,0 +1,36 @@ +// Our Item Sheet extends the default +export default class RMSSArmorSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + template: "systems/rmss/templates/sheets/items/rmss-armor-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/items/rmss-armor-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + enrichedDescription: enrichedDescription + }; + + return sheetData; + } +} diff --git a/module/sheets/items/rmss_herb_or_poison_sheet.js b/module/sheets/items/rmss_herb_or_poison_sheet.js new file mode 100644 index 0000000..1c32ac8 --- /dev/null +++ b/module/sheets/items/rmss_herb_or_poison_sheet.js @@ -0,0 +1,36 @@ +// Our Item Sheet extends the default +export default class RMSSHerbAndPoisonSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + template: "systems/rmss/templates/sheets/items/rmss-herb-or-poison-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/items/rmss-herb-or-poison-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + enrichedDescription: enrichedDescription + }; + + return sheetData; + } +} diff --git a/module/sheets/items/rmss_item_sheet.js b/module/sheets/items/rmss_item_sheet.js new file mode 100644 index 0000000..2eda346 --- /dev/null +++ b/module/sheets/items/rmss_item_sheet.js @@ -0,0 +1,36 @@ +// Our Item Sheet extends the default +export default class RMSSItemSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + template: "systems/rmss/templates/sheets/items/rmss-item-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/items/rmss-item-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + enrichedDescription: enrichedDescription + }; + + return sheetData; + } +} diff --git a/module/sheets/items/rmss_transport_sheet.js b/module/sheets/items/rmss_transport_sheet.js new file mode 100644 index 0000000..08164df --- /dev/null +++ b/module/sheets/items/rmss_transport_sheet.js @@ -0,0 +1,36 @@ +// Our Item Sheet extends the default +export default class RMSSTransportSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + template: "systems/rmss/templates/sheets/items/rmss-transport-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/items/rmss-transport-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + enrichedDescription: enrichedDescription + }; + + return sheetData; + } +} diff --git a/module/sheets/items/rmss_weapon_sheet.js b/module/sheets/items/rmss_weapon_sheet.js new file mode 100644 index 0000000..8382025 --- /dev/null +++ b/module/sheets/items/rmss_weapon_sheet.js @@ -0,0 +1,36 @@ +// Our Item Sheet extends the default +export default class RMSSWeaponSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + template: "systems/rmss/templates/sheets/items/rmss-weapon-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/items/rmss-weapon-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + enrichedDescription: enrichedDescription + }; + + return sheetData; + } +} diff --git a/module/sheets/skills/rmss_skill_category_sheet.js b/module/sheets/skills/rmss_skill_category_sheet.js new file mode 100644 index 0000000..adfdaf9 --- /dev/null +++ b/module/sheets/skills/rmss_skill_category_sheet.js @@ -0,0 +1,133 @@ +// Our Item Sheet extends the default +export default class RMSSSkillCategorySheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 580, + height: 440, + template: "systems/rmss/templates/sheets/skills/rmss-skill-category-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/skills/rmss-skill-category-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const context = await super.getData(); + + // Get a list of stats that can be used as applicable stats + let applicableStatList = this.prepareApplicableStatNames(CONFIG); + + // Get the currently selected value for all three applicable stats + let firstApplicableStat = this.prepareApplicableSelectedStat("app_stat_1"); + let secondApplicableStat = this.prepareApplicableSelectedStat("app_stat_2"); + let thirdApplicableStat = this.prepareApplicableSelectedStat("app_stat_3"); + + // Build and apply the display string for Applicable Stats + let applicableStatText = + this.buildApplicableStatsText(firstApplicableStat, secondApplicableStat, thirdApplicableStat); + context.item.system.applicable_stats = applicableStatText; + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: context.item, + system: context.item.system, + config: CONFIG.rmss, + applicable_stat_list: applicableStatList, + applicable_stat_1_selected: firstApplicableStat, + applicable_stat_2_selected: secondApplicableStat, + applicable_stat_3_selected: thirdApplicableStat, + enrichedDescription: enrichedDescription + }; + return sheetData; + } + + async _setApplicableStat(item, ev) { + // Build a JSON Object from the selected tag value and selected name (item data attribute key) + let updateKey = ev.currentTarget.getAttribute("name"); + let updateData = ev.target.value; + + // Update Item Data + await item.update({[updateKey]: updateData}); + } + + // Each Skill Category can have up to three Applicable Stats that apply to it. We need to get a list of + // the Stat Shortnames from Config so the user can select which stats are applicable to this Skill Category + prepareApplicableStatNames(config) { + let applicableStatList = {None: "None"}; + for (const item in config.rmss.stats) { + applicableStatList[config.rmss.stats[item].shortname] = config.rmss.stats[item].shortname; + } + return applicableStatList; + } + + // Get the values for the currently selected Applicable Stat so we can display it on the Skill Category Sheet + // If nothing is selected return an empty string. + prepareApplicableSelectedStat(appStat) { + let applicableStatSelected = ""; + applicableStatSelected = this.item.system[appStat]; + return applicableStatSelected; + } + + // The character sheet has an information field that displays the applicable stats in the following format + // St/Ag/St. This method checks the current applicable stats and builds that field so + // it can be displayed to the user. + buildApplicableStatsText(firstAppStat, secondAppStat, thirdAppStat) { + if (firstAppStat === "None") { + return ("None"); + } + else if (firstAppStat !== "None" && secondAppStat === "None") { + return (firstAppStat); + } + else if (firstAppStat !== "None" && secondAppStat !== "None" && thirdAppStat === "None" ) { + return (`${firstAppStat}/${secondAppStat}`); + } + else if (firstAppStat !== "None" && secondAppStat !== "None" && thirdAppStat !== "None" ) { + return (`${firstAppStat}/${secondAppStat}/${thirdAppStat}`); + } + else { + return ("None"); + } + } + + activateListeners(html) { + super.activateListeners(html); + + // ------------------------------------------------------------- + // Everything below here is only needed if the sheet is editable + if (!this.isEditable) return; + + // Every time the user selects one of the Applicable Stat dropdowns + // fire an event to change the value in the Skill Category + html.find(".stat-selector").change(ev => { + this._setApplicableStat(this.item, ev); + }); + + // Catch the event when the user clicks one of the New Ranks Checkboxes in a Skill Category. + // It will increment by one or wrap back to zero on a value of three + html.find(".skillcategorysheet-newrank").click(ev => { + switch (ev.currentTarget.getAttribute("value")) { + case "0": + this.object.update({system: {new_ranks: { value: 1 }}}); + break; + case "1": + this.object.update({system: {new_ranks: { value: 2 }}}); + break; + case "2": + this.object.update({system: {new_ranks: { value: 3 }}}); + break; + case "3": + this.object.update({system: {new_ranks: { value: 0 }}}); + break; + } + }); + } +} diff --git a/module/sheets/skills/rmss_skill_sheet.js b/module/sheets/skills/rmss_skill_sheet.js new file mode 100644 index 0000000..7f31af9 --- /dev/null +++ b/module/sheets/skills/rmss_skill_sheet.js @@ -0,0 +1,115 @@ +// Our Item Sheet extends the default +export default class RMSSSkillSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + template: "systems/rmss/templates/sheets/skills/rmss-skill-sheet.html", + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/skills/rmss-skill-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + // Get a list of the parent item's skill categories for the dropdown + let ownedSkillCategories = this.prepareSkillCategoryValues(); + + // Figure out if a valid Skill Category is already selected + let selectedSkillCategory = this.prepareSelectedSkillCategory(ownedSkillCategories, this.object.system.category); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + owned_skillcats: ownedSkillCategories, + enrichedDescription: enrichedDescription, + selected_skillcat: selectedSkillCategory, + designations: CONFIG.rmss.skill_designations + }; + + return sheetData; + } + + activateListeners(html) { + super.activateListeners(html); + + // Catch the event when the user clicks one of the New Ranks Checkboxes in a Skill. + // It will increment by one or wrap back to zero on a value of three + html.find(".skillsheet-newrank").click(ev => { + switch (ev.currentTarget.getAttribute("value")) { + case "0": + this.object.update({system: {new_ranks: { value: 1 }}}); + break; + case "1": + this.object.update({system: {new_ranks: { value: 2 }}}); + break; + case "2": + this.object.update({system: {new_ranks: { value: 3 }}}); + break; + case "3": + this.object.update({system: {new_ranks: { value: 0 }}}); + break; + } + }); + } + + // Skills are related to Skill Categories so we need something to allow the user to choose that relationship + // If this Skill is owned then we will return a list of Skill Categories and allow them to choose + // Otherwise we'll just return 'Skill has no owner' + prepareSkillCategoryValues() { + let skillNoOwner = {None: "Skill Has No Owner"}; + + if (this.item.isEmbedded === null) { + return (skillNoOwner); + } + else + { + const skillCategories = this.item.parent.getOwnedItemsByType("skill_category"); + return (skillCategories); + } + } + + // Determine which Skill Category is selected and test that it is in the current list of categories. + // If it isn't set it to None. + prepareSelectedSkillCategory(ownedSkillCategories, selectedSkillCategory) { + let defaultSelectedCategory = "None"; + if (Object.keys(ownedSkillCategories).includes(selectedSkillCategory)) { + return (selectedSkillCategory); + } else { + return (defaultSelectedCategory); + } + } + + // Populate the Skill Category Bonus field on the Skill Sheet. + // Iterate through the owned skill categories and if one of them matches the item id of currently + // selected skill category then set the Skill Category Bonus field to the Total Bonus field of the Skill Category + prepareSelectedSkillCategoryBonus(selected_skillcat) { + if (this.item.isEmbedded === null) { + console.log("Skill has no owner"); + } + else + { + const items = this.object.parent.items; + + for (const item of items) { + if (item.type === "skill_category" && item._id === selected_skillcat) { + console.log(`rmss | rmss_skill_sheet | Calculating Skill Category bonus for skill: ${this.object.name}`); + this.object.system.category_bonus = item.system.total_bonus; + } + } + } + } +} diff --git a/module/sheets/spells/rmss_spell_sheet.js b/module/sheets/spells/rmss_spell_sheet.js new file mode 100644 index 0000000..c294f70 --- /dev/null +++ b/module/sheets/spells/rmss_spell_sheet.js @@ -0,0 +1,35 @@ +// Our Item Sheet extends the default +export default class RMSSSpellSheet extends ItemSheet { + + // Set the height and width + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + width: 530, + height: 440, + classes: ["rmss", "sheet", "item"] + }); + } + + // If our sheet is called here it is. + get template() { + return "systems/rmss/templates/sheets/spells/rmss-spell-sheet.html"; + } + + // Make the data available to the sheet template + async getData() { + const baseData = await super.getData(); + + let enrichedDescription = await TextEditor.enrichHTML(this.item.system.description, {async: true}); + + let sheetData = { + owner: this.item.isOwner, + editable: this.isEditable, + item: baseData.item, + system: baseData.item.system, + config: CONFIG.rmss, + enrichedDescription: enrichedDescription + }; + + return sheetData; + } +} diff --git a/packs/skill_categories.db b/packs/skill_categories.db new file mode 100644 index 0000000..2602268 --- /dev/null +++ b/packs/skill_categories.db @@ -0,0 +1,53 @@ +{"name":"Weapon • Missile Artillery","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"In/Ag/Re","app_stat_1":"In","app_stat_2":"Ag","app_stat_3":"Re","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.swVilWoSF4JH0yhZ"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898842718,"modifiedTime":1663840828472,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"1HevhbCbvMonyQXe"} +{"name":"Armor • Medium","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.ENiEBop9Kgrn9pBt"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897408501,"modifiedTime":1663840704830,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"2fdM9ICcj7vp8nFd"} +{"name":"Athletic • Gymnastics","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/Qu/Ag","app_stat_1":"Ag","app_stat_2":"Qu","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.TASzGNEwHMQUz1AV"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897573841,"modifiedTime":1663840718046,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"2rw9aaYaiTiuKX6p"} +{"name":"Weapon • Missile","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/St/Ag","app_stat_1":"Ag","app_stat_2":"St","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.8a1d0Z2MfJe0R1Eb"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898823756,"modifiedTime":1663840820736,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"2sTx95Y88soBT6Xm"} +{"name":"Technical/Trade • General","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Re/Me/SD","app_stat_1":"Re","app_stat_2":"Me","app_stat_3":"SD","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.1td9QGD20b4nkD6h"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898674902,"modifiedTime":1663840807018,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"3mHLFWrWHEA8Fmyq"} +{"name":"Lore • Obscure","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Me/Re/Me","app_stat_1":"Me","app_stat_2":"Re","app_stat_3":"Me","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.bsDoIUKcNUeqxQQO"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897997337,"modifiedTime":1663840747755,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"47foBA6Yk70CVg2i"} +{"name":"Weapon • Thown","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/St/Ag","app_stat_1":"Ag","app_stat_2":"St","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.kCtfktVNlH414NL2"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898881742,"modifiedTime":1663840832033,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"5e3r6vHlLHjZzyTu"} +{"name":"Technical/Trade • Professional","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Re/Me/In","app_stat_1":"Re","app_stat_2":"Me","app_stat_3":"In","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.xNTn6oV9yMOmfP0Z"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898699996,"modifiedTime":1663840810513,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"67oz5EUQCrxKsh5e"} +{"name":"Spells • Other Realm Open Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.AUzgIWYzrE15qCt9"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898456160,"modifiedTime":1663840790383,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"7z1BmP1Qlx11GL1C"} +{"name":"Lore • Technical","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Me/Re/Me","app_stat_1":"Me","app_stat_2":"Re","app_stat_3":"Me","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.Tw2FXIQb5HA89kbX"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898032616,"modifiedTime":1663840749775,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"9XA38iy0DxyhUaaC"} +{"name":"Armor • Light","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/St/Ag","app_stat_1":"Ag","app_stat_2":"St","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.TMGapmlYutNuQaw8"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897388838,"modifiedTime":1663840702933,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"AIvpcHWyipCtWLvT"} +{"name":"Combat Maneuvers","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/Qu/SD","app_stat_1":"Ag","app_stat_2":"Qu","app_stat_3":"SD","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.bwL0nMJePO6OQNue"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897819566,"modifiedTime":1663840727979,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"Aa5S1GaRJmkyDjIR"} +{"name":"Awareness • Perceptions","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"In/SD/In","app_stat_1":"In","app_stat_2":"SD","app_stat_3":"In","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.gJHBJS3aEz62XbxE"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897610482,"modifiedTime":1663840719487,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"BJlyds9J8ILwLIyW"} +{"name":"Martial Arts • Sweeps","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/St/Ag","app_stat_1":"Ag","app_stat_2":"St","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.n9WaU79Ctzmf6JbC"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898139942,"modifiedTime":1663840757073,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"Bj3no8mNboD8qKTn"} +{"name":"Crafts","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/Me/SD","app_stat_1":"Ag","app_stat_2":"Me","app_stat_3":"SD","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.6nErPtcQ33WXkyH4"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897865848,"modifiedTime":1663840734368,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"CcUHr6zfVpRuu4xv"} +{"name":"Body Development","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Co/SD/Co","app_stat_1":"Co","app_stat_2":"SD","app_stat_3":"Co","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.cWtQ0YU3kGBhL8iR"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897724809,"modifiedTime":1663840726119,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"DL9XZU3P2Bw87PJa"} +{"name":"Weapon • Pole Arms","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.hpmgFsJPXxBQHJSE"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898862386,"modifiedTime":1663840830247,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"HkZMP2SZyRVqzzCJ"} +{"name":"Self Control","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"SD/Pr/SD","app_stat_1":"SD","app_stat_2":"Pr","app_stat_3":"SD","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.1B82OxRKQ781NEa9"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898315491,"modifiedTime":1663840773057,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"IIQQyaCr7KJeeMGp"} +{"name":"Special Defenses","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.eH1iaAuxyIwDmuA8"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898371453,"modifiedTime":1663840778477,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"JmokU4vzQQ4lPicS"} +{"name":"Spells • Own Realm Open Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.w8xibKSY2EShkDJq"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898482739,"modifiedTime":1663840794007,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"KICAwOwrP1cMTRKf"} +{"name":"Subterfuge • Stealth","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/SD/In","app_stat_1":"Ag","app_stat_2":"SD","app_stat_3":"In","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.FM9stBeKGFVdAPdc"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898591826,"modifiedTime":1663840803256,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"KmFEWAhhqtmRZCQv"} +{"name":"Subterfuge • Mechanics","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"In/Ag/Re","app_stat_1":"In","app_stat_2":"Ag","app_stat_3":"Re","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.O0Zwk5hAhCMx6ajP"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898576285,"modifiedTime":1663840801090,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"P6lna8uCBQeVNgau"} +{"name":"Influence","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Pr/Em/In","app_stat_1":"Pr","app_stat_2":"Em","app_stat_3":"In","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.zOKTXAFd6bK3XJZ5"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897929958,"modifiedTime":1663840741277,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"PnBxiNuUS8b3KjGE"} +{"name":"Spells • Own Realm Other Base Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.HeAonlDHotwBy2lx"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898530167,"modifiedTime":1663840795735,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"QolQRsysF7O5XJo8"} +{"name":"Power Awareness","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Em/In/Pr","app_stat_1":"Em","app_stat_2":"In","app_stat_3":"Pr","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.cnnhsP9vAOoN7VMn"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898233748,"modifiedTime":1663840766010,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"R2wZUOFxekV1mBgc"} +{"name":"Spells • Arcane Open Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.R3lQNaGBdz7C5Fhs"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898407655,"modifiedTime":1663840780153,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"RpiCBmS6DKnI8Pok"} +{"name":"Athletic • Endurance","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Co/Ag/St","app_stat_1":"Co","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.ldmZhkHo8m4VvV2V"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897539929,"modifiedTime":1663840716358,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"Rug8mq3LdUxGhHXK"} +{"name":"Directed Spells","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/SD/Ag","app_stat_1":"Ag","app_stat_2":"SD","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.RA46DfHavzTTrp99"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897900117,"modifiedTime":1663840738205,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"US94Sx46Vn1Rs9D5"} +{"name":"Lore • Magical","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Me/Re/Me","app_stat_1":"Me","app_stat_2":"Re","app_stat_3":"Me","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.V9otC0Kh0y0B3P8Q"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897982070,"modifiedTime":1663840745751,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"X8RmCDRpojxc6u09"} +{"name":"Weapon • 1-H Concussion","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.CXllZNGgTe80uZRQ"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898744329,"modifiedTime":1663840814331,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"YZw0sLV7fZwXD85n"} +{"name":"Weapon • 1-H Edged","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.MV3UkzR77MTPHTau"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898787439,"modifiedTime":1663840817273,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"ZS8ikAjF41M7eZg5"} +{"name":"Awareness • Searching","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"In/Re/SD","app_stat_1":"In","app_stat_2":"Re","app_stat_3":"SD","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.NZl30XPdtYjHqtwp"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897647294,"modifiedTime":1663840720922,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"ZaUdmzJSrTeI0gsl"} +{"name":"Lore • General","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Me/Re/Me","app_stat_1":"Me","app_stat_2":"Re","app_stat_3":"Me","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.5fCeVMz6xVnkmH8o"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897962808,"modifiedTime":1663840744241,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"brpsxpqHEnUfC8a1"} +{"name":"Science/Analytic • Basic","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Re/Me/Re","app_stat_1":"Re","app_stat_2":"Me","app_stat_3":"Re","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.BfDFjciYPFezmes0"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898290307,"modifiedTime":1663840771526,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"dKHsLzvDinagbTCm"} +{"name":"Power Manipulation","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Em/In/Pr","app_stat_1":"Em","app_stat_2":"In","app_stat_3":"Pr","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.CQX0326xax4K3lEP"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898250959,"modifiedTime":1663840767601,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"g64EdTWn0WxJXJFq"} +{"name":"Subterfuge • Attack","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Ag/SD/In","app_stat_1":"Ag","app_stat_2":"SD","app_stat_3":"In","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.Zva3DO0Zmk3G5xWT"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898559045,"modifiedTime":1663840799076,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"gYP00F897jg2I6pC"} +{"name":"Artistic • Passive","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Em/In/Pr","app_stat_1":"Em","app_stat_2":"In","app_stat_3":"Pr","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.NTMvAPWeh5G55Kjs"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897462965,"modifiedTime":1663840713026,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"hFi8bJUxX2HvSoDj"} +{"name":"Athletic • Brawn","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Co/Ag","app_stat_1":"St","app_stat_2":"Co","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.VufLKW42mP7RtinG"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897509473,"modifiedTime":1663840714620,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"iC37JIsE5RETzyd6"} +{"name":"Spells • Own Realm Own Base Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.eEAr5sqnGKej7eiC"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898544500,"modifiedTime":1663840797285,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"iWL7y95CGF7Y1dAq"} +{"name":"Artistic • Active","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Pr/Em/Ag","app_stat_1":"Pr","app_stat_2":"Em","app_stat_3":"Ag","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.cEffILww7nn8vqJ7"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897441727,"modifiedTime":1663840706776,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"iZn6Hzq4cr0zY7Uk"} +{"name":"Power Point Development","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.Q7rKLS4gJwH2Lygw"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898277091,"modifiedTime":1663840769117,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"jOywgkFX58CVDn7z"} +{"name":"Armor • Heavy","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.7UA8xwzcBrKZfFk9"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897366792,"modifiedTime":1663840700907,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"k4IOyyJU8t7MAySl"} +{"name":"Spells • Other Realm Closed Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.7ka2nD2kPq6ixwWu"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898426199,"modifiedTime":1663840788519,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"kbOWBGenZjWIVqrC"} +{"name":"Awareness • Senses","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"In/SD/In","app_stat_1":"In","app_stat_2":"SD","app_stat_3":"In","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.QplAVXReCFVlKVB8"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897666266,"modifiedTime":1663840724332,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"pApyCNOxQb5sIOsf"} +{"name":"Weapon • 2-Handed","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.JiH6JhVoH9jrqptT"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898804378,"modifiedTime":1663840819146,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"qRNUoJcWrF2EmLSP"} +{"name":"Spells • Own Realm Closed Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.cyNDeZDye15gUFzA"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898478099,"modifiedTime":1663840792427,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"ruxbCKHjuGsdQ79z"} +{"name":"Outdoor • Animal","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Em/Ag/Em","app_stat_1":"Em","app_stat_2":"Ag","app_stat_3":"Em","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.6UjbXeI6IFrsdTEy"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898166391,"modifiedTime":1663840758805,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"v6tHhdaL7amLDnzR"} +{"name":"Outdoor • Environmental","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"SD/In/Me","app_stat_1":"SD","app_stat_2":"In","app_stat_3":"Me","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.49iK0oluVd5Z1fpc"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898214394,"modifiedTime":1663840760505,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"vM8rePr9QRXnG6HK"} +{"name":"Spells • Other Realm Base Lists","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"None","app_stat_1":"None","app_stat_2":"None","app_stat_3":"None","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.Wo1SrqGsgMYNoApO"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898426199,"modifiedTime":1663840786314,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"vlFr24F5zJ9fYzs7"} +{"name":"Urban","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"In/Pr/Re","app_stat_1":"In","app_stat_2":"Pr","app_stat_3":"Re","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.JAY4cM0lv1wZm3vo"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898721300,"modifiedTime":1663840812646,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"xHqAlnQjgEScetvh"} +{"name":"Martial Arts • Striking","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/St","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"St","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.HVistg0XNoVGsSKZ"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898114714,"modifiedTime":1663840754969,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"xJXObXAQcdPbSXg9"} +{"name":"Communcations","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"Re/Me/Em","app_stat_1":"Re","app_stat_2":"Me","app_stat_3":"Em","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.fh63pdckz6VYGAFc"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662897838640,"modifiedTime":1663840730283,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"xTzO3HPhQe5OS255"} +{"name":"Special Attacks","type":"skill_category","img":"systems/rmss/assets/default/skill_category.svg","system":{"description":"Description here.","applicable_stats":"St/Ag/SD","app_stat_1":"St","app_stat_2":"Ag","app_stat_3":"SD","development_cost":"0","ranks":0,"new_ranks":{"value":0,"max":3,"max_default":3},"rank_bonus":0,"stat_bonus":0,"prof_bonus":0,"special_bonus_1":0,"special_bonus_2":0,"total_bonus":0,"favorite":false},"effects":[],"ownership":{"default":0,"jFAyH93PxEe1ncxK":3},"flags":{"core":{"sourceId":"Item.by1LH6XYGWd5d9bs"}},"_stats":{"systemId":"rmss","systemVersion":"0.0.2","coreVersion":"10.285","createdTime":1662898332987,"modifiedTime":1663840775989,"lastModifiedBy":"jFAyH93PxEe1ncxK"},"folder":null,"sort":0,"_id":"yRIFroc5VC9Oj3qY"} diff --git a/rmss.css b/rmss.css new file mode 100644 index 0000000..04c8b12 --- /dev/null +++ b/rmss.css @@ -0,0 +1,519 @@ +.skillcat-grid-container { + display: grid; + grid-template-columns: [skill-category-name] 10% [applicable-stats] 10% [dev-cost] 8% [num-ranks] 8% [new-ranks] 8% [rank-bonus] 8% [stat-bonus] 8% [prof-bonus] 8% [special-bonus-1] 8% [special-bonus-2] 8% [total-bonus] 8% [controls] 8%; +} +.skillcat-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} +.skillcat-grid-container > div:nth-child(24n+1), +.skillcat-grid-container > div:nth-child(24n+2), +.skillcat-grid-container > div:nth-child(24n+3), +.skillcat-grid-container > div:nth-child(24n+4), +.skillcat-grid-container > div:nth-child(24n+5), +.skillcat-grid-container > div:nth-child(24n+6), +.skillcat-grid-container > div:nth-child(24n+7), +.skillcat-grid-container > div:nth-child(24n+8), +.skillcat-grid-container > div:nth-child(24n+9), +.skillcat-grid-container > div:nth-child(24n+10), +.skillcat-grid-container > div:nth-child(24n+11), +.skillcat-grid-container > div:nth-child(24n+12) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.skillcat-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.container { + display: flex; +} +.actor-icon { + flex-shrink: 1; +} +.favorite-container { + padding: 5px; +} +.header-container { + flex-grow: 2; + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.header-text { + display: flex; + align-items: center; + padding: 1px; +} +.settings-button, +.playersheet-settings { + font-family: Signika, sans-serif; + font-size: 12px; + margin-right: 6px; +} +.resource-container { + display: flex; + flex-direction: row; + flex-grow: 3; + text-align: -webkit-center; +} +.resource-container > * { + flex: 1 1 0; +} +.resource-entry { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.resource-entry input { + width: 50px; + border: none; +} +.stat-container { + flex-direction: column; + flex-shrink: 1; +} +.stat-row { + align-items: center; +} +.equipment-container { + flex-direction: column; + flex-grow: 1; +} +.stat-block { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.stat-name, +.money-name { + width: 75px; + border: none; + font-family: Signika, sans-serif; + font-size: 12px; +} +.stat-name input { + border: none; +} +.stat-header { + font-family: Signika, sans-serif; + font-size: 12px; +} +.fixed-info-container { + flex-grow: 3; + flex-direction: row; + font-family: Signika, sans-serif; + font-size: 12px; +} +.fixed-info-section { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.armor-block { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.race-stat-fixed-info-block { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.role-traits-block { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.background-info-block { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.resistance-block { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; +} +.red { + background-color: orangered; +} +.blue { + background-color: lightblue; +} +.grey { + background-color: lightgrey; +} +.green { + background-color: lightseagreen; +} +.skills-grid-container { + display: grid; + grid-template-columns: [favorite] 9% [skill-name] 11% [num-ranks] 9% [new-ranks] 9% [rank-bonus] 9% [category-bonus] 9% [item-bonus] 9% [special-bonus-1] 9% [special-bonus-2] 9% [total-bonus] 9% [controls] 8%; +} +.skills-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} +.skills-grid-container > div:nth-child(22n+1), +.skills-grid-container > div:nth-child(22n+2), +.skills-grid-container > div:nth-child(22n+3), +.skills-grid-container > div:nth-child(22n+4), +.skills-grid-container > div:nth-child(22n+5), +.skills-grid-container > div:nth-child(22n+6), +.skills-grid-container > div:nth-child(22n+7), +.skills-grid-container > div:nth-child(22n+8), +.skills-grid-container > div:nth-child(22n+9), +.skills-grid-container > div:nth-child(22n+10), +.skills-grid-container > div:nth-child(22n+11) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.skills-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.money-column { + flex-direction: column; +} +.money-container { + flex-direction: column; + flex-shrink: 1; + padding-left: 10px; +} +.items-grid-container { + display: grid; + grid-template-columns: [worn] 10% [name] 30% [quantity] 15% [weight] 15% [cost] 15% [controls] 15%; +} +.items-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} +.items-grid-container > div:nth-child(12n+1), +.items-grid-container > div:nth-child(12n+2), +.items-grid-container > div:nth-child(12n+3), +.items-grid-container > div:nth-child(12n+4), +.items-grid-container > div:nth-child(12n+5), +.items-grid-container > div:nth-child(12n+6) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.items-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.weapons-grid-container { + display: grid; + grid-template-columns: [name] 30% [equipped] 8% [breakage_range] 9% [fumble_range] 9% [strength] 9% [quantity] 9% [weight] 9% [cost] 9% [controls] 8%; +} +.weapons-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} +.weapons-grid-container > div:nth-child(18n+1), +.weapons-grid-container > div:nth-child(18n+2), +.weapons-grid-container > div:nth-child(18n+3), +.weapons-grid-container > div:nth-child(18n+4), +.weapons-grid-container > div:nth-child(18n+5), +.weapons-grid-container > div:nth-child(18n+6), +.weapons-grid-container > div:nth-child(18n+7), +.weapons-grid-container > div:nth-child(18n+8), +.weapons-grid-container > div:nth-child(18n+9) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.weapons-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.armor-grid-container { + display: grid; + grid-template-columns: [name] 30% [equipped] 12% [at] 12% [quantity] 12% [weight] 12% [cost] 12% [controls] 10%; +} +.armor-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} +.armor-grid-container > div:nth-child(14n+1), +.armor-grid-container > div:nth-child(14n+2), +.armor-grid-container > div:nth-child(14n+3), +.armor-grid-container > div:nth-child(14n+4), +.armor-grid-container > div:nth-child(14n+5), +.armor-grid-container > div:nth-child(14n+6), +.armor-grid-container > div:nth-child(14n+7) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.armor-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.herbs-grid-container { + display: grid; + grid-template-columns: [name] 30% [quantity] 11% [codes] 12% [af] 12% [weight] 12% [cost] 11% [controls] 12%; +} +.herbs-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} +.herbs-grid-container > div:nth-child(14n+1), +.herbs-grid-container > div:nth-child(14n+2), +.herbs-grid-container > div:nth-child(14n+3), +.herbs-grid-container > div:nth-child(14n+4), +.herbs-grid-container > div:nth-child(14n+5), +.herbs-grid-container > div:nth-child(14n+6), +.herbs-grid-container > div:nth-child(14n+7) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.herbs-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.spell-grid-container { + display: grid; + grid-template-columns: [favorite] 9% [level] 8% [name] 30% [spell_list] 9% [area_of_effect] 9% [duration] 9% [range] 9% [type] 9% [controls] 8%; +} +.spell-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; +} +.spell-grid-container > div:nth-child(18n+1), +.spell-grid-container > div:nth-child(18n+2), +.spell-grid-container > div:nth-child(18n+3), +.spell-grid-container > div:nth-child(18n+4), +.spell-grid-container > div:nth-child(18n+5), +.spell-grid-container > div:nth-child(18n+6), +.spell-grid-container > div:nth-child(18n+7), +.spell-grid-container > div:nth-child(18n+8), +.spell-grid-container > div:nth-child(18n+9) { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: row; + justify-content: center; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.spell-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.resistances-grid-container { + outline: 1px solid; + /* use instead of border */ + margin-top: 1px; + margin-left: 1px; + padding: 5px; + display: grid; + grid-template-columns: [Name] 40% [Value] 20% [Race_Mod] 20% [Total] 20%; +} +.resistances-grid-heading { + font-weight: bold; + border-bottom: 1px solid; + background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0); +} +.resistance-input { + width: 50%; +} +.skillcat-name, +.skill-name, +.item-name, +.spell-name, +.equipable-name { + font-family: Signika, sans-serif; + font-size: 12px; + font-weight: bold; + text-align: center; +} +.skillcat-entry, +.skill-entry, +.item-entry, +.spell-entry, +.equipable-entry { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} +.skillcat-headeritem, +.skill-headeritem, +.item-headeritem, +.spell-headeritem, +.equipable-headeritem { + text-align: center; + font-weight: bold; +} +.skillcat-controls, +.skill-controls, +.item-controls { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; +} +.applicable-stats-grid-container { + display: grid; + grid-template-columns: [app-stat-1] 33% [app-stat-2] 33% [app-stat-3] 33%; +} +.applicable-stats-grid-container > div { + font-family: Signika, sans-serif; + font-size: 12px; + text-align: center; + border-bottom: 1px solid; + padding-top: 3px; + padding-bottom: 3px; + display: flex; + justify-content: flex-end; + flex-direction: column; + justify-content: center; +} +.sheet form { + display: flex; + flex-direction: column; +} +.sheet .sheet-content { + height: 100%; + display: flex; + flex-direction: column; +} +.sheet .sheet-content .editor { + height: 100%; +} diff --git a/rmss.js b/rmss.js new file mode 100644 index 0000000..46cc9f7 --- /dev/null +++ b/rmss.js @@ -0,0 +1,111 @@ +// Import Configuration Object +import { rmss } from "./module/config.js"; + +// Import document classes. +import { RMSSActor } from "./module/documents/actor.js"; +import { RMSSItem } from "./module/documents/item.js"; + +// Import Sheets +import RMSSItemSheet from "./module/sheets/items/rmss_item_sheet.js"; +import RMSSArmorSheet from "./module/sheets/items/rmss_armor_sheet.js"; +import RMSSTransportSheet from "./module/sheets/items/rmss_transport_sheet.js"; +import RMSSWeaponSheet from "./module/sheets/items/rmss_weapon_sheet.js"; +import RMSSHerbOrPoisonSheet from "./module/sheets/items/rmss_herb_or_poison_sheet.js"; +import RMSSSpellSheet from "./module/sheets/spells/rmss_spell_sheet.js"; +import RMSSSkillCategorySheet from "./module/sheets/skills/rmss_skill_category_sheet.js"; +import RMSSSkillSheet from "./module/sheets/skills/rmss_skill_sheet.js"; + +import RMSSPlayerSheet from "./module/sheets/actors/rmss_player_sheet.js"; +import RMSSActorSheetConfig from "./module/sheets/actors/rmss_player_sheet_config.js"; + +/** Preload handlebars templates for character sheets */ +async function preloadHandlebarsTemplates() { + const templatePaths = [ + "systems/rmss/templates/sheets/actors/parts/actor-stats.html", + "systems/rmss/templates/sheets/actors/parts/actor-fixed-info.html", + "systems/rmss/templates/sheets/actors/parts/actor-armor-info.html", + "systems/rmss/templates/sheets/actors/parts/actor-resistance.html", + "systems/rmss/templates/sheets/actors/parts/actor-race-stat-fixed-info.html", + "systems/rmss/templates/sheets/actors/parts/actor-role-traits.html", + "systems/rmss/templates/sheets/actors/parts/actor-background-info.html", + "systems/rmss/templates/sheets/actors/parts/actor-skill-categories.html", + "systems/rmss/templates/sheets/actors/parts/actor-skills.html", + "systems/rmss/templates/sheets/actors/parts/actor-fav-skills.html", + "systems/rmss/templates/sheets/actors/parts/actor-items.html", + "systems/rmss/templates/sheets/actors/parts/actor-weapons.html", + "systems/rmss/templates/sheets/actors/parts/actor-money.html", + "systems/rmss/templates/sheets/actors/parts/actor-skill-categories.html", + "systems/rmss/templates/sheets/actors/parts/actor-skills.html", + "systems/rmss/templates/sheets/actors/parts/actor-armor.html", + "systems/rmss/templates/sheets/actors/parts/actor-herbs.html", + "systems/rmss/templates/sheets/actors/parts/actor-spells.html", + "systems/rmss/templates/sheets/actors/parts/actor-fav-spells.html", + "systems/rmss/templates/sheets/actors/parts/actor-fav-items.html", + "systems/rmss/templates/sheets/actors/apps/actor-settings.html" + ]; + return loadTemplates(templatePaths); +} + +// Hook the init function and set up our system +Hooks.once("init", function() { + console.log("rmss | Initialising Rolemaster Standard System"); + + // Load our custom actor and item classes + console.log("rmss | Loading Rolemaster Actor and Item classes"); + game.rmss = { + RMSSActor, + RMSSItem, + applications: { + RMSSActorSheetConfig + } + }; + + // Define custom Document classes + CONFIG.Actor.documentClass = RMSSActor; + CONFIG.Item.documentClass = RMSSItem; + + // Make Config Data Available + CONFIG.rmss = rmss; + + // Unregister Default Sheets + console.log("rmss | Unregistering core sheets"); + + Items.unregisterSheet("core", ItemSheet); + Actors.unregisterSheet("core", ActorSheet); + + // Register RMSS Sheets + console.log("rmss | Registering RMSS sheets"); + + // Items + Items.registerSheet("rmss", RMSSItemSheet, {makeDefault: true, label: "rmss.entity_sheet.item", types: ["item"]}); + Items.registerSheet("rmss", RMSSArmorSheet, {makeDefault: true, label: "rmss.entity_sheet.armor", types: ["armor"]}); + Items.registerSheet("rmss", RMSSTransportSheet, {makeDefault: true, label: "rmss.entity_sheet.transport", types: ["transport"]}); + Items.registerSheet("rmss", RMSSWeaponSheet, {makeDefault: true, label: "rmss.entity_sheet.weapon", types: ["weapon"]}); + Items.registerSheet("rmss", RMSSHerbOrPoisonSheet, {makeDefault: true, label: "rmss.entity_sheet.herb_or_poison", types: ["herb_or_poison"]}); + + // Spells + Items.registerSheet("rmss", RMSSSpellSheet, {makeDefault: true, label: "rmss.entity_sheet.spell", types: ["spell"]}); + + // Skills + Items.registerSheet("rmss", RMSSSkillCategorySheet, {makeDefault: true, label: "rmss.entity_sheet.skill_category", types: ["skill_category"]}); + Items.registerSheet("rmss", RMSSSkillSheet, {makeDefault: true, label: "rmss.entity_sheet.skill", types: ["skill"]}); + + // Actors + Actors.registerSheet("rmss", RMSSPlayerSheet, {makeDefault: true, label: "rmss.entity_sheet.player_characrer", types: ["character"]}); + + // Preload Handlebars Templates + console.log("rmss | Preloading Handlebars Templates"); + preloadHandlebarsTemplates(); + + // Handlebars Helpers + Handlebars.registerHelper("switch", function(value, options) { + this.switch_value = value; + return options.fn(this); + }); + + Handlebars.registerHelper("case", function(value, options) { + if (value === this.switch_value) { + return options.fn(this); + } + }); +}); diff --git a/system.json b/system.json new file mode 100644 index 0000000..3e0673e --- /dev/null +++ b/system.json @@ -0,0 +1,45 @@ +{ + "name": "fvtt-rolemaster-frp", + "title": "Rolemaster FRP System", + "description": "The Rolemaster FRP system for FoundryVTT.", + "manifest": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/raw/branch/develop/rmss/system.json", + "authors": [ + { + "name": "Cynicide", + "email": "" + }, + { + "name": "LeRatierBretonnien", + "email": "" + } + ], + "version": "12.0.0", + "compatibility": { + "minimum": "12", + "verified": "12" + }, + "esmodules":[ + "rmss.js" + ], + "styles": ["rmss.css"], + "packs": [ { + "name": "skill_categories", + "label": "Skill Categories", + "system": "fvtt-rolemaster-frp", + "path": "./packs/skill_categories.db", + "type": "Item" + } + ], + "languages": [ + { + "lang": "en", + "name": "English", + "path": "lang/en.json" + } + ], + "grid": { + "distance": 5, + "units": "ft" + }, + "license": "LICENSE.txt" +} diff --git a/template.json b/template.json new file mode 100644 index 0000000..a7375f5 --- /dev/null +++ b/template.json @@ -0,0 +1,355 @@ +{ + "Actor": { + "types": ["character", "npc"], + "templates": { + "role_traits": { + "role_traits": { + "appearance": 0, + "sex": "", + "skin": "", + "apparent_age": 0, + "actual_age": 0, + "height": "", + "weight": "", + "hair": "", + "eyes": "", + "personality": "", + "motivations": "", + "alignment": "" + } + }, + "race_stat_fixed_info": { + "race_stat_fixed_info" : { + "soul_departure_rounds": 0, + "recovery_multiplier": 0, + "body_development_progression": "", + "pp_development_progression": "", + "recover_hits_per_hour_resting": 0, + "recover_hits_per_sleep_cycle": 0, + "recover_pp_per_hour_resting": 0, + "recover_pp_per_sleep_cycle": 0 + } + }, + "armor_info": { + "armor_info": { + "armor_type": 0, + "mmp": 0, + "weight_penalty": 0, + "missile_penalty": 0, + "quickness_penalty": 0, + "quickness_bonus": 0, + "adrenal_defense": 0, + "shield_bonus": 0, + "magic": "", + "total_db": 0 + } + }, + "fixed_info": { + "fixed_info": { + "race": "", + "profession": "", + "training_packages": "", + "realm": "" + } + }, + "resistance_rolls": { + "resistance_rolls": { + "channeling": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "essence": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "mentalism": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "chann_ess": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "chann_ment": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "ess_ment": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "arcane": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "poison_disease": { + "value": 0, + "race_mod": 0, + "total": 0 + }, + "fear": { + "value": 0, + "race_mod": 0, + "total": 0 + } + } + }, + "background": { + "background": { + "nationality": "", + "home_town": "", + "deity": "", + "patron": "", + "parents": "", + "spouse": "", + "children": "", + "other": "" + } + }, + "stats": { + "stats": { + "agility": { + "shortname": "Ag", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "constitution": { + "shortname": "Co", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "memory": { + "shortname": "Me", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "reasoning": { + "shortname": "Re", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "self_discipline": { + "shortname": "SD", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "empathy": { + "shortname": "Em", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "intuition": { + "shortname": "In", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "presence": { + "shortname": "Pr", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "quickness": { + "shortname": "Qu", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + }, + "strength": { + "shortname": "St", + "temp": 0, + "potential": 0, + "basic_bonus": 0, + "racial_bonus": 0, + "special_bonus": 0, + "stat_bonus": 0 + } + } + }, + "money": { + "money": { + "mithril": 0, + "platinum": 0, + "gold": 0, + "silver": 0, + "bronze": 0, + "copper": 0, + "tin": 0, + "iron": 0 + } + } + }, + "character": { + "templates": ["background", "stats", "resistance_rolls", "armor_info", "fixed_info", "race_stat_fixed_info", "role_traits", "money", "description"], + "attributes": { + "level": { + "value": 1 + }, + "hits": { + "current": 1, + "max": 1 + }, + "exhaustion_points": { + "current": 1, + "max": 1 + }, + "power_points": { + "current": 1, + "max": 1 + }, + "experience_points": { + "value": 0 + } + }, + "description": "" + } + }, + "Item": { + "types": ["item", "skill_category", "skill", "armor", "weapon", "transport", "herb_or_poison", "spell", "language"], + "templates": { + "base": { + "description": "Description here." + } + }, + "item": { + "templates": ["base"], + "worn": false, + "quantity": 1, + "weight": 0, + "cost": 0, + "prod_time": 0 + }, + "transport": { + "templates": ["base"], + "feet_per_round": 1, + "miles_per_hour": 0, + "cost": 0, + "maneuver": 0, + "height": 0, + "weight": 0, + "capacity": 0, + "offensive_bonus": 0 + }, + "armor": { + "templates": ["base"], + "equipped": false, + "quantity": 1, + "weight": 0, + "cost": 0, + "prod_time": 0, + "at": 0 + }, + "weapon": { + "templates": ["base"], + "equipped": false, + "quantity": 1, + "cost": 0, + "weight": 0, + "type" : "", + "prod_time": 0, + "at": 0, + "breakage_range": "", + "strength": "", + "fumble_range": "" + }, + "herb_or_poison": { + "templates": ["base"], + "quantity": 1, + "weight": 0, + "codes": "", + "form_and_prep" : "", + "cost": 0, + "af": 0 + }, + "skill": { + "templates": ["base"], + "category" : "", + "ranks": 0, + "new_ranks": { + "value": 0, + "max": 3, + "max_default": 3 + }, + "rank_bonus": -15, + "category_bonus": 0, + "item_bonus": 0, + "special_bonus_1": 0, + "special_bonus_2": 0, + "total_bonus": 0, + "favorite": false, + "designation": "None" + }, + "skill_category": { + "templates": ["base"], + "applicable_stats": "None", + "app_stat_1": "None", + "app_stat_2": "None", + "app_stat_3": "None", + "development_cost": "0", + "ranks": 0, + "new_ranks": { + "value": 0, + "max": 3, + "max_default": 3 + }, + "rank_bonus": -15, + "stat_bonus": 0, + "prof_bonus": 0, + "special_bonus_1": 0, + "special_bonus_2": 0, + "total_bonus": 0, + "favorite": false + }, + "spell": { + "favorite": false, + "spell_list": "", + "level": 1, + "area_of_effect": "", + "duration": "", + "range": "", + "type": "", + "description": "Description here." + } + } +} diff --git a/templates/sheets/actors/apps/actor-settings.html b/templates/sheets/actors/apps/actor-settings.html new file mode 100644 index 0000000..d6187d1 --- /dev/null +++ b/templates/sheets/actors/apps/actor-settings.html @@ -0,0 +1,17 @@ +
\ No newline at end of file diff --git a/templates/sheets/actors/parts/actor-armor-info.html b/templates/sheets/actors/parts/actor-armor-info.html new file mode 100644 index 0000000..9f64dc2 --- /dev/null +++ b/templates/sheets/actors/parts/actor-armor-info.html @@ -0,0 +1,62 @@ +{{ localize "rmss.pc_sheet_items.item_name" }} |
+ {{ localize "rmss.armor.at" }} |
+ {{ localize "rmss.weapon.breakage_range" }} |
+ {{ localize "rmss.weapon.fumble_range" }} |
+ {{ localize "rmss.weapon.strength" }} |
+ {{#each armor as |equipable id|}}
+ {{#if equipable.system.equipped}}
+
---|---|---|---|---|
+ {{equipable.name}}+ |
+ {{equipable.system.at}} |
+ - |
+ - |
+ - |
+
+ {{weapon.name}}+ |
+ - |
+ {{weapon.system.breakage_range}} |
+ {{weapon.system.fumble_range}} |
+ {{weapon.system.strength}} |
+
{{ localize "rmss.pc_sheet_skills.skill_name" }} |
+ {{ localize "rmss.pc_sheet_skills.ranks" }} |
+ {{ localize "rmss.pc_sheet_skills.total_bonus" }} |
+ {{#each playerskill as |skill id|}}
+ {{#if skill.system.favorite}}
+
---|---|---|
+ {{skill.name}}+ |
+ {{skill.system.ranks}} |
+ {{skill.system.total_bonus}} |
+
{{ localize "rmss.pc_sheet_spell.name" }} |
+ {{ localize "rmss.pc_sheet_spell.area_of_effect" }} |
+ {{ localize "rmss.pc_sheet_spell.duration" }} |
+ {{ localize "rmss.pc_sheet_spell.range" }} |
+ {{ localize "rmss.pc_sheet_spell.type" }} |
+ {{#each spells as |spell id|}}
+ {{#if spell.system.favorite}}
+
---|---|---|---|---|
+ {{spell.name}}+ |
+ {{spell.system.area_of_effect}} |
+ {{spell.system.duration}} |
+ {{spell.system.range}} |
+ {{spell.system.type}} |
+
{{ localize "rmss.pc_sheet_language.name" }} |
+ {{ localize "rmss.pc_sheet_language.spoken" }} |
+ {{ localize "rmss.pc_sheet_language.written" }} |
+ |
---|---|---|---|
+ {{language.name}}+ |
+ {{language.system.spoken}} |
+ {{language.system.written}} |
+ + |