master
Mimi Momo 2 years ago
parent 6d997f3f62
commit a3b24c220f

@ -15,3 +15,10 @@
<li>???✓ </li>
<li>rebinding controls✗ </li>
</ul>
<h2>wishlist</h2>
<ul>
<li>ESC - closes dialogue window, shop window </li>
<li>right-click entity - inspect </li>
<li>I - open inventory </li>
<li>tab - scan through nearest to farthest foes </li>
</ul>

@ -7,6 +7,9 @@
<h2>things I don't like in games</h2>
<ul>
<li>How long does it take to get into the game, and is it a reasonable amount of time? </li>
<li>Some kind of hint as to where you are in the game and how to quickly refresh on mechanics, for players who left for years </li>
<li>If it isn't replayable, maybe one part is too much of a drag, the puzzle was only fun to solve once, each playthrough is not new and variable. Also in that case, probably no point to play, better to just watch. </li>
<li>when game ignores the lore - permadeath for the young and vigorous in a world with plenty of resurrection </li>
<li>losing control of your own character for an extended period - knockdown room </li>
<li>forcing player to act stupidly - story won't progress until you trigger an obvious trap, sign a bad contract, etc </li>

@ -0,0 +1,5 @@
<h2>wishlist</h2>
<ul>
<li>close dialogue if player or other party moves away too far </li>
<li>ESC/rebindable closes dialogue window </li>
</ul>

@ -6,3 +6,5 @@
<p>Armor typically increases spirit by a total of 20 for armsman; 25 for tamer and brawler; and 30 for hacker, disciple, and chemist. </p>
<p>Armor typically increases spirit regen by a total of +2 for armsman; +3 for tamer; and +4 for hacker, disciple, chemist, brawler. </p>
<h2>weapons</h2>
<p>Flashlight is an off-hand equippable. It is functional, casting a persistent light area skill. It provides neglible stats.</p>

@ -0,0 +1,5 @@
<h2>wishlist</h2>
<ul>
<li>target stays highlighted, highlight any hover also. </li>
<li>change target, unhighlight previous target </li>
</ul>

