diff --git a/CHANGELOG.md b/CHANGELOG.md index a113ffa1a..f1d387de1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Export to JSON. - Faction editing. - Tavern illustration. +- Guardhouses - General Store illustration. - Foundry export functionality. +- GMBinder export functionality. ### Changed - Buildings are ordered via road. @@ -34,7 +36,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Individual NPC export (just copy + paste, you'll be fine.) ### Known issues -- On some machines, the faction profile page does not render (however, the text is still there and inspectable via element). - NPC history is still sometimes broken. ## 2.6.3 diff --git a/lib/guardhouse/_common.ts b/lib/guardhouse/_common.ts index 31274016a..671971485 100644 --- a/lib/guardhouse/_common.ts +++ b/lib/guardhouse/_common.ts @@ -2,4 +2,10 @@ import { Building } from '../buildings/_common' export interface Guardhouse extends Building { notableFeature: string + roll: { + expertise: number + cleanliness: number + wealth: number + size: number + } } diff --git a/lib/guardhouse/guardhouseData.ts b/lib/guardhouse/guardhouseData.ts index c270c2950..cafd51374 100644 --- a/lib/guardhouse/guardhouseData.ts +++ b/lib/guardhouse/guardhouseData.ts @@ -1,35 +1,9 @@ import { NPC } from '../npc-generation/_common' +import { ThresholdTable } from '../src/rollFromTable' import { Town } from '../town/_common' +import { Guardhouse } from './_common' -interface GuardhouseData { - name: { - wordNoun: string[] - adjective: string[] - } - notableFeature: { - exclusions?(town: Town): boolean - function(): string - }[] - evidenceLocker: { - items: { - function(): string - }[] - } - get: { - officeItems: string[] - officeDescription: { - wealth: number - size: number - description: string - }[] - holdingCell: { - reason: string - base?: Partial - }[] - } -} - -export const guardhouseData: GuardhouseData = { +export const guardhouseData = { name: { wordNoun: [ 'watchtower', @@ -37,17 +11,19 @@ export const guardhouseData: GuardhouseData = { 'garrison', 'quarters', 'fort', - 'fortress', - 'citadel', 'station', 'command post', 'office', 'command' - ], + ] as string[], adjective: [ 'yellow', 'green', 'blue', + 'red', + 'black', + 'white', + 'grey', 'grim', 'silent', 'watchful', @@ -55,14 +31,10 @@ export const guardhouseData: GuardhouseData = { 'ancient', 'old', 'new', - 'large', - 'small', - 'tiny', - 'underground', - 'short', - 'tall', - 'towering' - ] + 'bronze', + 'iron', + 'sterling' + ] as string[] }, notableFeature: [ // the guardhouse is known for @@ -114,8 +86,10 @@ export const guardhouseData: GuardhouseData = { return "the town's moneylenders also occupy the same building. The townsfolk often look to it with disgust as moneylender and guard are often a pair." } } - - ], + ] as { + exclusions?(town: Town): boolean + function(): string + }[], evidenceLocker: { // Inside the evidence locker, there is ___ items: [ @@ -219,9 +193,57 @@ export const guardhouseData: GuardhouseData = { return 'a cane with a hidden compartment. It belonged to a noble of ill repute.' } } - ] + ] as { + function(): string + }[] }, get: { + /** @example `At the moment, ______ */ + event: (town: Town, guardhouse: Guardhouse) => [ + { + exclusions (town: Town) { return town.roll.law > 50 }, + function () { return 'an execution is taking place.' } + }, + { + function () { return "a guard is taking down a witness's statement." } + }, + { + function () { return "a guard is holding a child's hand, who appears to be slightly lost." } + }, + { + function () { return 'a duo of two people in handcuffs are currently trying to throw each other under the bus.' } + }, + { + function () { return 'a celebration is taking place; the guardhouse is decked in cheer and decor, the joyous noise audible outside.' } + }, + { + exclusions (town: Town, guardhouse: Guardhouse) { return guardhouse.roll.expertise > 60 }, + function () { return 'a community program is going on. Townsfolk of all ages are seen inside, eagerly waiting. One of the guards is currently leading a small discussion.' } + }, + { + exclusions (town: Town, guardhouse: Guardhouse) { return guardhouse.roll.expertise < 50 }, + function () { return "a sizable number of people in the midst of a heated discussion. They're threatening something if their demands aren't accepted." } + }, + { + function () { return `a person of authority is performing an inspection of ${guardhouse.name}.` } + }, + { + function () { return "a noble is arguing about some fine which was levied against them- they clearly don't think that it's fair." } + }, + { + exclusions (town: Town, guardhouse: Guardhouse) { return guardhouse.roll.expertise < 50 }, + function () { return "a noble is arguing about some fine which was levied against them- they clearly don't think that it's fair, and after some money exchanges hands, it appears that the fine has been reduced in severity." } + }, + { + function (town: Town, guardhouse: Guardhouse) { + if (guardhouse.roll.expertise > 80) return 'a husband and wife are shouting, trying to get into the guard house, but are being blocked. They are screaming about the guards ignoring their child who has gone missing. The guards are patiently explaining something to them- it seems that they are quite used to the pair.' + if (guardhouse.roll.expertise > 50) return 'a husband and wife are shouting, trying to get into the guard house, but are being blocked. They are screaming about the guards ignoring their child who has gone missing, but the guards are totally disinterested- a stark contrast to the frantic parents, they seem unperturbed, even annoyed.' + if (guardhouse.roll.expertise <= 50) return 'a husband and wife are shouting, trying to get into the guard house, but are being blocked. They are screaming about the guards ignoring their child who has gone missing, but the guards are actively jeering, seeming to take some amusement in the couples pleading.' + } + } + ] as { + function(): string + }[], officeItems: [ // There is ____ 'a fine looking sword which has a gem embedded in the pommel- looks mostly decorative, but could definitely hurt someone if it was put to use.', @@ -234,8 +256,8 @@ export const guardhouseData: GuardhouseData = { "a small bust placed on the desk. It's clearly expensive and symbolic.", "a small shrine to a deity. It's well kept and maintained.", "an amulet on the desk. The chain is polished from wear. It's been left out possibly accidentally." - ], - officeDescription: [ + ] as string[], + officeDescription: (guardhouse: Guardhouse) => [ { wealth: 90, size: 10, @@ -361,9 +383,13 @@ export const guardhouseData: GuardhouseData = { size: 10, description: 'This is a tiny hole in the wall that serves as the local constabulary. There are a few heavily rusted weapons piled in the corner, but no furniture.' } - ], + ] as { + wealth: number + size: number + description: string + }[], + /** @example `In the holding cell is ${reason}` */ holdingCell: [ - // In the holding cell is ${reason} { reason: 'a gnome dressed in black rogues gear caught beating up a man in an alley. She claims she was stopping him from committing a crime.', base: { @@ -478,6 +504,202 @@ export const guardhouseData: GuardhouseData = { background: 'criminal' } } + ] as { + reason: string + base?: Partial + }[], + customers: [ + { + relationshipDescription: 'guard', + relationships: { + building: { + relationship: 'guard', + reciprocalRelationship: 'place of work' + }, + associatedNPC: { + relationship: 'peer' + } + }, + base: { + profession: 'guard' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} works in ${building.name}.` } + }, + { + relationshipDescription: 'prisoner', + relationships: { + building: { + relationship: 'prisoner', + reciprocalRelationship: 'place of imprisonment' + }, + associatedNPC: { + relationship: 'captor' + } + }, + base: { + professionSector: 'crime' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} is a captured criminal being held in ${building.name} awaiting trial.` } + }, + { + relationshipDescription: 'investigator', + relationships: { + building: { + relationship: 'investigator', + reciprocalRelationship: 'place of work' + }, + associatedNPC: { + relationship: 'peer' + } + }, + base: { + profession: 'investigator' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} works on cases in ${building.name}.` } + }, + { + relationshipDescription: 'kidnapper', + relationships: { + building: { + relationship: 'kidnapper', + reciprocalRelationship: 'sends letters of demand' + }, + associatedNPC: { + relationship: 'contact point' + } + }, + base: { + profession: 'kidnapper' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} is kidnapping children, and sending ransom letters to ${building.name}.` } + }, + { + relationshipDescription: 'fugitive', + relationships: { + building: { + relationship: 'fugitive', + reciprocalRelationship: 'pursuant body' + }, + associatedNPC: { + relationship: 'lead investigator' + } + }, + base: { + profession: 'fugitive' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} is a dangerous fugitive being hunted down by ${building.name}.` } + }, + { + relationshipDescription: 'wanted criminal', + relationships: { + building: { + relationship: 'wanted criminal', + reciprocalRelationship: 'pursuant body' + }, + associatedNPC: { + relationship: 'lead investigator' + } + }, + base: { + professionSector: 'crime' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} is a wanted criminal being hunted down by ${building.name}.` } + }, + { + relationshipDescription: 'informant', + relationships: { + building: { + relationship: 'informant', + reciprocalRelationship: 'informee' + }, + associatedNPC: { + relationship: 'lead investigator' + } + }, + base: { + professionSector: 'crime' + }, + description (building: Guardhouse, npc: NPC) { return `${npc.firstName} is an informant who is assisting ${building.name} with their investigations.` } + } ] + }, + rollData: { + wealth: { + description: 'How well are they funded?', + preceding: 'Guardhouse Wealth:', + rolls: [ + [95, 'kingly'], + [80, 'aristocratic'], + [70, 'wealthy'], + [60, 'comfortable'], + [50, 'modest'], + [25, 'poor'], + [15, 'squalid'], + [0, 'destitute'] + ] as ThresholdTable + }, + size: { + description: 'How large is it?', + preceding: 'Guardhouse Size:', + rolls: [ + [95, 'cavernous'], + [80, 'huge'], + [70, 'quite large'], + [60, 'large'], + [50, 'spacious'], + [40, 'average sized'], + [30, 'somewhat cramped'], + [20, 'small'], + [10, 'tiny'], + [0, 'extremely cramped'] + ] as ThresholdTable + }, + cleanliness: { + description: 'How clean is the guardhouse? What about the cells?', + preceding: 'Guardhouse:', + /** @example `The guardhouse is ______` */ + rolls: [ + [90, 'fastidious- even the prisoner cells are clean.'], + [70, 'very tidy. The prisoner cells are in pretty good condition, and quite liveable.'], + [60, 'tidy, although the cells are in need of a sweeping.'], + [50, 'reasonably tidy, though the cells have the occasional rat.'], + [40, 'somewhat messy, with the worst of it concentrated in the cells, which are in need of a deep clean.'], + [30, 'rather messy- especially the cells, which are positively disgusting.'], + [20, 'very messy, and the cells are even worse, with a fecal aroma wafting out.'], + [10, 'in dire need of a cleaner; blood spatters have seeped in, and the cells are filthy.'], + [0, 'apparently a crime scene in itself, with blood stains everywhere. The cells must be unimaginably bad.'] + ] as ThresholdTable + }, + expertise: { + description: 'How well trained are the guards?', + preceding: 'Guardhouse Training:', + /** @example `The guards are _____` */ + rolls: [ + [80, 'consummate professionals'], + [70, 'professional'], + [60, 'reasonably professional'], + [50, 'as professional as one could expect'], + [40, 'mostly professional, though the occasional bad eggs causes a public scandal now and then'], + [30, 'not exactly known for their professionalism'], + [20, 'not very professional, and are known for not being very good at their jobs'], + [10, 'basically amateurs, with no real procedures or trainings'], + [0, 'basically playing dress-ups, with virtually no interest in actual policing'] + ] as ThresholdTable + }, + reputation: { + description: 'Is it known for applying the law equally, or is it a crime den?', + preceding: 'Guardhouse Reputation:', + hasRolls: false + }, + magic: { + description: 'How likely is it to find magic here?', + preceding: 'Guardhouse Magic:', + hasRolls: false + }, + activity: { + description: 'How busy is the store?', + preceding: 'Guardhouse Activity:', + hasRolls: false + } } } diff --git a/lib/index.ts b/lib/index.ts index 2e4abe416..09f9079e8 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -47,6 +47,8 @@ export * from './faction/setFactionSize' export * from './faction/setFactionStability' export * from './faction/factionSliders' +export * from './guardhouse/guardhouseData' + export * from './general-store/generalStoreData' export * from './general-store/generalStoreModifiers' export * from './general-store/generalStoreRenders' diff --git a/lib/town/roads.ts b/lib/town/roads.ts index f5091c26f..aff007572 100644 --- a/lib/town/roads.ts +++ b/lib/town/roads.ts @@ -698,6 +698,7 @@ export const roads = { 'There\'s a bench on the side of the road, with the wood being smoothed out from many sittings.', 'There\'s a laundry line connecting two houses that are slightly closer together than usual.', 'A crude drawing of an animal carved into a brick wall, affectionately labeled “R.E. Was here.”', + 'A tree has a little heart carved into it, with the name Claire inside.', 'One of the houses on the side leans concerningly far over the road.' ], namesakes: { diff --git a/src/Blacksmith/js/createSmithy.d.ts b/src/Blacksmith/js/createSmithy.d.ts index 81acc53a6..83dfe0317 100644 --- a/src/Blacksmith/js/createSmithy.d.ts +++ b/src/Blacksmith/js/createSmithy.d.ts @@ -2,7 +2,12 @@ import { Building } from '../../../lib/buildings/_common' import { NPC } from '../../../lib/npc-generation/_common' interface Setup { - createSmithy(town: Town, opts?: Partial): Smithy + createSmithy(town: Town, opts?: Partial): Smithy +} + +interface Options { + newBuilding(town: Town, type?: string): Building + npc: Partial } export interface Smithy extends Building { diff --git a/src/Buildings/Components/CreateNewNPC.twee b/src/Buildings/Components/CreateNewNPC.twee index f4487d5cb..b311d8033 100644 --- a/src/Buildings/Components/CreateNewNPC.twee +++ b/src/Buildings/Components/CreateNewNPC.twee @@ -5,11 +5,9 @@ <><><> <><><> <><> - -<><>
-

