feat: add support for Demon's Souls-style packs

This commit is contained in:
Anna 2024-06-15 18:42:22 -04:00
parent 62c579c42d
commit c933a550ca
Signed by: anna
GPG Key ID: D0943384CD9F87D1
5 changed files with 924 additions and 52 deletions

View File

@ -10,9 +10,12 @@ public class Pack {
public string Name { get; init; }
public Guid Id { get; init; }
public string[] Templates { get; init; }
public string[] Conjunctions { get; init; }
public List<WordList> Words { get; init; }
[JsonConverter(typeof(TemplateConverter))]
public ITemplate[] Templates { get; init; }
public string[]? Conjunctions { get; init; }
public List<WordList>? Words { get; init; }
internal static void UpdatePacks() {
Task.Run(async () => {
@ -29,6 +32,52 @@ public class Pack {
}
}
public interface ITemplate {
public string Template { get; }
public string[]? Words { get; }
}
public class BasicTemplate : ITemplate {
public string Template { get; init; }
public string[]? Words => null;
}
[Serializable]
public class WordListTemplate : ITemplate {
public string Template { get; init; }
public string[] Words { get; init; }
}
public class TemplateConverter : JsonConverter<ITemplate>
{
public override ITemplate? ReadJson(JsonReader reader, Type objectType, ITemplate? existingValue, bool hasExistingValue, JsonSerializer serializer) {
if (reader.TokenType == JsonToken.String) {
var template = reader.ReadAsString();
if (template == null) {
return null;
}
return new BasicTemplate {
Template = template,
};
} else if (reader.TokenType == JsonToken.StartObject) {
return serializer.Deserialize<WordListTemplate>(reader);
} else {
throw new JsonReaderException("unexpected template kind");
}
}
public override void WriteJson(JsonWriter writer, ITemplate? value, JsonSerializer serializer) {
if (value is BasicTemplate basic) {
serializer.Serialize(writer, basic.Template);
} else if (value is WordListTemplate wordList) {
serializer.Serialize(writer, wordList);
} else {
throw new JsonWriterException("unexpected template kind");
}
}
}
[Serializable]
public class WordList {
public string Name { get; init; }

View File

@ -104,6 +104,21 @@ internal class Write : ITab {
ImGui.EndCombo();
}
void DrawSpecificWordPicker(string id, WordListTemplate template, ref (int, int) x) {
var preview = x == (-1, -1) ? "" : template.Words[x.Item2];
if (!ImGui.BeginCombo(id, preview)) {
return;
}
for (var wordIdx = 0; wordIdx < template.Words.Length; wordIdx++) {
if (ImGui.Selectable(template.Words[wordIdx], x == (-1, wordIdx))) {
x = (-1, wordIdx);
}
}
ImGui.EndCombo();
}
void DrawWordPicker(string id, IReadOnlyList<WordList> words, ref (int, int) x) {
var preview = x == (-1, -1) ? "" : words[x.Item1].Words[x.Item2];
if (!ImGui.BeginCombo(id, preview)) {
@ -149,12 +164,13 @@ internal class Write : ITab {
var preview = new StringBuilder();
var template1 = pack.Templates[this._part1];
var word1 = this._word1 == (-1, -1) ? placeholder : pack.Words[this._word1.Item1].Words[this._word1.Item2];
preview.Append(string.Format(template1, word1));
var wordList1 = template1.Words ?? pack.Words?[this._word1.Item1].Words;
var word1 = this._word1 == (-1, -1) ? placeholder : wordList1?[this._word1.Item2];
preview.Append(string.Format(template1.Template, word1));
if (this._conj != -1) {
var conj = pack.Conjunctions[this._conj];
var isPunc = conj.Length == 1 && char.IsPunctuation(conj[0]);
var conj = pack.Conjunctions?[this._conj];
var isPunc = conj?.Length == 1 && char.IsPunctuation(conj[0]);
if (isPunc) {
preview.Append(conj);
preview.Append('\n');
@ -166,8 +182,9 @@ internal class Write : ITab {
if (this._part2 != -1) {
var template2 = pack.Templates[this._part2];
var word2 = this._word2 == (-1, -1) ? placeholder : pack.Words[this._word2.Item1].Words[this._word2.Item2];
preview.Append(string.Format(template2, word2));
var wordList2 = template2.Words ?? pack.Words?[this._word2.Item1].Words;
var word2 = this._word2 == (-1, -1) ? placeholder : wordList2?[this._word2.Item2];
preview.Append(string.Format(template2.Template, word2));
}
}
@ -182,17 +199,47 @@ internal class Write : ITab {
ImGui.Separator();
DrawPicker("Template##part-1", pack.Templates, ref this._part1);
if (this._part1 > -1 && pack.Templates[this._part1].Contains("{0}")) {
DrawWordPicker("Word##word-1", pack.Words, ref this._word1);
var templateStrings = pack.Templates
.Select(template => template.Template)
.ToArray();
DrawPicker("Template##part-1", templateStrings, ref this._part1);
if (this._part1 > -1 && pack.Templates[this._part1].Template.Contains("{0}")) {
switch (pack.Templates[this._part1]) {
case BasicTemplate basic: {
if (pack.Words != null) {
DrawWordPicker("Word##word-1", pack.Words, ref this._word1);
}
break;
}
case WordListTemplate wordListTemplate: {
DrawSpecificWordPicker("Word##word-1", wordListTemplate, ref this._word1);
break;
}
}
}
DrawPicker("Conjunction##conj", pack.Conjunctions, ref this._conj);
if (pack.Conjunctions != null) {
DrawPicker("Conjunction##conj", pack.Conjunctions, ref this._conj);
}
if (this._conj != -1) {
DrawPicker("Template##part-2", pack.Templates, ref this._part2);
if (this._part2 > -1 && pack.Templates[this._part2].Contains("{0}")) {
DrawWordPicker("Word##word-2", pack.Words, ref this._word2);
DrawPicker("Template##part-2", templateStrings, ref this._part2);
if (this._part2 > -1 && pack.Templates[this._part2].Template.Contains("{0}")) {
switch (pack.Templates[this._part2]) {
case BasicTemplate basic: {
if (pack.Words != null) {
DrawWordPicker("Word##word-2", pack.Words, ref this._word2);
}
break;
}
case WordListTemplate wordListTemplate: {
DrawSpecificWordPicker("Word##word-2", wordListTemplate, ref this._word2);
break;
}
}
}
}
@ -301,7 +348,7 @@ internal class Write : ITab {
var pack = Pack.All[this._pack];
if (this._part1 == -1 || !pack.Templates[this._part1].Contains("{0}")) {
if (this._part1 == -1 || !pack.Templates[this._part1].Template.Contains("{0}")) {
this._word1 = (-1, -1);
}
@ -309,7 +356,7 @@ internal class Write : ITab {
this._part2 = -1;
}
if (this._part2 == -1 || !pack.Templates[this._part2].Contains("{0}")) {
if (this._part2 == -1 || !pack.Templates[this._part2].Template.Contains("{0}")) {
this._word2 = (-1, -1);
}
}
@ -321,7 +368,7 @@ internal class Write : ITab {
var pack = Pack.All[this._pack];
var template1 = pack.Templates[this._part1];
var temp1Variable = template1.Contains("{0}");
var temp1Variable = template1.Template.Contains("{0}");
switch (temp1Variable) {
case true when this._word1 == (-1, -1):
@ -339,7 +386,7 @@ internal class Write : ITab {
}
var template2 = pack.Templates[this._part2];
var temp2Variable = template2.Contains("{0}");
var temp2Variable = template2.Template.Contains("{0}");
switch (temp2Variable) {
case true when this._word2 == (-1, -1):

View File

@ -0,0 +1,693 @@
name: Demon's Souls (PS3)
id: 9ad0d0aa-a1e0-48ff-a1e9-d305b26f4e72
visible: true
order: 7
word-refs:
rewards: &rewards
- "a weapon"
- "armor"
- "a ring"
- "ore"
- "a recovery item"
- "an item"
- "Souls"
- "a valuable weapon"
- "valuable armor"
- "a valuable ring"
- "valuable ore"
- "a valuable recovery item"
- "a valuable item"
- "a strange weapon"
- "strange armor"
- "a strange ring"
- "strange ore"
- "a strange recovery item"
- "a strange item"
- "a Hardstone"
- "a Sharpstone"
- "a Clearstone"
- "a Greystone"
- "a Bladestone"
- "a Dragonstone"
- "a Suckerstone"
- "a Mercurystone"
- "a Marrowstone"
- "a Spiderstone"
- "a Moonlightstone"
- "a Darkmoonstone"
- "a Faintstone"
- "a Cloudstone"
- "a Meltstone"
- "sparkly things"
- "twinkly things"
- "true love"
attacks: &attacks
- "blunt attacks"
- "slash attacks"
- "pierce attacks"
- "one-handed attacks"
- "two-handed attacks"
- "daggers"
- "straight swords"
- "large swords"
- "very large swords"
- "curved swords"
- "katanas"
- "rapiers"
- "axes"
- "large axes"
- "hammers"
- "large hammers"
- "fist weapons"
- "spears"
- "pole weapons"
- "strong weapons"
- "magic weapons"
- "flame weapons"
- "bows"
- "arrows"
- "crossbows"
- "bolts"
- "projectiles"
- "spells"
- "miracles"
- "shields"
- "large shields"
- "fire"
- "bleed attacks"
- "poison"
- "plague"
- "decay"
- "Soul drain"
- "staggering attacks"
- "guard breaks"
- "dodges"
- "shield guards"
- "parries"
- "knockback attacks"
- "clockwise dodges"
- "counterclockwise dodges"
- "pincer attacks"
- "divide and conquer tactics"
- "luring tactics"
- "power pushes"
- "preemptive strikes"
- "standard attacks"
- "attrition"
- "observation"
- "stealthy footsteps"
- "nothing"
- "willpower"
- "luck"
roles: &roles
- "Beginners"
- "Veterans"
- "Confident ones"
- "Cowards"
- "Challengers"
- "Soldiers"
- "Knights"
- "Hunters"
- "Priests"
- "Magicians"
- "Wanderers"
- "Barbarians"
- "Thieves"
- "Temple Knights"
- "Royalty"
terms: &terms
- "Item"
- "Footsteps"
- "At your feet"
- "Head"
- "Safe place"
- "Good guy"
- "Crossbow"
- "At some point..."
- "Someday..."
- "One-way road"
- "Nasty guy"
- "Up"
- "Ascending stairs"
- "Ascending ladder"
- "Movement"
- "Cloudstone"
- "Liar"
- "Singing voice"
- "Luck"
- "While casting..."
- "Sharpstone"
- "Plague"
- "Beware the plague"
- "Ed's Grindstone"
- "MP recovery item"
- "Ranged attack"
- "Large axe"
- "Large shield"
- "Large hammer"
- "Strong attack"
- "Coward"
- "Knockback"
- "Try falling through..."
- "Axe"
- "Lure it out"
- "Yourself"
- "While turning..."
- "Dodge"
- "HP recovery item"
- "While recovering..."
- "Fist weapon"
- "Firebomb"
- "Key"
- "If you get the key..."
- "Hidden passage"
- "Single-handed"
- "Katana"
- "Divide and conquer"
- "Paralysis"
- "Archstone"
- "Shard of Archstone"
- "Widow's Lotus"
- "Hunter"
- "Deceptive cuteness"
- "Poor guy"
- "Cuteness"
- "Observation"
- "Misunderstanding"
- "Willpower"
- "Dangerous foe"
- "Knight"
- "Miracle"
- "Royalty"
- "Royal Lotus"
- "Valuable item"
- "Valuable recovery item"
- "Valuable ore"
- "Valuable treasure"
- "Valuable weapon"
- "Valuable armor"
- "Valuable ring"
- "Carelessness"
- "Formidable foe"
- "Critical attack"
- "Curved sword"
- "Twinkly stuff"
- "Spiderstone"
- "Darkness"
- "Black Phantom"
- "Black Turpentine"
- "Moonstone"
- "Bloodstain"
- "Crystal Lizard"
- "Kick"
- "Primeval Demon"
- "After attacking..."
- "During your attack..."
- "Hardstone"
- "Ore"
- "In your heart"
- "Terrifying foe"
- "Pole weapon"
- "If you go on ahead..."
- "Rapier"
- "Slash attack"
- "Battle of attrition"
- "Confident one"
- "Down"
- "Descending stairs"
- "Descending ladder"
- "Thrust attack"
- "Stealthy footsteps"
- "Perimeter"
- "V.I.P."
- "Bleeding"
- "Bleeding resistance"
- "Front"
- "Item burden"
- "Beginner"
- "Sticky White Stuff"
- "True love"
- "Priest"
- "Temple Knight"
- "Mercurystone"
- "Marrowstone"
- "Suckerstone"
- "Overhead"
- "Stamina"
- "World Tendency"
- "Great view"
- "Below"
- "Narrow corridor"
- "Preemptive strike"
- "Reinforcement"
- "Equipment burden"
- "Soul"
- "Soul drain"
- "If Soul tendency is black..."
- "If Soul tendency is white..."
- "Soul Remains"
- "Side"
- "Sniper's perch"
- "Standard attack"
- "Large sword"
- "Horde of foes"
- "Treasure"
- "Blunt attack"
- "Barrage attack"
- "Shield"
- "Guard"
- "Guard break"
- "Dagger"
- "Power push"
- "Terrain"
- "Challenger"
- "Straight sword"
- "Darkmoonstone"
- "Hammer"
- "Strong weapon"
- "Tough guy"
- "Adversary"
- "Escape"
- "Thief"
- "Poison"
- "Very large sword"
- "Poison swamp"
- "Poison resistance"
- "Anywhere"
- "Closed door"
- "Closed gate"
- "Rush"
- "Projectile"
- "Door"
- "Greystone"
- "Escape route"
- "Remaining HP"
- "Remaining MP"
- "Rear"
- "Back Side"
- "Stone of Ephemeral Eyes"
- "Pincer attack"
- "Chest"
- "Parry"
- "Savage"
- "Sparkly"
- "Light"
- "Faintstone"
- "Left"
- "Counterclockwise"
- "Open area"
- "Sneak attack"
- "Intense pursuit"
- "Weapon"
- "Dead end"
- "Corrosion"
- "Staggering attack"
- "Bolt"
- "Soldier"
- "Soldier's Lotus"
- "Veteran"
- "If you disguise yourself..."
- "Strange item"
- "Strange recovery item"
- "Strange ore"
- "Strange foe"
- "Strange weapon"
- "Strange armor"
- "Strange ring"
- "Armor"
- "Roar"
- "Wanderer"
- "Howl"
- "Other"
- "Fire"
- "Fire defense"
- "Flame weapon"
- "Magician"
- "Ambush"
- "Turpentine"
- "Spell"
- "Magic defense"
- "Magic weapon"
- "Trick road"
- "Invisible foe"
- "Right"
- "Clockwise"
- "Augite of Guidance"
- "Clearstone"
- "Illusion"
- "Ignore"
- "Message"
- "Merchant"
- "Sounds"
- "Gate"
- "Arrow"
- "Bladestone"
- "Spear"
- "Friend"
- "Ring"
- "Bow"
- "Lava"
- "Meltstone"
- "Pay attention"
- "Weak guy"
- "Fall"
- "Rhythm"
- "Dragonstone"
- "Two-handed attack"
- "Lever"
- "If you use the lever..."
- "Combo attack"
- "After combo"
- "During combo"
- "Crossroads"
templates:
- template: 'Beware of {0} ahead.'
words:
- "the ceiling"
- "the floor"
- "the rear area"
- "a fall"
- "the bloodstain"
- "the message"
- "a World Tendency event"
- "the poison swamp"
- "the lava"
- "the crossroads"
- "a trick road"
- "the sounds"
- "the footsteps"
- "the singing voice"
- "the darkness"
- "the light"
- "a distraction"
- "not using caution"
- "misunderstanding what's"
- "an illusion"
- "the liar"
- "the adversary"
- "the formidable foe"
- "the horde of foes"
- "the dangerous foe"
- "the invisible foe"
- "the bizarre foe"
- "the terrifying foe"
- "the cute foe"
- "the Black Phantom"
- "the bow-users"
- "ranged attacks"
- "the spell-users"
- "the miracle-users"
- "fire"
- "bleeding"
- "poison"
- "plague"
- "paralysis"
- "corrosion"
- "Soul drain"
- "your remaining HP"
- "your remaining MP"
- "your stamina"
- "your equipment burden"
- "your item burden"
- template: 'Beware of the enemy''s {0}.'
words:
- "ambush"
- "sneak attack"
- "barrage"
- "reinforcements"
- "escape"
- "intense pursuit"
- "movement"
- "rhythm"
- "perimeter"
- "terrain"
- "strong attacks"
- "critical attacks"
- "combo attacks"
- "rush"
- "staggering attacks"
- "guard break"
- "evasion"
- "guard"
- "parries"
- "knockback"
- "kick"
- "roar"
- "howl"
- "bows"
- "ranged attacks"
- "spells"
- "miracles"
- "fire attacks"
- "bloodletting"
- "poison"
- "plague"
- "paralysis"
- "decay"
- "Soul drain"
- "cuteness"
- template: 'There''s {0} ahead.'
words:
- "treasure"
- "valuable treasure"
- "keys"
- "an Archstone"
- "bloodstains"
- "messages"
- "a lever"
- "a door"
- "a gate"
- "a closed door"
- "a closed gate"
- "an escape route"
- "a dead end"
- "a one-way road"
- "a hidden passage"
- "a fall"
- "ascending stairs"
- "descending stairs"
- "a ladder up"
- "a ladder down"
- "a narrow place"
- "an open place"
- "a safe place"
- "a sniper's perch"
- "a great view"
- template: 'A {0} lies in wait ahead.'
words:
- "merchant"
- "V.I.P."
- "friend"
- "good guy"
- "poor guy"
- "bad guy"
- "tough guy"
- "weak guy"
- "liar"
- "villain"
- "formidable foe"
- "horde of foes"
- "dangerous foe"
- "hidden foe"
- "strange foe"
- "terrifying foe"
- "cute foe"
- "Black Phantom"
- "Crystal Lizard"
- "Primeval Demon"
- template: 'You''ll find {0} past here.'
words: *rewards
- template: 'You''ll get {0} from the next foe.'
words: *rewards
- template: 'If you {0}, you can proceed.'
words:
- "get the key"
- "use the lever"
- "have white Soul tendency"
- "have black Soul tendency"
- "press on"
- "keep trying"
- "don't give up"
- "disguise yourself"
- template: 'Use {0} on the next enemy.'
words: *attacks
- template: 'Don''t bother with {0}.'
words: *attacks
- template: 'The next enemy''s weakness is {0}.'
words:
- "its head"
- "its feet"
- "its back"
- "its chest"
- "its front"
- "its side"
- "its back"
- "during its attack"
- "after its attack"
- "during its combo"
- "after its combo"
- "during its recovery"
- "when it turns"
- "when it chants"
- "above"
- "below"
- "to the left"
- "to the right"
- "not what you think"
- "anywhere"
- "in your heart"
- "you"
- template: 'Don''t go forward without {0}.'
words:
- "a dagger"
- "a straight sword"
- "a large sword"
- "a very large sword"
- "a curved sword"
- "a katana"
- "a rapier"
- "an axe"
- "a large axe"
- "a hammer"
- "a large hammer"
- "a fist weapon"
- "a spear"
- "a pole weapon"
- "a strong weapon"
- "a magic weapon"
- "a flame weapon"
- "a bow"
- "arrows"
- "a crossbow"
- "bolts"
- "projectiles"
- "spells"
- "miracles"
- "a shield"
- "a large shield"
- "spell resistance"
- "fire defense"
- "bleed resistance"
- "poison resistance"
- "plague resistance"
- "recovery items"
- "a Soldier's Lotus"
- "a Royal Lotus"
- "a Widow's Lotus"
- "MP recovery items"
- "a grindstone"
- "a Stone of Ephemeral Eyes"
- "a Splinter of Archstone"
- "an Augite of Guidance"
- "Soul remains"
- "Turpentine"
- "Black Turpentine"
- "Sticky White Stuff"
- "Firebombs"
- template: "You'll need a Soul Level of {0} ahead."
words:
- '1'
- '2'
- '3'
- '4'
- '5'
- '6'
- '7'
- '8'
- '9'
- '10'
- '11'
- '12'
- '13'
- '14'
- '15'
- '16'
- '17'
- '18'
- '19'
- '20'
- '21'
- '22'
- '23'
- '24'
- '25'
- '26'
- '27'
- '28'
- '29'
- '30'
- '31'
- '32'
- '33'
- '34'
- '35'
- '36'
- '37'
- '38'
- '39'
- '40'
- template: '{0} should go here first.'
words: *roles
- template: '{0} should try this area later.'
words: *roles
- "Watch out."
- "Listen well."
- "Think hard."
- "Remember..."
- "Don't stop!"
- "Run straight through."
- "Take a step forward."
- "Watch yourself."
- "This is it."
- "The true Demon's Souls starts here."
- "Welcome!"
- "Hi!"
- "Farewell!"
- "Best of luck to you."
- "There are demons nearby."
- "It's safe here."
- "It's not safe here."
- "You can summon here."
- "Requesting a challenger..."
- "I'm in trouble please recommend this message!"
- "Write more messages!"
- "Beware of false messages."
- "Don't attack!"
- "Attack!"
- "I've got a good item..."
- "If you press onward..."
- "If you jump down from here..."
- "Behind you!"
- "If you read this message..."
- "I'm lost..."
- "This place again...?"
- "Why is it always..."
- "My heart's breaking..."
- "Now I've done it..."
- "I want to go home..."
- "I want to be resurrected..."
- "I've been in Soul form for so long..."
- "If I only had some friends..."
- "I told you so."
- "This is no time to read messages!"
- "Did you think there'd be a hint?"
- "The answer is within you."
- template: "{0}"
words: *terms

View File

@ -28,7 +28,33 @@
"type": "array",
"description": "An array of template strings, using {0} for where the chosen word should be inserted (if any).",
"items": {
"type": "string"
"anyOf": [
{
"type": "string",
"description": "A template that should use the global word list defined at the root of this document."
},
{
"type": "object",
"description": "A template that should use its own word list defined on the template object.",
"properties": {
"template": {
"type": "string",
"description": "The template string, using {0} for where the chosen word should be inserted (if any)."
},
"words": {
"type": "array",
"description": "A list of words for this template specifically.",
"items": {
"type": "string"
}
}
},
"required": [
"template",
"words"
]
}
]
},
"minItems": 1
},
@ -72,8 +98,6 @@
"id",
"visible",
"order",
"templates",
"conjunctions",
"words"
"templates"
]
}

View File

@ -9,9 +9,36 @@ pub struct Pack {
pub visible: bool,
#[serde(default, skip_serializing)]
pub order: u8,
pub templates: Vec<String>,
pub conjunctions: Vec<String>,
pub words: Vec<WordList>,
pub templates: Vec<Template>,
pub conjunctions: Option<Vec<String>>,
pub words: Option<Vec<WordList>>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(untagged)]
pub enum Template {
Basic(String),
List {
template: String,
words: Vec<String>,
},
}
impl Template {
pub fn template(&self) -> &str {
match self {
Self::Basic(template) => template,
Self::List { template, .. } => template,
}
}
pub fn requires_word(&self) -> bool {
self.template().contains("{0}")
}
pub fn format(&self, word: &str) -> String {
self.template().replace("{0}", word)
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
@ -21,27 +48,71 @@ pub struct WordList {
}
impl Pack {
pub fn format(&self, template_1_idx: usize, word_1_idx: Option<(usize, usize)>, conjunction: Option<usize>, template_2_idx: Option<usize>, word_2_idx: Option<(usize, usize)>) -> Option<String> {
let template_1 = self.templates.get(template_1_idx)?;
fn get_word(&self, list_idx: usize, word_idx: usize) -> Option<&str> {
let words = self.words.as_ref()?;
let list = words.get(list_idx)?;
list.words
.get(word_idx)
.map(|word| word.as_str())
}
if template_1.contains("{0}") && word_1_idx.is_none() {
fn replace(
&self,
template: &Template,
list_idx: usize,
word_idx: usize,
) -> Option<String> {
let word = match template {
Template::Basic(_) => self.get_word(list_idx, word_idx),
Template::List { words, .. } => words
.get(word_idx)
.map(|word| word.as_str()),
}?;
Some(template.format(word))
}
fn partial_format(
&self,
template: &Template,
word_idx: Option<(usize, usize)>,
) -> Option<String> {
let requires_word = template.requires_word();
if requires_word && word_idx.is_none() {
return None;
}
let mut formatted = if_chain::if_chain! {
if template_1.contains("{0}");
if let Some((w1_list, w1_word)) = word_1_idx;
if_chain::if_chain! {
if requires_word;
if let Some((list_idx, word_idx)) = word_idx;
then {
let word_1 = self.words.get(w1_list)?.words.get(w1_word)?;
template_1.replace("{0}", word_1)
self.replace(template, list_idx, word_idx)
} else {
template_1.clone()
Some(template.template().to_string())
}
};
}
}
if let Some(conj_idx) = conjunction {
if let Some(template_2_idx) = template_2_idx {
let conj = self.conjunctions.get(conj_idx)?;
pub fn format(
&self,
template_1_idx: usize,
word_1_idx: Option<(usize, usize)>,
conjunction: Option<usize>,
template_2_idx: Option<usize>,
word_2_idx: Option<(usize, usize)>,
) -> Option<String> {
let template_1 = self.templates.get(template_1_idx)?;
let mut formatted = self.partial_format(template_1, word_1_idx)?;
if_chain::if_chain! {
if let Some(conj_idx) = conjunction;
if let Some(conjunctions) = &self.conjunctions;
if let Some(template_2_idx) = template_2_idx;
then {
let template_2 = self.templates.get(template_2_idx)?;
let append = self.partial_format(template_2, word_2_idx)?;
let conj = conjunctions.get(conj_idx)?;
let is_punc = conj.len() == 1 && conj.chars().next().map(|x| x.is_ascii_punctuation()).unwrap_or(false);
if is_punc {
formatted.push_str(conj);
@ -52,18 +123,6 @@ impl Pack {
formatted.push(' ');
}
let template_2 = self.templates.get(template_2_idx)?;
let append = if_chain::if_chain! {
if template_2.contains("{0}");
if let Some((w2_list, w2_word)) = word_2_idx;
then {
let word_2 = self.words.get(w2_list)?.words.get(w2_word)?;
template_2.replace("{0}", word_2)
} else {
template_2.clone()
}
};
formatted.push_str(&append);
}
}