@ -1,26 +1,27 @@
<h2>description </h2>
<p>Right-click on an tangible entity or inventory item to open a popup inspect menu with all relevant inspect options. Selecting one will execute a method. Examples are 'follow Chloe' (pathfind after Chloe wherever she moves until action is cancelled), 'pick up clover' (item pickup), and 'examine button' (write a descriptive line about her in Helia's thought bubble) <br></p>
<br>
<p>Right-click on an tangible entity or inventory item to open a popup inspect menu with all relevant inspect options. Selecting one will execute a method. Examples are 'follow Chloe' (pathfind after Chloe wherever she moves until action is cancelled), 'pick up clover' (item pickup), and 'examine button' (write a descriptive line about her in Helia's thought bubble) </p>
<h2>structure </h2>
<p>Every tangible entity has an exported dictionary of inspect_options: {index: ['tr_key', 'method']}. For example, {0:['tr_pick up','pickup'],1:['tr_extinguish','extinguish']}. Every tangible appends 'examine' at ready. <br></p>
<br>
<p>The Clickable has a _ready input event signal looking for "right-click." <br></p>
<br>
<p>The inspect menu ("res://UI/InspectMenu/InspectMenu.tscn") is instanced at declaration and added as a child at ready in the UI singleton. <br></p>
<br>
<p>Every tangible entity has an exported dictionary of inspect_options: {index: ['tr_key', 'method']}. For example, {0:['tr_pick up','pickup'],1:['tr_extinguish','extinguish']}. Every tangible appends 'examine' at ready. </p>
<p>The Clickable has a _ready input event signal looking for "right-click." </p>
<p>The inspect menu ("res://UI/InspectMenu/InspectMenu.tscn") is instanced at declaration and added as a child at ready in the UI singleton. </p>
<h2>logic </h2>
<p>When tangible entity is right-clicked (@ $Body/Sprite/Clickable), the UI enters InspectMenu with its subject set. (The subject setter also sets the player's target.) The "id_pressed" signal is reset for each subject. InspectMenu connects "about_to_show" the first time it's needed and keeps it forever. Before popup(), it resets, adds a label at an offset with the subject's display name, then adds a UI option for each inspect option. <br></p>
<br>
<p>When a selection is made, the "id_pressed" signal calls "id_pressed" on the subject, which calls the method at its inspect_options[pressed_id][1]. So 'examine' calls 'examine,' which is in tangible.gd. Most related methods are on tangible.gd, though they may be at a more specific script. <br></p>
<p>When tangible entity is right-clicked (@ $Body/Sprite/Clickable), the UI enters InspectMenu with its subject set. (The subject setter also sets the player's target.) The "id_pressed" signal is reset for each subject. InspectMenu connects "about_to_show" the first time it's needed and keeps it forever. Before popup(), it resets, adds a label at an offset with the subject's display name, then adds a UI option for each inspect option. </p>
<p>When a selection is made, the "id_pressed" signal calls "id_pressed" on the subject, which calls the method at its inspect_options[pressed_id][1]. So 'examine' calls 'examine,' which is in tangible.gd. Most related methods are on tangible.gd, though they may be at a more specific script.</p>
<p>Only one inspect menu can be open at a time. </p>
<h2>challenges/known issues </h2>
<p>It's not obvious how to get popupmenus to appear at specific coordinates. I get it to appear at the subject's current location by setting <code>rect_global_position = get_global_mouse_position()</code> the line immediately after <code>popup()</code>. <br></p>
<br>
<p>The inspect menu retains the largest ever size going forward. I reset the size to 20,20 when clearing previous options. <br></p>
<br>
<p>Tangibles and inventory items both have inspect menus, but their code has to be separate. They are too different from each other. <br></p>
<br>
<p>It doesn't close the inspect menu if pickup is chosen while item out of range, even after item is picked up. <br></p>
<br>
<p>It's not obvious how to get popupmenus to appear at specific coordinates. I get it to appear at the subject's current location by setting <code>rect_global_position = get_global_mouse_position()</code> the line immediately after <code>popup()</code>. </p>
<p>The inspect menu retains the largest ever size going forward. I reset the size to 20,20 when clearing previous options. </p>
<p>Tangibles and inventory items both have inspect menus, but their code has to be separate. They are too different from each other. </p>
<p>It doesn't close the inspect menu if pickup is chosen while item out of range, even after item is picked up. </p>
<h2>works for...</h2>
<ul>
<li>player✓ </li>

@ -1,2 +1,28 @@
<p>Keywords are the building blocks of skills. <br></p>
<h2>wishlist</h2>
<ul>
<li>stance </li>
<li>AoE </li>
<li>mark </li>
<li>make sure aloe drop heals burning (remove applied_effects has good cleanup)</li>
<li>pacificism (can't use attack skills, weapon swings. maybe on specific target, maybe at all)</li>
<li>Any Degen pips remove natural Regen pips (What if something has natural NEGATIVE Regen pips?) </li>
<li>Flash cannot be interrupted </li>
<li>Attack: One-time loss of Life that is affected by the targets armor. Damage value is rolled for a chance to crit with a higher value. Usually deals melee or ranged damage. Weapon swings are imparting this keyword onto their target. Attack for 50 damage. </li>
<li>Damage: Loss of Life. </li>
<li>If </li>
<li>Heal: One-time gain of Life. Technically applies negative damage points through the characters damage method. (Keyword itself makes the value negative, so skills, etc, will feed it a positive number.) Heal for 5 life every 1 second. </li>
<li>Life Drain: Continuous loss of life from the target and gain of life for the user over time. </li>
<li>Life Gain/Loss: One-time gain or loss of Life. Same as Attack/Heal? Lose 50 Life. </li>
<li>Life Regeneration/Degeneration: Continuous gain or loss of life over time. -1 Life Degeneration (30 seconds). </li>
<li>Life Steal: One time loss of life from the target and gain of life for the user. </li>
<li>Spirit Regeneration/Degeneration: Continuous gain or loss of spirit over time. -1 Spirit Degeneration (20 seconds). </li>
<li>Spirit Gain/Loss: One-time gain or loss of Spirit. Same keyword positive = loss | negative = gain When spirit loss is triggered by skill usage (“Whenever user uses a skill, user gains 5 spirit”), when should spirit loss be applied? At use doesnt recover trigger skill cost. Lose 50 Spirit. </li>
<li>Mark: </li>
<li>Poison: Conveys a negative effect over a duration. </li>
<li>Spiritual Damage: Loss of Spirit </li>
<li>Status Effect </li>
<li>Weapon Swing: Basic attack by an entity. No skill necessary, just press the attack button once to continuously perform weapon swings on the target until canceled, dead, or target dead. Affected by stats of equipped weapon and active keywords. </li>
<li>Wait: Technically a when</li>
</ul>

@ -5,3 +5,9 @@
<li>Come up with default builds for teammates </li>
<li>Design a weapon, costume, boss. Or simply name them. </li>
</ul>
<h2>extras</h2>
<ul>
<li>Steam extras. Badges, achievements, card drops, backgrounds, desirable emoticons for conversion in general, probably more things I don't know about.</li>
<li>Art book, storybook (canon, side, or alternative), comic book, cards, 3D paper, paper dolls </li>
</ul>

@ -25,4 +25,7 @@
<li>move to target but don't attack✗ </li>
<li>move to target then interact✗ </li>
</ul>
<h2>wishlist</h2>
<ul>
<li>pathfinding to points outside of bounds - need to readjust to one within bounds, otherwise character runs into obstacles </li>
</ul>

@ -1,2 +1,7 @@
<img src="/static/img/gdd/projectiles.png" alt="(photo)">
<img src="/static/img/gdd/bodies.png" alt="(photo)">
<h2>wishlist</h2>
<ul>
<li>despawn projectiles that hit obstructions </li>
</ul>

@ -1,7 +1,13 @@
<h2>description </h2>
<p>Skills are individual powers usable by entities. They can take 8 at a time on their skillbar. They can be used for combat, puzzle-solving, and roleplaying. They are acquired through exploring. </p>
<h2>flow </h2>
<h2>skill acquisition </h2>
<ul>
<li>basic job skills are learned when the job is unlocked, temporarily or permanently </li>
<li>update skill list if skill was added (MessageBus)<li>
<li>giantess NPC that will allow the player to make some custom skills (dropdown menu for parts of a skill desc sentence -> exported to JSON)</li>
</ul>
<h2>skill usage flow</h2>
<ul>
<li>Skill button pressed </li>
<li>Used
@ -31,3 +37,4 @@
<p>A skill prematurely ends if it is removed (the remove keyword targets applied skills) or reapplied (a duplicate skill ends earlier instances of the skill then is applied normally). </p>
<p>When a skill ends for any reason, all keywords must also end. </p>

@ -1 +1,7 @@
<img src="/static/img/gdd/Appstore.png" alt="(photo)">
<h2>wishlist</h2>
<ul>
<li>apps are to smartphones as scenes are to windows </li>
<li>apps are entities </li>
</ul>

@ -15,3 +15,6 @@
<li>✗ </li>
<li>✓ </li>
</ul>
<h2>wishlist</h2>
<ul>
<li>make sure only status effects are added to applied effects </li>

@ -0,0 +1,4 @@
<h2>wishlist</h2>
<ul>
<li>ESC/rebindable closes shop window </li>
</ul>

@ -1167,6 +1167,13 @@ Helia comes to the security office to pick up her luggage, but it isn't on the r
<li>Night betrays Helia </li>
<li>School brick fundraiser </li>
<li>Night's secret place </li>
<li>Mecha Angel, robo Angel </li>
<li>Black pond portal </li>
<li>Tessa breaks up with her boyfriend </li>
<li>Tessa dates a very minor celebrity </li>
<li>Angel wants you to playtest her game </li>
<li>sea of stars - crystals set against a black void or cave water </li>
<li>nebraska ocean </li>
</ul>
</div>
<div class="character" id="character"><h3>character tidbits </h3>
@ -1220,16 +1227,6 @@ Helia comes to the security office to pick up her luggage, but it isn't on the r

@ -1,23 +1,53 @@
<p><ul>
<p>in use</p>
<ul>
<li><b>activation</b>: the activation must complete before the skill can begin functioning. After a successful activation, the skill penalties are applied. If activation fails, no penalties are applied. Flash skills activate instantly and cannot fail. </li>
<li><b>attack</b>: An aggressive action that begins combat. </li>
<li><b><a href="/blessfrey-gdd/item">base item</a></b>: the core of data of an individual item. Floor items and inventory items contain a base item. </li>
<li><b>base max health</b>: characters expected max health, calculated by level. The formula is 100 + 10 * get_character().find_level(get_character().get_xp()).</li>
<li><b>combat</b>: </li>
<li><b>cost</b>: a price must be paid before a skill is used. The main currency for skills is spirit, which is taken after a successful skill activation.</li>
<li><b><a href="/blessfrey-gdd/pathfinding">current_dot</a></b>: (DG era variable, StateMachine.gd) the immediate point the entity is pathfinding to in order to ultimately reach the goal_target. </li>
<li><b><a href="/blessfrey-gdd/proxemics">degrees(❥)</a></b>: (concept) the unit of social distance </li>
<li><b><a href="/blessfrey-gdd/pathfinding">dot</a></b>: (DG era variable, StateMachine.gd) a set of coordinates for a global position. </li>
<li><b><a href="/blessfrey-gdd/pathfinding">dots</a></b>: (DG era variable, StateMachine.gd) the discreet path between points, esp. the entity and the goal target. </li>
<li><b>equipped<b>: for skills, this has two meanings. Known skills that are loaded into an entitys skillbar are equipped. A player would not be aware that all hidden and subskills are also equipped to their entity before they are used, but these are not equipped to the skillbar.</li>
<li><b>event</b>: anything that happens in the game that brings about an effect. Using a skill, completing a quest, using a specific item, walking steps, starting the game, entering a room, etc...</li>
<li><b>event handler</b>: An object that subscribes to the MessageBus and waits to receive notification of the event when it happens. The event topic usually comes bundled with data that helps the handler bring about some kind of effect. Responses include level up rewards, quest rewards, world changes, new dialog options, adding an item to the inv, updating UI, etc. </li>
<li><b><a href="/blessfrey-gdd/item">floor item</a></b>: </li>
<li><b><a href="/blessfrey-gdd/pathfinding">goal target</a></b>: (DG era variable, MoveToDestination.gd) It is set when the entity decides to pathfind and nulled during clear_goal(). mobile.gd/path_to_object(goal_target) is called from MoveToDestination every Execute loop to reassess the path between entity and goal. </li>
<li><b><a href="/blessfrey-gdd/knowledgebase">KnowledgeBase</a></b>: </li>
<li><b><a href="/blessfrey-gdd/inspect">inspect menu</a></b>: (UI) presents options for interacting with the subject </li>
<li><b><a href="/blessfrey-gdd/proxemics">intimate distance</a></b>: 45❥, declared at mobile.gd/intimate_space </li>
<li><b><a href="/blessfrey-gdd/item">inventory item</a></b>: </li>
<li><b>life</b>: Health points. Entity dies at 0 life. Entity experiences life regeneration over time when not in combat. </li>
<li><b><a href="/blessfrey-gdd/item">item</a></b>: varies in form depending on its context - base item, floor item, inventory item, merchandise </li>
<li><b>max health</b>: characters actual max health, affected by the max_health addend and max_health factor. The formula is get_max_health() * get_max_health_factor() + get_max_health_addend().</li>
<li><b><a href="/blessfrey-gdd/item">merchandise</a></b>: </li>
<li><b><a href="/blessfrey-gdd/Mercur">Mercur</a></b>: generic attribution for events </li>
<li><b><a href="/blessfrey-gdd/MessageBus">MessageBus</a></b>: </li>
<li><b><a href="/blessfrey-gdd/pathfinding">next</a></b>: (DG era variable, StateMachine.gd) same as the goal_target. The current waypoint for the entity. </li>
<li><b><a href="/blessfrey-gdd/pathfinding">next_dot</a></b>: (DG era variable, StateMachine.gd) the first item in the dots array that is not at the entity's global_position. </li>
<li><b>Penalty</b>: Skill penalties typically include a skill cost and skill cooldown. They are only paid after the skill successfully activates.</li>
<li><b><a href="/blessfrey-gdd/proxemics">personal distance</a></b>: 60❥, declared at mobile.gd/personal_space </li>
<li><b><a href="/blessfrey-gdd/proxemics">proxemics</a></b>: (concept) interentitic, mechanical distances </li>
<li><b>side-load</b>: skills can be side-loaded onto the skillbar, avoiding skillbar equip rules, with skills that copy or permanently replace with other skills (Signet of Skill Capture, Arcane Thievery, etc). Also, skills that are offered in a room (i.e., Chloe offers you a temporary Holy Water skill while you are doing the mission)</li>
<li><b>skill</b>: individual power usable by an entity to modify the attributes other entities. They are represented by an ID. To be used, they are instanced into individual containers and managed by individual DMVs</li>
<li><b>skill library, skill pool</b>: each entity has its own, full of all its known skills </li>
<li><b><a href="/blessfrey-gdd/proxemics">social distance</a></b>: 90❥, declared at mobile.gd/social_space </li>
<li><b>skillbar</b>: each entity has its own, full of its equipped skills. There is a limit of 8 skills, 1 elite skill, and no repeating skills. Side-loaded skills avoid these restrictions, but the skillbar will be governed upon zoning. </li>
<li><b>spirit</b>: energy points. Entity experiences spirit regeneration at all time.</li>
<li><b><a href="/blessfrey-gdd/inspect">subject</a></b>: inspect menu has a subject; inspect options will affect it </li>
<li><b><a href="/blessfrey-gdd/pathfinding">swing</a></b>: (BF era action, ???.gd) Encompasses both weapon swings and the use phase of weapon attack skills. </li>
</ul>
<p>in use soon? or never?</p>
<ul>
<li><b>ActivationUse</b>: a skill is considered used once a skillequip has been entered. It will immediately begin activating.</li>
<li><b>arsenal</b>: a list of SkillEquips. Skills are represented as IDs and must be instanced into a container before they can be used by an entity. The instances are appended to the entitys skill arsenal upon being equipped. </li>
<li><b>remove by tag</b>: published to remove keywords by tag.</li>
<li><b>skill tagged</b>: published during keyword setup; sends tags and the keyword</li>
<li><b>skill untagged</b>: published when keyword is untagged, like during keyword teardown; sends tags and the keyword. </li>
<li><b>SkillEquip</b>: an instance containing a skill and information about its cooldown status. A skill needs one in order to be used.</li>
<li><b>tag removed</b>: published when a tag was requested to be removed. It wont be published if the tags keyword expires naturally. It sends its tags, the keyword, and the source of removal. </li>
<li><b><a href="/blessfrey-gdd/pathfinding">track</a></b>: (DG era variable, MoveToDestination.gd) If the AI is pathfinding to a point or object, track is true. Upon arrived(), it is false. It is checked in handle_moved_result(result, entity).</li>
<li><b><a href="/blessfrey-gdd/pathfinding">waypoints</a></b>: (DG era variable, StateMachine.gd) the list of selected points the entity will be traveling to. Usually a patrol route. </li>
</ul></p>
</ul>

@ -0,0 +1,9 @@
<h2>wishlist</h2>
<ul>
<li>save positions of UI plates at close/tree_exit </li>
<li>if windows were dragged outside of viewport, should I save outside coords or the nearest coords that are fully within the viewport? </li>
<li>only open one instance of a window at a time (open chest once) </li>
<li>close plates with their hotkeys and/or esc
window scenes share a base </li>
<li>custom cursor</li>
</ul>

@ -2,7 +2,7 @@
<li>role: student </li>
<li>age: teens </li>
<li>birthday: March 18 </li>
<li>mental: smart, logical, overly blunt </li>
<li>mental: smart, logical, overly blunt, disciplined, egalitarian </li>
<li>physical: average, toned, very pale, very short fair hair, pale green eyes </li>
<li>height: 5'7 </li>
<li>style: bold colors, color blocking, active wear </li>

@ -0,0 +1,12 @@
<ul>
<li><b>role:</b> gym teacher </li>
<li><b>age:</b> 20s-30s </li>
<li><b>birthday:</b> </li>
<li><b>mental:</b> naturally intimidating and forceful, focused on more important things or otherwise distracted from the task at hand, always manages to kill all her students during shooter drills, crass </li>
<li><b>physical:</b> tall, big breasts, athletic </li>
<li><b>height:</b> </li>
<li><b>style:</b> </li>
<li><b>residence:</b> </li>
<li><b>likes:</b> </li>
<li><b>dislikes:</b> </li>
</ul>

@ -0,0 +1 @@
<p>lots of absurd rumors (used to run a gang)</p>

@ -0,0 +1 @@
Name Danika Blake | means <i>?</i> | job♀

@ -2,7 +2,7 @@
<li><b>role:</b> transfer student </li>
<li><b>age:</b> teens </li>
<li><b>birthday:</b> whenever </li>
<li><b>mental:</b> kind of rude </li>
<li><b>mental:</b> kind of rude and antisocial </li>
<li><b>physical:</b> short, blonde front ponytail with chunks of burgundy and flaming orange, hot pink eyes </li>
<li><b>style:</b> DIY fashion </li>
<li><b>height:</b> 5'1 </li>

@ -2,8 +2,8 @@
<li><b>role:</b> teacher </li>
<li><b>age:</b> 20s-30s </li>
<li><b>birthday:</b> December 5 </li>
<li><b>mental:</b> </li>
<li><b>physical:</b> </li>
<li><b>mental:</b> tries too hard to be taken seriously </li>
<li><b>physical:</b> dishwater blonde, confused for a student </li>
<li><b>height:</b> </li>
<li><b>style:</b> </li>
<li><b>residence:</b> </li>

@ -2,7 +2,7 @@
<li><b>role:</b> pharmacist </li>
<li><b>age:</b> teens </li>
<li><b>birthday:</b> </li>
<li><b>mental:</b> genius, haughty </li>
<li><b>mental:</b> genius, haughty, instrumental love </li>
<li><b>physical:</b> short, thin but without muscles, dark hair, light blue eyes, pale </li>
<li><b>style:</b> relatively formal, lots of suit jackets and vests with pops of bold colors </li>
<li><b>height:</b> 5'5 </li>

@ -2,7 +2,7 @@
<li><b>role:</b> floor guardian </li>
<li><b>age:</b> teens </li>
<li><b>birthday:</b> May 25? </li>
<li><b>mental:</b> simple, ignorant but curious </li>
<li><b>mental:</b> simple, ignorant but curious, childlike but deep, protective </li>
<li><b>physical:</b> tall, dark hair, red eyes, semi-rigid keratin "horns" </li>
<li><b>style:</b> assembled trash, hand-me-downs </li>
<li><b>height:</b> 5'10 </li>

@ -106,6 +106,9 @@ def find_gallery(name):
if name == "Chloe":
gal.append("Blessfrey")
gal.append([["girls.png","Angel, Chloe, and Tessa"]])
if name == "Danika":
gal.append("Blessfrey")
gal.append([["name.png","desc"]])
if name == "Dia":
gal.append("Blessfrey")
gal.append([["name.png","desc"]])
@ -505,7 +508,7 @@ def entry(page):
def gddbf():
"""Game Design Document"""
info = {'css': 'doc', 'title': 'blessfrey gdd', 'year': find_year(), 'topics': get_gdd_topics(
["achievement", "ai", "armor-rating", "attack-loop", "attribute", "attribute-point", "cast", "character", "collision", "controls", "credits", "damage-type", "death-penalty", "design-philosophy", "dialogue", "docs", "environment-effect", "gear", "gig", "groups", "highlight", "ID", "inspect menu", "inventory", "item", "job", "keyword", "language", "life", "marketing", "mechanics", "Mercur", "milestones", "miracles", "pathfinding", "perk", "pip", "projectile", "proxemics", "punishment", "setting", "skill", "smartphone", "spirit", "status-effect", "story", "style guide", "terms", "vibe", "website", "xp", "xp-bar", "zone"],3
["achievement", "ai", "armor-rating", "attack-loop", "attribute", "attribute-point", "cast", "character", "collision", "controls", "credits", "damage-type", "death-penalty", "design-philosophy", "dialogue", "docs", "environment-effect", "fog-of-war", "gear", "gig", "groups", "highlight", "ID", "inspect menu", "inventory", "item", "job", "keyword", "KnowledgeBase", "language", "life", "marketing", "mechanics", "MessageBus", "Mercur", "milestones", "miracles", "pathfinding", "perk", "pip", "projectile", "proxemics", "punishment", "setting", "skill", "smartphone", "spirit", "status-effect", "store", "story", "style guide", "terms", "ui", "vibe", "website", "xp", "xp-bar", "zone"],3
)}
return template('bf-gdd.tpl', info)
@route('/gdd')

@ -3,6 +3,7 @@
<div class="content-grid"><div class="center">
<h1>blessfrey game design document </h1>
<p>The vision for Blessfrey</p>
<p>Choose a primary and secondary class, gain skills through gameplay, build a skillbar from unlimited combinations of skills with interesting synergies, and test it in combat with new friends around town. Or collect practical skills to spend a day transmuting items, cooking, or socializing. Lots to discover and explore!</p>
<table>
% # find longest column, since html tables need to be doled out row by row

Loading…
Cancel
Save