$currentPassage.randomNPC.name

-<> is currently <> in the corner. +<><>

$currentPassage.randomNPC.name

+<> is currently <> in the corner. You strike up conversation with $currentPassage.randomNPC.himher, and the $currentPassage.randomNPC.descriptor introduces $currentPassage.randomNPC.himherself as <>, <> <>.
-
<
><
> +<><> <> \ No newline at end of file diff --git a/src/Buildings/goodsAndServices.js b/src/Buildings/goodsAndServices.js index a72abe3ae..a6d8dda02 100644 --- a/src/Buildings/goodsAndServices.js +++ b/src/Buildings/goodsAndServices.js @@ -48,7 +48,7 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${[name.noun.random().toUpperFirst(), name.wordNoun.random().toUpperFirst()].random()}`, `The ${name.foodAdjective.random().toUpperFirst()} ${name.noun.random().toUpperFirst()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, @@ -59,7 +59,7 @@ setup.initGoodsAndServices = () => { `The ${lib.flora.fruit.fruitS.random().toUpperFirst()} ${name.nounBakedGood.random().toUpperFirst()}`, `The ${lib.flora.fruit.tree.random().toUpperFirst()} Tree ${name.wordNoun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ 'The Really Good Bakery', @@ -419,7 +419,7 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${[name.noun.random().toUpperFirst(), name.wordNoun.random().toUpperFirst()].random()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, `The ${town.roads[building.road].name} ${name.wordNoun.random().toUpperFirst()}`, @@ -430,7 +430,7 @@ setup.initGoodsAndServices = () => { `The ${lib.flora.flower.bush.random().toUpperFirst()} Bush ${name.wordNoun.random().toUpperFirst()}`, `${name.adjectivePerson.random().toUpperFirst()} ${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ 'The Daisy Chain', @@ -701,14 +701,14 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${[name.noun.random().toUpperFirst(), name.wordNoun.random().toUpperFirst()].random()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, `The ${town.roads[building.road].name} ${name.wordNoun.random().toUpperFirst()}`, `${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, `${name.adjectivePerson.random().toUpperFirst()} ${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ 'Golden Stitching', @@ -1394,14 +1394,14 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${name.noun.random().toUpperFirst()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, `The ${town.roads[building.road].name} ${name.wordNoun.random().toUpperFirst()}`, `${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, `${name.adjectivePerson.random().toUpperFirst()} ${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ 'A Cut Above', @@ -1740,7 +1740,7 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${name.noun.random().toUpperFirst()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, `The ${town.roads[building.road].name} ${name.wordNoun.random().toUpperFirst()}`, @@ -1748,7 +1748,7 @@ setup.initGoodsAndServices = () => { `${name.adjectivePerson.random().toUpperFirst()} ${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, `${building.associatedNPC.lastName}'s Shoe Repair`, unique - ].random() + ].random()) }, unique: [ 'Shoes and More', @@ -2000,7 +2000,7 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${name.noun.random().toUpperFirst()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, `The ${town.roads[building.road].name} ${name.wordNoun.random().toUpperFirst()}`, @@ -2008,7 +2008,7 @@ setup.initGoodsAndServices = () => { `${name.adjectivePerson.random().toUpperFirst()} ${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, `${building.associatedNPC.lastName}'s ${name.noun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ "The Hunter's Mark", @@ -2293,7 +2293,7 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${[name.noun.random(), name.wordNoun.random()].random().toUpperFirst()}`, `The ${name.jewelleryAdjective.random().toUpperFirst()} ${name.noun.random().toUpperFirst()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, @@ -2302,7 +2302,7 @@ setup.initGoodsAndServices = () => { `${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, `${building.associatedNPC.lastName}'s ${name.noun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ 'Emerald City Gems', @@ -2536,7 +2536,7 @@ setup.initGoodsAndServices = () => { function (town, building) { const name = setup.goodsAndServices[building.type].name const unique = name.unique.random() || `The ${town.name} ${name.wordNoun.random().toUpperFirst()}` - return [ + return lib.toTitleCase([ `The ${name.adjective.random().toUpperFirst()} ${name.noun.random().toUpperFirst()}`, `The ${town.name} ${name.wordNoun.random().toUpperFirst()}`, `The ${town.roads[building.road].name} ${name.wordNoun.random().toUpperFirst()}`, @@ -2544,7 +2544,7 @@ setup.initGoodsAndServices = () => { `${name.adjectivePerson.random().toUpperFirst()} ${building.associatedNPC.firstName}'s ${name.wordNoun.random().toUpperFirst()}`, `${building.associatedNPC.lastName}'s ${name.noun.random().toUpperFirst()}`, unique - ].random() + ].random()) }, unique: [ 'A Little Off The Top', diff --git a/src/Docks/createDocks.d.ts b/src/Docks/createDocks.d.ts index 5567fade3..0202126b3 100644 --- a/src/Docks/createDocks.d.ts +++ b/src/Docks/createDocks.d.ts @@ -1,5 +1,10 @@ interface Setup { - createDocks(town: Town, opts?: Partial): Docks + createDocks(town: Town, opts?: Partial): Docks +} + +interface Options { + newBuilding(town: Town, type?: string): Building + npc: Partial } export interface Docks { diff --git a/src/Factions/FactionProfile.twee b/src/Factions/FactionProfile.twee index 048429366..8e87f6fb6 100644 --- a/src/Factions/FactionProfile.twee +++ b/src/Factions/FactionProfile.twee @@ -1,8 +1,8 @@ :: FactionProfile -<><><> -<> -

$currentPassage.name

-<
><> is <> $currentPassage.wordNoun. It's $currentPassage.age, and the $currentPassage.size faction has <> reputation, and is motivated by $currentPassage.motivation. They are $currentPassage.misc. +\<><><> +\<> +\

$currentPassage.name

+<> is <> $currentPassage.wordNoun. It's $currentPassage.age, and the $currentPassage.size faction has <> reputation, and is motivated by $currentPassage.motivation. They are $currentPassage.misc. <><><> <>

Members

Members of $currentPassage.name are identifiable by $currentPassage.membersTrait. Membership requires $currentPassage.joiningRequirement, and costs $currentPassage.joiningFee. The initiation into $currentPassage.name involves $currentPassage.joiningInitiation. diff --git a/src/Factions/components/FactionGovernance.twee b/src/Factions/components/FactionGovernance.twee index e71a44d42..3fbc225b2 100644 --- a/src/Factions/components/FactionGovernance.twee +++ b/src/Factions/components/FactionGovernance.twee @@ -1,10 +1,9 @@ :: FactionGovernance -

Governance

<> +

Governance

It's ruled by -<> - <> - <> of $currentPassage.leaderGroupSize, who were $currentPassage.leaderQualification. They are $currentPassage.leaderCompetence, and their positions on the $currentPassage.leaderGroupTitle are $currentPassage.stability<> due to $currentPassage.stabilityCause<>. Their meetings are held $currentPassage.meetingRegularity, and are $currentPassage.meetingAccessibility. Bribes to the $currentPassage.leaderGroupTitle $currentPassage.leaderBribes. - <><> - <>, who was $currentPassage.leaderQualification. <> is $currentPassage.leaderCompetence, and _leader.hisher position is $currentPassage.stability<> due to $currentPassage.stabilityCause<>. Bribes $currentPassage.leaderBribes. +\<> + \<> + \<> of $currentPassage.leaderGroupSize, who were $currentPassage.leaderQualification. They are $currentPassage.leaderCompetence, and their positions on the $currentPassage.leaderGroupTitle are $currentPassage.stability<> due to $currentPassage.stabilityCause<>. Their meetings are held $currentPassage.meetingRegularity, and are $currentPassage.meetingAccessibility. Bribes to the $currentPassage.leaderGroupTitle $currentPassage.leaderBribes. + \<><> + \<>, who was $currentPassage.leaderQualification. <> is $currentPassage.leaderCompetence, and _leader.hisher position is $currentPassage.stability<> due to $currentPassage.stabilityCause<>. Bribes $currentPassage.leaderBribes. <> -<
> \ No newline at end of file diff --git a/src/Factions/components/FactionPolitics.twee b/src/Factions/components/FactionPolitics.twee index 6532f45c5..eef9a0258 100644 --- a/src/Factions/components/FactionPolitics.twee +++ b/src/Factions/components/FactionPolitics.twee @@ -1,6 +1,6 @@ :: FactionPolitics -

Politics

$currentPassage.name have $currentPassage.alliesDescription; <> -<> +

Politics

$currentPassage.name have $currentPassage.alliesDescription; +<
><> <> and $currentPassage.allies[1] can be called on for aid. <> <> are the only others they can rely on. @@ -15,9 +15,8 @@ _allies, <> and <>. -<><> - -$currentPassage.name have $currentPassage.rivalsDescription; <><> +<> +$currentPassage.name have $currentPassage.rivalsDescription; <> <> and $currentPassage.rivals[1] are the only that wish $currentPassage.name ill. <> <> are the enemies of $currentPassage.name. diff --git a/src/Factions/components/FactionResources.twee b/src/Factions/components/FactionResources.twee index 596134b05..c8914c593 100644 --- a/src/Factions/components/FactionResources.twee +++ b/src/Factions/components/FactionResources.twee @@ -1,6 +1,5 @@ :: FactionResources -

Resources

<
> -They have $currentPassage.resourcesDescription resources. <> +

Resources

<
>They have $currentPassage.resourcesDescription resources. <> <> and <> are their only significant resources. <> <> are their only significant resources. diff --git a/src/Factions/components/PolicingFaction.twee b/src/Factions/components/PolicingFaction.twee index f471f8eb7..2e36cc2ee 100644 --- a/src/Factions/components/PolicingFaction.twee +++ b/src/Factions/components/PolicingFaction.twee @@ -1,6 +1,6 @@ :: PolicingFaction -

Policing

<> - <>$town.name is policed by $currentPassage.name. $town.guard.funding - <>$town.name is policed by $currentPassage.name, rather than a separate guard. $town.guard.funding -<>One can recognise a member of $currentPassage.name by the <><><>$currentPassage.membersTrait<>. +

Policing

<> + <>$town.name is policed by $currentFaction.name. $town.guard.funding + <>$town.name is policed by $currentFaction.name, rather than a separate guard. $town.guard.funding +<>One can recognise a member of $currentFaction.name by the <><><>$currentFaction.membersTrait<>.

Law in $town.name

$town.law \ No newline at end of file diff --git a/src/GeneralStore/GeneralStoreOutput.twee b/src/GeneralStore/GeneralStoreOutput.twee index 596835b21..088742e04 100644 --- a/src/GeneralStore/GeneralStoreOutput.twee +++ b/src/GeneralStore/GeneralStoreOutput.twee @@ -4,7 +4,7 @@ \<> \<> \

$building.name

<> -<> make your way down <>, and enter $building.structure.generalStoreDescriptor and see that inside, the $building.size building is $building.cleanliness.<> $building.clutter<> You notice $building.note. The store's shopkeep is currently $building.idle. +<> make your way down <>, and enter $building.structure.descriptor and see that inside, the $building.size building is $building.cleanliness.<> $building.clutter<> You notice $building.note. The store's shopkeep is currently $building.idle.

Shopkeeper

The shopkeep <> <>. <> introduces $associatedNPC.himherself as <>, the $associatedNPC.owner of the General Store, and $building.say. $building.shopkeepNote. diff --git a/src/GeneralStore/JS/createGeneralStore.d.ts b/src/GeneralStore/JS/createGeneralStore.d.ts index 279dc8eeb..f1c14f8e3 100644 --- a/src/GeneralStore/JS/createGeneralStore.d.ts +++ b/src/GeneralStore/JS/createGeneralStore.d.ts @@ -1,5 +1,10 @@ import { GeneralStore } from '../../../lib/general-store/_common' interface Setup { - createGeneralStore(town: Town, opts?: Partial): GeneralStore + createGeneralStore(town: Town, opts?: Partial): GeneralStore +} + +interface Options { + newBuilding(town: Town, type?: string): Building + npc: Partial } diff --git a/src/GeneralStore/JS/createGeneralStore.js b/src/GeneralStore/JS/createGeneralStore.js index b37026aa9..8c3e11d28 100644 --- a/src/GeneralStore/JS/createGeneralStore.js +++ b/src/GeneralStore/JS/createGeneralStore.js @@ -25,7 +25,7 @@ setup.createGeneralStore = (town, opts = {}) => { buildingType: 'generalStore' }) lib.createStructure(town, generalStore) - generalStore.structure.generalStoreDescriptor = `${lib.articles.output(generalStore.structure.material.wealth)} ${generalStore.structure.material.noun} ${generalStore.wordNoun} with ${lib.articles.output(generalStore.structure.roof.verb)} roof` + generalStore.structure.descriptor = `${lib.articles.output(generalStore.structure.material.wealth)} ${generalStore.structure.material.noun} ${generalStore.wordNoun} with ${lib.articles.output(generalStore.structure.roof.verb)} roof` setup.createGeneralStoreName(town, generalStore) lib.generalStoreModifiers(town, generalStore) diff --git a/src/MiniEstablishments/Brothel/createBrothel.d.ts b/src/MiniEstablishments/Brothel/createBrothel.d.ts index be327c066..af94d6557 100644 --- a/src/MiniEstablishments/Brothel/createBrothel.d.ts +++ b/src/MiniEstablishments/Brothel/createBrothel.d.ts @@ -20,7 +20,7 @@ interface Brothel { notice: string idle: string owner: string - notableFeature?: string + notableFeature: string wealth: string size: string cleanliness: string diff --git a/src/MiniEstablishments/Graveyard/GraveyardOutput.twee b/src/MiniEstablishments/Graveyard/GraveyardOutput.twee index 8f0b42638..48730ecaf 100644 --- a/src/MiniEstablishments/Graveyard/GraveyardOutput.twee +++ b/src/MiniEstablishments/Graveyard/GraveyardOutput.twee @@ -1,14 +1,14 @@ :: GraveyardOutput <
> <> -<> +<> <>

$building.name

<
> <> walk down <> to the $building.wordNoun. It is $building.location, and is $building.size. You enter the $building.wordNoun $building.entrance. It's mostly $building.cleanliness. As you enter you notice $building.feature.

Gravedigger

$building.gravediggerLook. -The gravedigger greets you as you come near, and introduces $building.associatedNPC.himherself as <>. <> says $building.gravediggerChat. +The gravedigger greets you as you come near, and introduces $associatedNPC.himherself as <>. <> says $building.gravediggerChat. <><><><><><> <><>
$building.grave.readout
<
><
>
<><><>
\ No newline at end of file diff --git a/src/MiniEstablishments/Guardhouse/GuardhouseOutput.twee b/src/MiniEstablishments/Guardhouse/GuardhouseOutput.twee new file mode 100644 index 000000000..f012b3ad7 --- /dev/null +++ b/src/MiniEstablishments/Guardhouse/GuardhouseOutput.twee @@ -0,0 +1,21 @@ +:: GuardhouseOutput +<> +<> +<> +<> +<> +

$building.name

+<
> +<> make your way down <>, and enter $building.name $building.structure.descriptor. $building.name is known for $building.notableFeature +It is run by <>, who are $building.expertise. +At the moment, <> +<> +

Chief's Office

+The person in charge is <>, a <> <>. <> +<Evidence Locker'>><><><> +\<><>In the evidence locker is $building.evidence<><> +\The guardhouse is $building.cleanliness +<Holding Cell'>><><><><> +<><>In the holding cell is <><> +<> +<People Around" t8n>><><> \ No newline at end of file diff --git a/src/MiniEstablishments/Guardhouse/createGuardhouse.d.ts b/src/MiniEstablishments/Guardhouse/createGuardhouse.d.ts new file mode 100644 index 000000000..8bb1923bb --- /dev/null +++ b/src/MiniEstablishments/Guardhouse/createGuardhouse.d.ts @@ -0,0 +1,8 @@ +interface Setup { + createGuardhouse(town: Town, opts?: Partial): Guardhouse +} + +interface Options { + newBuilding(town: Town, type?: string): Building + npc: Partial +} diff --git a/src/MiniEstablishments/Guardhouse/createGuardhouse.js b/src/MiniEstablishments/Guardhouse/createGuardhouse.js new file mode 100644 index 000000000..327102ea0 --- /dev/null +++ b/src/MiniEstablishments/Guardhouse/createGuardhouse.js @@ -0,0 +1,54 @@ +/** + * Creates the guardhouse. + * @param {import("../../../lib/town/_common").Town} town + */ +setup.createGuardhouse = (town, opts) => { + const guardhouse = (opts.newBuilding || lib.createBuilding)(town, 'guardhouse') + + lib.assign(guardhouse, { + initPassage: 'GuardhouseOutput', + passageName: 'GuardhouseOutput', + buildingType: 'guardhouse', + wordNoun: lib.guardhouseData.name.wordNoun.random(), + needsWordNoun: false, + associatedNPC: setup.createNPC(town, { profession: 'guard', ...opts.associatedNPC }) + }) + lib.createBuildingRelationship(town, guardhouse, guardhouse.associatedNPC, { relationship: 'worker', reciprocalRelationship: 'place of employment' }) + guardhouse.notableFeature = lib.weightedRandomFetcher(town, lib.guardhouseData.notableFeature, guardhouse, undefined, 'function') + + guardhouse.name = setup.createGuardhouseName(town) + lib.createStructure(town, guardhouse) + const props = ['cleanliness', 'expertise'] + for (const propName of props) { + lib.defineRollDataGetter(guardhouse, lib.guardhouseData.rollData[propName].rolls, propName) + } + guardhouse.tippyDescription = `A ${guardhouse.wordNoun} whose guards are ${guardhouse.expertise}. It is known for ${guardhouse.notableFeature}` + return guardhouse +} + +/** + * Returns a guardhouse name. + * @param {import("../../../lib/town/_common").Town} town + */ +setup.createGuardhouseName = (town) => { + const potentialUniqueNames = [ + 'Emberhead Garrison', + 'Nightwatch', + 'Bulwark', + 'The Compass', + 'The Watchtower', + 'The Veil', + 'Watch Headquarters', + 'Bastion', + 'Hillside Watchtower' + ] + if (random(3) > 2) { + return lib.toTitleCase(potentialUniqueNames.random()) + } else { + return lib.toTitleCase([ + `The ${town.type} ${lib.guardhouseData.name.wordNoun.random()}`, + `The ${lib.guardhouseData.name.adjective.random()} ${lib.guardhouseData.name.wordNoun.random()}`, + `The ${lib.guardhouseData.name.adjective.random()} ${town.type} ${lib.guardhouseData.name.wordNoun.random()}` + ].random()) + } +} diff --git a/src/Settings/Setting.js b/src/Settings/Setting.js index 1861772af..f66f01281 100644 --- a/src/Settings/Setting.js +++ b/src/Settings/Setting.js @@ -23,14 +23,6 @@ if (State.metadata.get('forceOneColumn') !== settings.forceOneColumn) { settings.forceOneColumn = State.metadata.get('forceOneColumn') } -if (State.metadata.get('showVerboseErrors') !== settings.showVerboseErrors) { - settings.showVerboseErrors = State.metadata.get('showVerboseErrors') -} - -if (settings.showVerboseErrors) { - jQuery('error-view').css('display', 'block') -} - if (settings.forceOneColumn) { jQuery('html').addClass('force-one-column') } @@ -95,18 +87,6 @@ function settingForceOneColumn () { } } -function settingShowVerboseErrors () { - const showVerboseErrors = State.metadata.get('showVerboseErrors') - if (settings.showVerboseErrors !== showVerboseErrors) { - State.metadata.set('showVerboseErrors', settings.showVerboseErrors) - } - if (settings.showVerboseErrors) { - jQuery('error-view').css('display', 'block') - } else { - jQuery('error-view').css('display', 'none') - } -} - Setting.addToggle('showTutorial', { label: 'Show tutorial?', onChange: settingShowTutorial @@ -151,11 +131,6 @@ Setting.addToggle('hideAds', { onChange: settingHideAds }) -Setting.addToggle('showVerboseErrors', { - label: 'Show debugging information?', - onChange: settingShowVerboseErrors -}) - Setting.addToggle('disableAnalytics', { label: 'Disable analytics?', onChange: settingDisableAnalytics diff --git a/src/Start/StoryInit.twee b/src/Start/StoryInit.twee index b561f52b1..c0e24df06 100644 --- a/src/Start/StoryInit.twee +++ b/src/Start/StoryInit.twee @@ -5,7 +5,7 @@ <> <> <> diff --git a/src/Town/js/createNewBuilding.js b/src/Town/js/createNewBuilding.js index 803190376..6ef40d03d 100644 --- a/src/Town/js/createNewBuilding.js +++ b/src/Town/js/createNewBuilding.js @@ -16,6 +16,7 @@ setup.initBuildingTypes = () => { 'Florist': setup.goodsAndServices.default.create('florist'), 'General Store': setup.createGeneralStore, 'Graveyard': setup.createGraveyard, + 'Guardhouse': setup.createGuardhouse, 'Jeweller': setup.goodsAndServices.default.create('jeweller'), 'Market': setup.createMarket, 'Smithy': setup.createSmithy, diff --git a/src/Town/js/createStartBuildings.js b/src/Town/js/createStartBuildings.js index 56d027f35..c02177068 100644 --- a/src/Town/js/createStartBuildings.js +++ b/src/Town/js/createStartBuildings.js @@ -20,6 +20,7 @@ setup.createStartBuildings = town => { 'Graveyard': ['gravedigger', 'sexton'], 'Dungeon': ['jailer', 'bailiff'], 'Castle': ['castellan', 'king'], + 'Guardhouse': ['city watch', 'captain', 'bailiff', 'guard'], 'Smithy': ['weaponsmith', 'blacksmith', 'farrier', 'armorer'], 'Florist': ['florist', 'botanist'], 'Jeweller': ['lapidary', 'goldsmith', 'silversmith', 'jeweller'], diff --git a/src/Town/js/findPoliceSource.js b/src/Town/js/findPoliceSource.js index e1c479fe2..6f0340012 100644 --- a/src/Town/js/findPoliceSource.js +++ b/src/Town/js/findPoliceSource.js @@ -37,11 +37,12 @@ setup.findPoliceSource = (town) => { /** * @param {import("../../../lib/town/_common").Town} town + * @returns {import("../../../lib/faction/_common").Faction} */ setup.findPolice = (town) => { for (const faction in town.factions) { if (town.factions[faction].isPolicing) { - return faction + return town.factions[faction] } } } diff --git a/src/setup.d.ts b/src/setup.d.ts index d751a82fe..5564d6f18 100644 --- a/src/setup.d.ts +++ b/src/setup.d.ts @@ -36,6 +36,7 @@ interface Setup { createStartBuildings(town: Town): void createStartFactions(town: Town): void createBrothel(town: Town): Building + createCastle(town: Town): Building findPoliceSource(town: Town): void makePolice(town: Town, faction: Faction): void getTownType(town: Town): string