fixes + data updates

This commit is contained in:
Chen Asraf
2022-04-27 18:26:05 +03:00
parent 025b877e2d
commit 6b3d665dfe
8 changed files with 167 additions and 68 deletions

5
.editorconfig Normal file
View File

@@ -0,0 +1,5 @@
[*]
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

8
.vscode/launch.json vendored
View File

@@ -10,6 +10,12 @@
"request": "launch",
"program": "${file}"
},
{
"name": "Migrate v2 -> v3",
"type": "dart",
"request": "launch",
"program": "scripts/migrate/v2_to_v3.dart"
},
{
"name": "All Tests",
"type": "dart",
@@ -35,4 +41,4 @@
"type": "dart"
},
]
}
}

View File

@@ -25,8 +25,7 @@ class GearChoice extends DWEntity {
Map toJSON() => {
'key': key,
'label': label,
'list': listMapper<GearOption, dynamic, GearOption>(
gearOptions, (i) => i.toJSON()),
'list': listMapper<GearOption, dynamic, GearOption>(gearOptions, (i) => i.toJSON()),
};
@override
@@ -57,9 +56,8 @@ class GearOption extends DWEntity {
final num openParen = str.indexOf('(');
final num? closeParen = str.indexOf(')');
final name = str.substring(0, openParen > -1 ? openParen : null);
final rawTags = openParen > -1 && closeParen! > -1
? str.substring(openParen + 1, closeParen)
: '';
final rawTags =
openParen > -1 && closeParen! > -1 ? str.substring(openParen + 1, closeParen) : '';
final tags = rawTags.isNotEmpty
? rawTags.split(',').map((tag) => Tag.fromJSON(tag.trim())).toList()
: [];

View File

@@ -156,6 +156,42 @@ void initData() {
null,
'When making your own magic items keep in mind that these items are magical. Simple modifiers, like+1 damage, are the realm of the mundane—magic items should provide more interesting bonuses.',
));
equipmentList.add(Equipment(
key: 'fathers_mandolin',
name: "Father's Mandolin",
description: "Your father's mandolin, repaired.",
tags: [Tag.fromJSON('{weight:0}')],
));
equipmentList.add(Equipment(
key: 'fine_lute',
name: 'Fine Lute',
description: 'A fine lute, a gift from a noble.',
tags: [Tag.fromJSON('{weight:0}')],
));
equipmentList.add(Equipment(
key: 'memorable_pipes',
name: 'Memorable Pipes',
description: 'The pipes with which you courted your first love',
tags: [Tag.fromJSON('{weight:0}')],
));
equipmentList.add(Equipment(
key: 'stolen_horn',
name: 'Stolen Horn',
description: 'A stolen horn',
tags: [Tag.fromJSON('{weight:0}')],
));
equipmentList.add(Equipment(
key: 'unplayed_fiddle',
name: 'Unplayed Fiddle',
description: 'A fiddle, never before played.',
tags: [Tag.fromJSON('{weight:0}')],
));
equipmentList.add(Equipment(
key: 'forgotten_songbook',
name: 'Forgotten Songbook',
description: 'A songbook in a forgotten tongue.',
tags: [Tag.fromJSON('{weight:0}')],
));
equipmentList.add(Equipment(
key: 'ragged_bow',
name: 'Ragged Bow',
@@ -176,7 +212,7 @@ void initData() {
],
));
equipmentList.add(Equipment(
key: 'hunter_s_bow',
key: 'hunters_bow',
name: "hunter's bow",
pluralName: "hunter's bows",
description: null,
@@ -326,6 +362,18 @@ void initData() {
Tag.fromJSON('{weight: 2}')
],
));
equipmentList.add(Equipment(
key: 'two_handed_sword',
name: 'Two Handed Sword',
pluralName: 'Two Handed Swords',
description: null,
tags: [
Tag.fromJSON('close'),
Tag.fromJSON('{damage: +1}'),
Tag.fromJSON('{coins: 15}'),
Tag.fromJSON('{weight: 2}')
],
));
equipmentList.add(Equipment(
key: 'battle_axe',
name: 'Battle Axe',
@@ -440,6 +488,12 @@ void initData() {
description: null,
tags: [Tag.fromJSON('{armor: +1}'), Tag.fromJSON('{coins: 15}'), Tag.fromJSON('{weight: 2}')],
));
equipmentList.add(Equipment(
key: 'ostentatious_clothes',
name: 'Ostentatious clothes',
description: 'Clothes that are vulgar or pretentious, designed to impress attract notice.',
tags: [Tag.fromJSON('{weight: 0}')],
));
equipmentList.add(Equipment(
key: 'leather_armor',
name: 'Leather Armor',
@@ -541,7 +595,7 @@ void initData() {
));
equipmentList.add(Equipment(
key: 'dungeon_rations',
name: 'dungeon rations',
name: 'Dungeon Rations',
pluralName: 'dungeon rations',
description: 'Not tasty, but not bad either.',
tags: [
@@ -685,7 +739,7 @@ void initData() {
name: 'Bag of Holding',
pluralName: 'Bag of Holdings',
description:
'A bag of holding is larger on the inside than the outside, it can contain an infinite number of items, and its weight never increases. When you try to retrieve an item from a bag of holding, roll+WIS. On a 10+, its right there. On a 7-9, choose one:\nYou get the exact item, but it takes a while\n\nYou get a similar item of the GMs choice, but it only takes a moment\nNo matter how many items it contains, a bag of holding is always 0 weight.',
'A bag of holding is larger on the inside than the outside, it can contain an infinite number of items, and its weight never increases. When you try to retrieve an item from a bag of holding, roll+WIS. \n* On a 10+, its right there. \n* On a 7-9, choose one:\nYou get the exact item, but it takes a while\n\nYou get a similar item of the GMs choice, but it only takes a moment\nNo matter how many items it contains, a bag of holding is always 0 weight.',
tags: [Tag.fromJSON('{weight: 0}')],
));
equipmentList.add(Equipment(
@@ -693,7 +747,7 @@ void initData() {
name: 'The Burning Wheel',
pluralName: 'The Burning Wheels',
description:
'An ancient wooden wheel, as might appear on a war-wagon, banded with steel. On a glance, it appears to be nothing special—many spokes are shattered and the thing seems mundane. Under the scrutiny of magic or the eyes of an expert, its true nature is revealed: the Burning Wheel is a gift from the God of Fire and burns with his authority.\nWhen you hold The Burning Wheel and speak a gods name, roll+CON. On a 7+, the god you name takes notice and grants you an audience. An audience with a god is not without a price: on a 10+, you choose one of your stats and reduce it to the next lowest modifier (for example, a 14 is +1, so it would be reduced to 12, a +0). On a 79, the GM chooses which stat to reduce.\nOnce used, the Burning Wheel ignites and burns with brilliant light. It does not confer any protection from those flames, nor does it provide any bonus to swimming.',
'An ancient wooden wheel, as might appear on a war-wagon, banded with steel. On a glance, it appears to be nothing special—many spokes are shattered and the thing seems mundane. Under the scrutiny of magic or the eyes of an expert, its true nature is revealed: the Burning Wheel is a gift from the God of Fire and burns with his authority.\nWhen you hold The Burning Wheel and speak a gods name, roll+CON. \n* On a 7+, the god you name takes notice and grants you an audience. An audience with a god is not without a price: on a 10+, you choose one of your stats and reduce it to the next lowest modifier (for example, a 14 is +1, so it would be reduced to 12, a +0). \n* On a 79, the GM chooses which stat to reduce.\nOnce used, the Burning Wheel ignites and burns with brilliant light. It does not confer any protection from those flames, nor does it provide any bonus to swimming.',
tags: [Tag.fromJSON('{weight: 2}')],
));
equipmentList.add(Equipment(
@@ -773,7 +827,7 @@ void initData() {
name: 'Farsight Stone',
pluralName: 'Farsight Stones',
description:
'Swirling clouds fill this smoky orb and those in its presence often hear strange whispers. In ancient times, it was part of a network of such stones, used to communicate and surveil across great distances. When you gaze into the stone, name a location and roll+WIS. On a 10+, you see a clear vision of the location and can maintain it as long as you concentrate on the orb. On a 79, you still see the vision, but you draw the attention of some other thing (an angel, a demon, or the holder of another Farsight stone) that uses the stone to surveil you, as well.',
'Swirling clouds fill this smoky orb and those in its presence often hear strange whispers. In ancient times, it was part of a network of such stones, used to communicate and surveil across great distances. When you gaze into the stone, name a location and roll+WIS. \n* On a 10+, you see a clear vision of the location and can maintain it as long as you concentrate on the orb. \n* On a 79, you still see the vision, but you draw the attention of some other thing (an angel, a demon, or the holder of another Farsight stone) that uses the stone to surveil you, as well.',
tags: [Tag.fromJSON('{weight: 1}')],
));
equipmentList.add(Equipment(
@@ -781,7 +835,7 @@ void initData() {
name: 'The Fiasco Codex',
pluralName: 'The Fiasco Codexs',
description:
'A thick tome, said to be penned in the blood of poor fools and robber-barons by some demon prince possessed of dark humor, this tome details tales and stories of those whose ambition overwhelmed their reason. Reading from this tome teaches one the value of clear-headedness but leaves a sense of dread behind. When you read from the Fiasco Codex, Roll+WIS. On a 10+, ask two of the questions below. On a 79, ask one.\nWhat is my greatest opportunity, right now?\n\nWho can I betray to gain an advantage?\n\nWho is an ally I should not trust?\nThe codex gives up its answers only once to each reader and takes 2 to 3 hours to read.',
'A thick tome, said to be penned in the blood of poor fools and robber-barons by some demon prince possessed of dark humor, this tome details tales and stories of those whose ambition overwhelmed their reason. Reading from this tome teaches one the value of clear-headedness but leaves a sense of dread behind. When you read from the Fiasco Codex, Roll+WIS. \n* On a 10+, ask two of the questions below. \n* On a 79, ask one.\nWhat is my greatest opportunity, right now?\n\nWho can I betray to gain an advantage?\n\nWho is an ally I should not trust?\nThe codex gives up its answers only once to each reader and takes 2 to 3 hours to read.',
tags: [Tag.fromJSON('{weight: 0}')],
));
equipmentList.add(Equipment(
@@ -797,7 +851,7 @@ void initData() {
name: 'Folly Held Aloft, The Wax Wings, A Huge Mistake',
pluralName: 'Folly Held Aloft, The Wax Wings, A Huge Mistakes',
description:
'Who hasnt always wanted to soar the pretty blue sky? In an attempt to grant the wishes of land-bound folk, these great magical wings were created. Known by many names and crafted by as many mages, they commonly take the shape of the wings of whatever local birds hold affection. Worn by means of a harness or, in some dire cases, a surgical procedure.\nWhen you take to the air with these magical wings, roll+DEX. On a 10+, your flight is controlled and you may stay aloft as long as you like. On a 79, you make it aloft but your flight is short or erratic and unpredictable, your choice. On a 6-, you make it aloft, but the coming-down part and everything between is up to the GM.',
'Who hasnt always wanted to soar the pretty blue sky? In an attempt to grant the wishes of land-bound folk, these great magical wings were created. Known by many names and crafted by as many mages, they commonly take the shape of the wings of whatever local birds hold affection. Worn by means of a harness or, in some dire cases, a surgical procedure.\nWhen you take to the air with these magical wings, roll+DEX. \n* On a 10+, your flight is controlled and you may stay aloft as long as you like. \n* On a 79, you make it aloft but your flight is short or erratic and unpredictable, your choice. \n* On a 6-, you make it aloft, but the coming-down part and everything between is up to the GM.',
tags: [Tag.fromJSON('{weight: 1}')],
));
equipmentList.add(Equipment(
@@ -829,7 +883,7 @@ void initData() {
name: 'The Kumeh Maneuver',
pluralName: 'The Kumeh Maneuvers',
description:
'A great, leathery tome worn shiny by the hands of a hundred great generals, this book is often passed from warrior to warrior, from father to son along the great battle lines that have divided Dungeon Worlds past. Anyone reading it may, upon finishing for the first time, roll+INT. On a 10+, hold 3. On a 7-9, hold 1. You may spend your hold to advise a companion on some matter of strategic or tactical significance. This advice allows you to, at any time, regardless of distance, roll to aid them on any one roll. On a miss, the GM can hold 1 and spend it to apply -2 to any roll of yours or the poor sap who listened to your advice.',
'A great, leathery tome worn shiny by the hands of a hundred great generals, this book is often passed from warrior to warrior, from father to son along the great battle lines that have divided Dungeon Worlds past. Anyone reading it may, upon finishing for the first time, roll+INT. \n* On a 10+, hold 3. \n* On a 7-9, hold 1. You may spend your hold to advise a companion on some matter of strategic or tactical significance. This advice allows you to, at any time, regardless of distance, roll to aid them on any one roll. On a miss, the GM can hold 1 and spend it to apply -2 to any roll of yours or the poor sap who listened to your advice.',
tags: [Tag.fromJSON('{weight: 1}')],
));
equipmentList.add(Equipment(
@@ -877,7 +931,7 @@ void initData() {
name: 'Sacred Herbs',
pluralName: 'Sacred Herbss',
description:
'The sacred herbs, collected and prepared by an order of lost wizard-monks, can be found in bundles with two or three uses to them. Kept dry, they last indefinitely. When smoked in a pipe or consumed in an incense burner and the thick, blue smoke inhaled, these herbs will grant you strange visions of faraway places and distant times. If you focus your will on a particular person, place or thing, the herbs will respond: roll+WIS. On a 10+, the vision is clear and useful—yielding some valid information. On a 79, the vision is about the thing desired, but is unclear, fraught with metaphor or somehow difficult to understand. On a miss, the GM will ask you, “What is it you fear most?” You must answer honestly, of course.',
'The sacred herbs, collected and prepared by an order of lost wizard-monks, can be found in bundles with two or three uses to them. Kept dry, they last indefinitely. When smoked in a pipe or consumed in an incense burner and the thick, blue smoke inhaled, these herbs will grant you strange visions of faraway places and distant times. If you focus your will on a particular person, place or thing, the herbs will respond: roll+WIS. \n* On a 10+, the vision is clear and useful—yielding some valid information. \n* On a 79, the vision is about the thing desired, but is unclear, fraught with metaphor or somehow difficult to understand. \n* On a miss, the GM will ask you, “What is it you fear most?” You must answer honestly, of course.',
tags: [Tag.fromJSON('{weight: 0}')],
));
equipmentList.add(Equipment(
@@ -901,7 +955,7 @@ void initData() {
name: 'Teleportation Room',
pluralName: 'Teleportation Rooms',
description:
'James Ninefingers, eccentric genius mage, created these room-sized magical apparati. A stone chamber etched with runes and scribblings, glowing with a faint blue light. When you enter and say aloud the name of a location, roll+INT. On a 10+, you arrive exactly where youd intended. On a 79, the GM chooses a safe location nearby. On a miss, you end up someplace. Maybe its nearby? Its definitely not safe. Strange things sometimes happen to those who bend time and space with these devices.',
'James Ninefingers, eccentric genius mage, created these room-sized magical apparati. A stone chamber etched with runes and scribblings, glowing with a faint blue light. When you enter and say aloud the name of a location, roll+INT. \n* On a 10+, you arrive exactly where youd intended. \n* On a 79, the GM chooses a safe location nearby. \n* On a miss, you end up someplace. Maybe its nearby? Its definitely not safe. Strange things sometimes happen to those who bend time and space with these devices.',
tags: [Tag.fromJSON('slow')],
));
equipmentList.add(Equipment(
@@ -1229,12 +1283,28 @@ void initData() {
],
spells: [],
gearChoices: [
GearChoice(
key: '5becbb00-f57a-4655-b955-b291e1bcaeb4',
label: 'You have dungeon rations (5 uses, 1 weight)',
gearOptions: [
GearOption(
key: 'dungeon_rations',
name: 'Dungeon Rations',
tags: [
Tag.fromJSON('ration'),
Tag.fromJSON('{uses: 5}'),
Tag.fromJSON('{coins: 3}'),
Tag.fromJSON('{weight: 1}'),
],
),
],
),
GearChoice(
key: '58883c28-13ec-46a2-8454-a09436cb6e79',
label: 'Choose one instrument, all are 0 weight for you',
gearOptions: [
GearOption(
key: 'your_father_s_mandolin_repaired',
key: 'your_fathers_mandolin_repaired',
name: "Your father's mandolin, repaired",
tags: [],
),
@@ -6073,7 +6143,7 @@ void initData() {
key: 'take_watch',
name: 'Take Watch',
description:
'When youre on watch and something approaches the camp roll+Wis. On a 10+, youre able to wake the camp and prepare a response, everyone in the camp takes +1 forward. On a 79, you react just a moment too late; your companions in camp are awake but havent had time to prepare. They have weapons and armor but little else. On a miss, whatever lurks outside the campfires light has the drop on you.',
'When youre on watch and something approaches the camp roll+Wis. \n* On a 10+, youre able to wake the camp and prepare a response, everyone in the camp takes +1 forward. \n* On a 79, you react just a moment too late; your companions in camp are awake but havent had time to prepare. They have weapons and armor but little else. \n* On a miss, whatever lurks outside the campfires light has the drop on you.',
explanation: null,
classes: [],
));
@@ -6089,7 +6159,7 @@ void initData() {
key: 'supply',
name: 'Supply',
description:
'When you go to **buy something with gold on hand**, if its something readily available in the settlement youre in, you can buy it at market price. If its something special, beyond whats usually available here, or non-mundane, roll+Cha. On a 10+, you find what youre looking for at a fair price. On a 79, youll have to pay more or settle for something thats not exactly what you wanted, but close. The GM will tell you what your options are.',
'When you go to **buy something with gold on hand**, if its something readily available in the settlement youre in, you can buy it at market price. If its something special, beyond whats usually available here, or non-mundane, roll+Cha. \n* On a 10+, you find what youre looking for at a fair price. \n* On a 79, youll have to pay more or settle for something thats not exactly what you wanted, but close. The GM will tell you what your options are.',
explanation: null,
classes: [],
));
@@ -6097,7 +6167,7 @@ void initData() {
key: 'undertake_a_perilous_journey',
name: 'Undertake a Perilous Journey',
description:
'When you travel through hostile territory, choose one member of the party to act as trailblazer, one to scout ahead, and one to be quartermaster. Each character with a job to do rolls+Wis. On a 10+:\n\n - the quartermaster reduces the number of rations required by one\n - the trailblazer reduces the amount of time it takes to reach your destination (the GM will say by how much)\n - the scout will spot any trouble quick enough to let you get the drop on it\n\nOn a 79, each role performs their job as expected: the normal number of rations are consumed, the journey takes about as long as expected, no one gets the drop on you but you dont get the drop on them either.',
'When you travel through hostile territory, choose one member of the party to act as trailblazer, one to scout ahead, and one to be quartermaster. Each character with a job to do rolls+Wis. \n* On a 10+:\n\n - the quartermaster reduces the number of rations required by one\n - the trailblazer reduces the amount of time it takes to reach your destination (the GM will say by how much)\n - the scout will spot any trouble quick enough to let you get the drop on it\n\n\n* On a 79, each role performs their job as expected: the normal number of rations are consumed, the journey takes about as long as expected, no one gets the drop on you but you dont get the drop on them either.',
explanation:
'You cant assign more than one job to a character. If you dont have enough party members, or choose not to assign a job, treat that job as if it had been assigned and the responsible player had rolled a 6.\n\nDistances in Dungeon World are measured in rations. A ration is the amount of supplies used up in a day. Journeys take more rations when they are long or when travel is slow.\n\nA perilous journey is the whole way between two locations. You dont roll for one days journey and then make camp only to roll for the next days journey, too. Make one roll for the entire trip.\n\nThis move only applies when you know where youre going. Setting off to explore is not a perilous journey. Its wandering around looking for cool things to discover. Use up rations as you camp and the GM will give you details about the world as you discover them.',
classes: [],
@@ -6114,7 +6184,7 @@ void initData() {
key: 'carouse',
name: 'Carouse',
description:
'When you return triumphant and throw a big party, spend 100 coins and roll +1 for every extra 100 coins spent. On a 10+, choose 3. On a 79, choose 1. On a miss, you still choose one, but things get really out of hand (the GM will say how).\n\n - You befriend a useful NPC.\n - You hear rumors of an opportunity.\n - You gain useful information.\n - You are not entangled, ensorcelled, or tricked.\n\nYou can only carouse when you return triumphant. Thats what draws the crowd of revelers to surround adventurers as they celebrate their latest haul. If you dont proclaim your success or your failure, then who would want to party with you anyway?',
'When you return triumphant and throw a big party, spend 100 coins and roll +1 for every extra 100 coins spent. \n* On a 10+, choose 3. \n* On a 79, choose 1. \n* On a miss, you still choose one, but things get really out of hand (the GM will say how).\n\n - You befriend a useful NPC.\n - You hear rumors of an opportunity.\n - You gain useful information.\n - You are not entangled, ensorcelled, or tricked.\n\nYou can only carouse when you return triumphant. Thats what draws the crowd of revelers to surround adventurers as they celebrate their latest haul. If you dont proclaim your success or your failure, then who would want to party with you anyway?',
explanation: null,
classes: [],
));
@@ -6122,7 +6192,7 @@ void initData() {
key: 'recruit',
name: 'Recruit',
description:
'When you put out word that youre looking to hire help, roll:\n\n - +1 if you make it known that your pay is generous\n - +1 if you make it known what youre setting out to do\n - +1 if you make it known that theyll get a share of whatever you find\n - +1 if you have a useful reputation around these parts\n\nOn a 10+, youve got your pick of a number of skilled applicants, your choice who you hire, no penalty for not taking them along. On a 79, youll have to settle for someone close to what you want or turn them away. On a miss someone influential and ill-suited declares theyd like to come along (a foolhardy youth, a loose-cannon, or a veiled enemy, for example), bring them and take the consequences or turn them away. If you turn away applicants you take -1 forward to recruit.',
'When you put out word that youre looking to hire help, roll:\n\n - +1 if you make it known that your pay is generous\n - +1 if you make it known what youre setting out to do\n - +1 if you make it known that theyll get a share of whatever you find\n - +1 if you have a useful reputation around these parts\n\n\n* On a 10+, youve got your pick of a number of skilled applicants, your choice who you hire, no penalty for not taking them along. \n* On a 79, youll have to settle for someone close to what you want or turn them away. \n* On a miss someone influential and ill-suited declares theyd like to come along (a foolhardy youth, a loose-cannon, or a veiled enemy, for example), bring them and take the consequences or turn them away. If you turn away applicants you take -1 forward to recruit.',
explanation: null,
classes: [],
));
@@ -6146,7 +6216,7 @@ void initData() {
key: 'outstanding_warrants',
name: 'Outstanding Warrants',
description:
'When you return to a civilized place in which youve caused trouble before, roll+Cha. On a 10+, word has spread of your deeds and everyone recognizes you. On a 79, as above, and the GM chooses a complication:\n\n - The local constabulary has a warrant out for your arrest.\n - Someone has put a price on your head.\n - Someone important to you has been put in a bad spot as a result of your actions',
'When you return to a civilized place in which youve caused trouble before, roll+Cha. \n* On a 10+, word has spread of your deeds and everyone recognizes you. \n* On a 79, as above, and the GM chooses a complication:\n\n - The local constabulary has a warrant out for your arrest.\n - Someone has put a price on your head.\n - Someone important to you has been put in a bad spot as a result of your actions',
explanation:
'This move is only for places where youve caused trouble, not every patch of civilization you enter. Being publicly caught up in someone elses trouble still triggers this move.\n\nCivilization generally means the villages, towns and cities of humans, elves, dwarves, and halflings but it can also apply to any relatively lawful establishment of monstrous species, such as orcs or goblins. If the PCs have stayed in a place as part of the community, it counts as civilization.',
classes: [],

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
class AlignmentValue {
AlignmentValue({
class Alignment {
Alignment({
required this.key,
required this.description,
});
@@ -9,21 +9,20 @@ class AlignmentValue {
final String key;
final String description;
AlignmentValue copyWith({
Alignment copyWith({
String? key,
String? description,
}) =>
AlignmentValue(
Alignment(
key: key ?? this.key,
description: description ?? this.description,
);
factory AlignmentValue.fromRawJson(String str) =>
AlignmentValue.fromJson(json.decode(str));
factory Alignment.fromRawJson(String str) => Alignment.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AlignmentValue.fromJson(Map<String, dynamic> json) => AlignmentValue(
factory Alignment.fromJson(Map<String, dynamic> json) => Alignment(
key: json["key"],
description: json["description"],
);
@@ -64,13 +63,11 @@ class AlignmentValues {
chaotic: chaotic ?? this.chaotic,
);
factory AlignmentValues.fromRawJson(String str) =>
AlignmentValues.fromJson(json.decode(str));
factory AlignmentValues.fromRawJson(String str) => AlignmentValues.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory AlignmentValues.fromJson(Map<String, dynamic> json) =>
AlignmentValues(
factory AlignmentValues.fromJson(Map<String, dynamic> json) => AlignmentValues(
good: json["good"],
evil: json["evil"],
lawful: json["lawful"],

View File

@@ -83,9 +83,10 @@ class Dice {
String get modifierWithSign =>
hasModifier ? "$modifierSign${modifierValue?.abs() ?? modifierStat}" : "";
bool get hasModifier => (modifierValue != null || modifierStat != null);
bool get hasModifier => ((modifierValue != null && modifierValue != 0) || modifierStat != null);
String get modifier => hasModifier ? modifierStat ?? modifierValue!.toString() : "";
String get modifier =>
hasModifier ? modifierStat ?? (modifierValue != 0 ? modifierValue : '')!.toString() : "";
DiceRoll roll() {
if (needsModifier) {
@@ -95,7 +96,7 @@ class Dice {
}
var arr = <int>[];
for (var i = 0; i < amount; i++) {
arr.add(Random().nextInt(sides));
arr.add(Random().nextInt(sides - 1) + 1);
}
return DiceRoll(dice: this, results: arr);
}
@@ -105,6 +106,9 @@ class Dice {
operator *(int amount) => copyWith(amount: this.amount * amount);
operator /(int amount) => copyWith(amount: this.amount ~/ amount);
static List<Dice> flatten(List<Dice> dice) =>
dice.fold([], (all, cur) => [...all, ...List.filled(cur.amount, cur / cur.amount)]);
static List<String?> _diceMatches(String json) {
_assertDicePattern(json);
var m = _dicePattern.firstMatch(json)!;
@@ -130,15 +134,13 @@ class DiceRoll {
static List<DiceRoll> rollMany(List<Dice> dice) => dice.map((d) => roll(d)).toList();
static DiceRoll roll(Dice dice) => dice.roll();
int get total => results.reduce((all, cur) => all + cur) + (dice.modifierValue ?? 0);
bool get didHitNaturalMax => indexOfNaturalMax >= 0;
int get indexOfNaturalMax => results.indexOf(dice.sides);
static DiceRoll roll(Dice dice) {
return dice.roll();
}
void assertDiceModifier() {
if (dice.needsModifier) {
throw Exception("Dice is being rolled without an actual modifier."

View File

@@ -12,7 +12,7 @@ class Repository {
String get currentLocale => _currentLocale;
final Set<String> _locales = {};
final Map<String, RepositoryItem<AlignmentValue>> _alignments = {};
final Map<String, RepositoryItem<Alignment>> _alignments = {};
final Map<String, RepositoryItem<CharacterClass>> _classes = {};
final Map<String, RepositoryItem<Item>> _items = {};
final Map<String, RepositoryItem<Monster>> _monsters = {};
@@ -25,7 +25,7 @@ class Repository {
required String currentLocale,
}) : _currentLocale = currentLocale;
RepositoryItem<AlignmentValue> get alignments => _withCurrentLocale(_alignments);
RepositoryItem<Alignment> get alignments => _withCurrentLocale(_alignments);
RepositoryItem<CharacterClass> get classes => _withCurrentLocale(_classes);
RepositoryItem<Item> get items => _withCurrentLocale(_items);
RepositoryItem<Monster> get monsters => _withCurrentLocale(_monsters);
@@ -57,8 +57,8 @@ class Repository {
void loadItems<T>(String locale, Map<String, T> items) {
registerLocale(locale);
switch (T) {
case AlignmentValue:
_alignments[locale]!.addItems(items.cast<String, AlignmentValue>());
case Alignment:
_alignments[locale]!.addItems(items.cast<String, Alignment>());
break;
case CharacterClass:
_classes[locale]!.addItems(items.cast<String, CharacterClass>());

View File

@@ -5,12 +5,12 @@ import 'package:dungeon_world_data/_old/dw_data.dart' as old;
import 'package:dungeon_world_data/_utils/uuid.dart';
import 'package:dungeon_world_data/dungeon_world_data.dart';
import 'package:dungeon_world_data/gear_option.dart';
import 'package:dungeon_world_data/monster.dart';
import 'package:path/path.dart' as path;
final _jsonOut = path.join(
path.dirname(Platform.script.path),
'dump.json',
'dumps',
'all.json',
);
Map<String, String> strFixMap = {
@@ -21,21 +21,27 @@ Map<String, String> strFixMap = {
"": "\"",
};
final json = <String, List<Map<String, dynamic>>>{
'moves': [],
'races': [],
'classes': [],
'spells': [],
'items': [],
'monsters': [],
'tags': [],
final json = <String, dynamic>{
'moves': <Map<String, dynamic>>[],
'races': <Map<String, dynamic>>[],
'classes': <Map<String, dynamic>>[],
'spells': <Map<String, dynamic>>[],
'items': <Map<String, dynamic>>[],
'monsters': <Map<String, dynamic>>[],
'tags': <Map<String, dynamic>>[],
'names': <String, Map<String, List<String>>>{},
};
final defaultTags = <Tag>[
Tag(name: "language", value: "EN"),
Tag(name: "source", value: "repo"),
// Tag(name: "language", value: "EN"),
// Tag(name: "source", value: "repo"),
];
final defaultMeta = {
'language': 'EN',
'createdBy': '__repo__',
};
main() async {
print("Starting...");
// Basic moves
@@ -60,13 +66,13 @@ main() async {
json['items']!.add(equipMapper(equip).toJson());
}
// Monsters
// Monsters
print("Adding ${old.dungeonWorld.monsters.length} monsters");
for (var mon in old.dungeonWorld.monsters) {
json['monsters']!.add(monsterMapper(mon).toJson());
}
// Tags
// Tags
print("Adding ${old.dungeonWorld.tags.length} tags");
for (var tag in old.dungeonWorld.tags) {
json['tags']!.add(tagMapper(tag).toJson());
@@ -99,6 +105,10 @@ main() async {
// Classes
json['classes']!.add(classMapper(cls).toJson());
print("Adding ${cls.names.values.fold<int>(0, (t, c) => t + c.length)} ${cls.key} names");
final Map<String, List<String>> names = (json['names'][cls.key] ??= <String, List<String>>{});
names.addAll(cls.names);
}
print("Total ${json['classes']!.length} classes");
@@ -158,7 +168,7 @@ Move moveMapper(old.Move move, MoveCategory category) => Move(
dice: guessDice(fix(move.description)).toList(),
explanation: fix(move.explanation ?? ""),
key: makeKey(move.name),
meta: null,
meta: defaultMeta,
name: fix(move.name),
tags: defaultTags,
);
@@ -168,7 +178,7 @@ Race raceMapper(old.Move move, String classKey) => Race(
description: fix(move.description),
explanation: fix(move.explanation ?? ""),
key: makeKey(move.name),
meta: null,
meta: defaultMeta,
name: fix(move.name),
tags: defaultTags,
);
@@ -178,7 +188,7 @@ Spell spellMapper(old.Spell spell) => Spell(
description: fix(spell.description),
explanation: "",
key: makeKey(spell.name),
meta: null,
meta: defaultMeta,
name: fix(spell.name),
dice: guessDice(spell.description).toList(),
tags: [...defaultTags, ...spell.tags.map((t) => tagMapper(t))],
@@ -190,7 +200,7 @@ Tag tagMapper(old.Tag t) => Tag.fromJson(t.toJSON().runtimeType == String
Item equipMapper(old.Equipment equip) => Item(
key: makeKey(equip.name),
meta: null,
meta: defaultMeta,
name: fix(equip.name),
description: fix(equip.description),
tags: equip.tags.map((t) => tagMapper(t)).toList(),
@@ -200,7 +210,7 @@ Monster monsterMapper(old.Monster move) => Monster(
instinct: fix(move.instinct),
description: fix(move.description),
key: makeKey(move.name),
meta: null,
meta: defaultMeta,
name: fix(move.name),
tags: defaultTags,
moves: move.moves,
@@ -239,7 +249,7 @@ CharacterClass classMapper(old.PlayerClass cls) => CharacterClass(
? Item.fromJson(found)
: Item(
key: makeKey(o.name),
meta: null,
meta: defaultMeta,
name: fix(o.name),
description: fix(o.name),
tags: [...defaultTags, ...o.tags.map(tagMapper)],
@@ -282,10 +292,11 @@ CharacterClass classMapper(old.PlayerClass cls) => CharacterClass(
item: item,
),
];
var incomplete = found == null && !isCoinsItem && !foundSplit;
return GearSelection(
key: generatedKey,
description: o.name +
(found == null && !isCoinsItem && !foundSplit ? '(TODO: INCOMPLETE)' : ''),
description: o.name + (incomplete ? '(TODO: INCOMPLETE)' : ''),
options: isCoinsItem ? [] : splitItems,
coins: isCoinsItem ? numFromName ?? 0 : 0,
);
@@ -298,9 +309,18 @@ CharacterClass classMapper(old.PlayerClass cls) => CharacterClass(
key: makeKey(cls.name),
load: cls.load.toInt(),
name: cls.name,
meta: null,
meta: defaultMeta,
);
final incompleteGearMap = {
'your_fathers_mandolin_repaired': 'fathers_mandolin',
'a_fine_lute_a_gift_from_a_noble': 'fine_lute',
'the_pipes_with_which_you_courted_your_first_love': 'memorable_pipes',
'a_stolen_horn': 'stolen_horn',
'a_fiddle_never_before_played': 'unplayed_fiddle',
'a_songbook_in_a_forgotten_tongue': 'forgotten_songbook',
};
Map<String, dynamic> tryFindItem(String key, String generatedKey) {
final keyStartsWithNum = key.startsWith(RegExp(r'[0-9]+'));
final keyWithoutNum =
@@ -309,6 +329,7 @@ Map<String, dynamic> tryFindItem(String key, String generatedKey) {
keyWithoutNum.isEmpty ? '' : keyWithoutNum.substring(0, keyWithoutNum.length - 1);
return json['items']!.firstWhere(
(el) =>
el['key'].toLowerCase() == incompleteGearMap[key] ||
el['key'].toLowerCase() == key.toLowerCase() ||
el['key'].toLowerCase() == generatedKey.toLowerCase() ||
el['key'].toLowerCase() == keyWithoutNum.toLowerCase() ||