Skip to content

Commit

Permalink
Merge pull request #586 from ryceg:Fix-life-events
Browse files Browse the repository at this point in the history
Add custom images
  • Loading branch information
ryceg authored Apr 23, 2021
2 parents 95e353b + 75eeba8 commit 0b1a500
Show file tree
Hide file tree
Showing 51 changed files with 689 additions and 376 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## 2.8.5

### Added
- Edit button to buildings that have an editor (it's still rather terrible, but at least now it's more visible)
- Custom image uploading for Hero patrons accessible in the settings.

### Changed
- Fixed issue with Patreon thanks list sometimes breaking.
- Modified formatting
- Shifted notification down slightly so it does not collide with the header
- Fixed an issue with Tippy not initialising for elements created in a table.

### Removed
- Obsolete 'Show Sliders' setting.

## 2.8.5

### Added
- Disable NSFW setting which removes slavery and brothels from being generated.
- Unlocked GMBinder exporting for everyone because we hit 100 Patrons! Thanks!
Expand Down
1 change: 1 addition & 0 deletions lib/buildings/_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface Location {
objectType: 'building'
/** The type of building- 'castle', 'townSquare', 'generalStore', etc. */
type: string
buildingType: string
passageName?: string
parentKey?: string
name?: string
Expand Down
16 changes: 11 additions & 5 deletions lib/npc-generation/createDescriptors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { articles } from '../src/articles'
import { NPC } from './_common'

const getHumanOrRaceDescription = (npc: NPC) => {
if (npc.race === 'human') return `${lib.random([npc.weight, npc.height])} ${npc.manwoman}`
return `${lib.random([npc.weight, npc.height])} ${npc.malefemale} ${npc.raceName}`
}

export function createDescriptors (npc: NPC): string[] {
console.log(`assigning descriptors to ${npc.name}...`)

Expand All @@ -9,9 +14,9 @@ export function createDescriptors (npc: NPC): string[] {
* @see https://github.com/ryceg/Eigengrau-s-Essential-Establishment-Generator/wiki/Style-Guide#adjectives
*/
const descriptors = [
`${npc.age || npc.ageStage} ${npc.raceName}`,
`${npc.age || npc.ageStage} ${npc.raceName} with ${npc.physicalTrait}`,
`${npc.skinColour} skinned ${lib.random([npc.weight, npc.height])} ${npc.raceName}`,
`${lib.random([npc.weight, npc.height])} ${npc.raceName}`,
`${getHumanOrRaceDescription(npc)} with ${npc.physicalTrait}`,
`${lib.random([npc.height, npc.age])} ${npc.gender} with ${npc.physicalTrait}`
]

Expand All @@ -22,11 +27,12 @@ export function createDescriptors (npc: NPC): string[] {
default:
switch (npc.race) {
case 'human':
descriptors.push(`${lib.random([npc.weight, npc.height])} ${npc.manwoman}`)
break
default:
descriptors.push(`${lib.random([npc.weight, npc.height])} ${npc.malefemale} ${npc.raceName}`)
descriptors.push(`${lib.random([npc.weight, npc.height])} ${lib.raceTraits[npc.race].raceWords.raceAdjective} ${npc.manwoman}`)
descriptors.push(
getHumanOrRaceDescription(npc),
`${lib.random([npc.weight, npc.height])} ${lib.raceTraits[npc.race].raceWords.raceAdjective} ${npc.manwoman}`
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/npc-generation/familyRelationships.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { roads } from '../town/roads'
import { Town } from '../town/_common'
import { Family, NPC } from './_common'
import { random } from '../src/random'

export const familyRelationships = {
/**
Expand Down Expand Up @@ -107,15 +108,14 @@ export function createFamily (town: Town, npc: NPC) {
road: ''
}
}
createFamilyHouse(town, family)
town.families[key] = family
npc.family = key
}

export function createFamilyHouse (town: Town, family: Family) {
const road = town.roads[family.home.road] ||
roads.findExisting(town) ||
lib.random(Object.keys(town.roads))
random(Object.keys(town.roads))
// roads.assign(town)

for (const member in family.members) {
Expand Down
1 change: 1 addition & 0 deletions lib/religion/religion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ export interface Deity {
* @usage 'Hades resides in ______'
*/
realm?: string
customImage?: URL
followers: Partial<Followers>
/**
* If a deity particularly embodies a virtue or vice, it can be specified.
Expand Down
12 changes: 11 additions & 1 deletion lib/src/createMagic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { magicData, MagicType } from './magicData'
import { random } from './random'
import { assign } from './utils'

export function createMagic <T extends MagicType> (type: T | 'ring') {
export function createMagic <T extends MagicType> (type: T | 'ring'): MagicItem {
console.log(`Type: ${type}`)

if (type === 'ring') {
Expand Down Expand Up @@ -33,3 +33,13 @@ export function createMagic <T extends MagicType> (type: T | 'ring') {
console.log(magic)
return magic
}

export interface MagicItem {
type: string
description: string
name: string
prefix?: string
suffix?: string
prefixProperty?: string
suffixProperty?: string
}
22 changes: 21 additions & 1 deletion lib/src/createRing.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MagicItem } from '@lib'
import { articles } from './articles'
import { getRandomValue } from './getRandomValue'
import { random } from './random'
Expand All @@ -9,7 +10,21 @@ interface Options {
activation: string
}

export function createRing (base?: Partial<Options>) {
interface MagicRing extends MagicItem {
works: string
material: string
decoration: string
gemstone: string
intendedowner: string
importance: string
setting: string
cut: string
power: string
cost: string
activation: string
}

export function createRing (base?: Partial<Options>): MagicRing {
const ringData = createRingData()

const ring = {
Expand Down Expand Up @@ -193,6 +208,11 @@ export function createRing (base?: Partial<Options>) {
])
})

assign(ring, {
type: 'ring',
name: `${ring.gemstone} Ring`,
description: ring.firstOutputs
})
return ring
}

Expand Down
45 changes: 20 additions & 25 deletions lib/src/getIllustration.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,39 @@
import { Town } from '../town/_common'

type Illustration =
| 'general-store-illustration'
| 'tavern-illustration'
| 'town-illustration'
| 'city-illustration'

export const getIllustration = (illustration: Illustration, alt: string) => {
let img = '<img '
img += 'id="illustration" '
const path = getPath()

img += `src="${path}src/Resources/img/hero/${illustration}.jpg" `
// If it's in production, then we can add the srcset options, otherwise we might as well omit it.
if (process.env.NODE_ENV === 'production' && location.origin !== 'file://') img += `srcset="${path}src/Resources/img/hero/${illustration}-x360.jpg 360w, ${path}src/Resources/img/hero/${illustration}-x411.jpg 411w, ${path}src/Resources/img/hero/${illustration}-x500.jpg 500w, ${path}src/Resources/img/hero/${illustration}-x576.jpg 576w, ${path}src/Resources/img/hero/${illustration}-x768.jpg 768w, ${path}src/Resources/img/hero/${illustration}-x992.jpg 992w, ${path}src/Resources/img/hero/${illustration}-x1200.jpg 1200w, ${path}src/Resources/img/hero/${illustration}.jpg" `
img += `alt="${alt || `An image depicting ${lib.articles.output(illustration)}, created by artist Juho Huttunen.`}" `
img += '/>'
return img
}

const getPath = () => {
if (process.env.NODE_ENV === 'production' && location.origin !== 'file://') {
return './'
}
return '../'
}

// It would obviously be preferable to output actual <img>s instead of having it render via SugarCube.
// Unfortunately, I am not a clever man, and cannot figure it out.
export const getImage = (illustration: Illustration) => {
const addLocalSourceSet = (illustration: Illustration, sizes: string[] = ['360', '411', '500', '576', '768', '992', '1200']) => {
let img = ''
const path = getPath()
for (const size of sizes) {
img += `${path}src/Resources/img/hero/${illustration}-x${size}.jpg ${size}w, `
}
return img
}

export const getCustomImage = (url: URL) => {
const img = document.createElement('img')
img.id = 'illustration'
img.src = url as unknown as string
img.alt = 'A custom-defined image.'
return img.outerHTML
}

export const getLocalImage = (illustration: Illustration) => {
const img = document.createElement('img')
const path = getPath()
img.id = 'illustration'
img.src = `${path}src/Resources/img/hero/${illustration}.jpg`
img.srcset = `${path}src/Resources/img/hero/${illustration}-x360.jpg 360w, ${path}src/Resources/img/hero/${illustration}-x411.jpg 411w, ${path}src/Resources/img/hero/${illustration}-x500.jpg 500w, ${path}src/Resources/img/hero/${illustration}-x576.jpg 576w, ${path}src/Resources/img/hero/${illustration}-x768.jpg 768w, ${path}src/Resources/img/hero/${illustration}-x992.jpg 992w, ${path}src/Resources/img/hero/${illustration}-x1200.jpg 1200w, ${path}src/Resources/img/hero/${illustration}.jpg`
if (process.env.NODE_ENV === 'production' && location.origin !== 'file://') img.srcset = `${addLocalSourceSet(illustration)} ${path}src/Resources/img/hero/${illustration}.jpg`
img.alt = `An image depicting ${lib.articles.output(illustration)}, created by artist Juho Huttunen.`
return img
}

export const townOrCity = (town: Town) => {
if (town.type === 'city' || town.type === 'town') return 'city-illustration'
return 'town-illustration'
return img.outerHTML
}
1 change: 1 addition & 0 deletions lib/town/_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface TownProfessions extends Profession {
}

export interface Town extends TownBasics {
localImage: string
taxes: {
welfare: number
military: number
Expand Down
7 changes: 7 additions & 0 deletions lib/town/townRender.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { Town } from './_common'
import { getPolice } from './getPolice'

export const townOrCity = (town: Town) => {
if (town.type === 'city' || town.type === 'town') return 'city-illustration'
return 'town-illustration'
}

export function townRender (town: Town) {
console.log(`Rendering ${town.name}...`)

town.localImage = townOrCity(town)

town.roll.guardFunding = 0

const police = getPolice(town.factions)
Expand Down
19 changes: 9 additions & 10 deletions src/Alchemist/AlchemistOutput.twee
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@

:: AlchemistOutput [alchemist]
\<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>>
\<<set $building.brew to lib.createAlchemy({ type: "brewing potion" })>><<set $currentPassage.availableRelationships to lib.alchemistData.get.customers>>
\<<set $associatedNPC to $npcs[$building.associatedNPC.key]>>
\<h1 class="interactive-only">$building.name</h1>
\<<include "TownMicroEventsOutput">>
<<nobr>><p>You enter $building.name, <<print lib.articles.output($building.structure.alchemistDescriptor)>>. <<print lib.closestMatch(lib.alchemistData.get.lookAround($building), 'note', 'cleanliness', 'wealth', $building.roll.cleanliness, $building.roll.wealth)>> There is a chemist behind the shop counter currently <<print $associatedNPC.idle.random()>>.</p>
:: AlchemistOutput [alchemist nobr]
<<include "PrintImage">>
<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>>
<<set $building.brew to lib.createAlchemy({ type: "brewing potion" })>><<set $currentPassage.availableRelationships to lib.alchemistData.get.customers>>
<<set $associatedNPC to $npcs[$building.associatedNPC.key]>>
<h1 class="interactive-only">$building.name</h1><<button "Edit $building.name" $building.initPassage>><</button>><<include "TownMicroEventsOutput">><p>You enter $building.name, <<print lib.articles.output($building.structure.alchemistDescriptor)>>. <<print lib.closestMatch(lib.alchemistData.get.lookAround($building), 'note', 'cleanliness', 'wealth', $building.roll.cleanliness, $building.roll.wealth)>> There is a chemist behind the shop counter currently <<print $associatedNPC.idle.random()>>.</p>
<section><h3>Chemist</h3><p>The $associatedNPC.weight chemist <<print $associatedNPC.greeting.random()>> <<print ['when you come inside', 'after finishing with another customer', 'as soon as you come through the door', 'when you come up to the counter', 'while you look around'].random()>>. <<print $associatedNPC.heshe.toUpperFirst()>> introduces $associatedNPC.himherself as <<profile $associatedNPC>>, the $associatedNPC.owner of the shop, and asks what $associatedNPC.heshe can do for you.</p>
<<linkreplace "<h4>Talk with $associatedNPC.name</h4>" t8n>>
<<linkreplace "Talk with $associatedNPC.name" t8n>>
<h6>$associatedNPC.name</h6><<include "ChemistTalk">><</linkreplace>></section>
<span class="interactive-only"><<link "<h4>Generate plothook</h4>">><<set $associatedNPC.plot to setup.alchemistMission($town)>><</link>></span><<liveblock>><<if def $associatedNPC.plot>><div id="plothook"><<print ["When you say that you're adventurers, $associatedNPC.hisher $associatedNPC.eyes eyes light up, and $associatedNPC.heshe says", "You chat for a while, and then $associatedNPC.firstName says ", "You discuss business, and when you talk about your adventures, $associatedNPC.firstName asks "].random()>> "$associatedNPC.plot"</div><</if>><</liveblock>>
<span class="interactive-only"><<link "Generate plothook">><<set $associatedNPC.plot to setup.alchemistMission($town)>><</link>></span><<liveblock>><<if def $associatedNPC.plot>><div id="plothook"><<print ["When you say that you're adventurers, $associatedNPC.hisher $associatedNPC.eyes eyes light up, and $associatedNPC.heshe says", "You chat for a while, and then $associatedNPC.firstName says ", "You discuss business, and when you talk about your adventures, $associatedNPC.firstName asks "].random()>> "$associatedNPC.plot"</div><</if>><</liveblock>>
<<include "RandomPotion">>
<<include "AlchemistSell">>
<<details "CreateNewNpc" "Customers">><</nobr>>
<<details "CreateNewNpc" "Customers">>
4 changes: 2 additions & 2 deletions src/Alchemist/ChemistTalk.twee
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
:: ChemistTalk
$associatedNPC.firstName looks <<print $associatedNPC.currentMood.random()>>, and idly shifts a box of <<print lib.alchemistData.ingredients.random()>> as $associatedNPC.heshe talks. The $associatedNPC.raceNote <<print $associatedNPC.chitchat.random()>> as you peruse the shop. $associatedNPC.firstName tells you that $associatedNPC.heshe is working on <<print lib.articles.output($building.brew.potionPurpose)>>, and points to the <<linkappend $building.brew.containerDescription t8n>>. Looking inside the $building.brew.vesselType, you see <<print lib.articles.output( $building.brew.liquidDescription)>> bubbling away<</linkappend>>.
:: ChemistTalk [nobr]
$associatedNPC.firstName looks <<print $associatedNPC.currentMood.random()>>, and idly shifts a box of <<print lib.alchemistData.ingredients.random()>> as $associatedNPC.heshe talks. The $associatedNPC.raceNote <<print $associatedNPC.chitchat.random()>> as you peruse the shop. $associatedNPC.firstName tells you that $associatedNPC.heshe is working on <<print lib.articles.output($building.brew.potionPurpose)>>, and points to the <<linkappend $building.brew.containerDescription t8n>>. Looking inside the $building.brew.vesselType, you see <<print lib.articles.output($building.brew.liquidDescription)>> bubbling away<</linkappend>>.
8 changes: 5 additions & 3 deletions src/Blacksmith/SmithyOutput.twee
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

:: SmithyOutput
:: SmithyOutput [nobr]
<<include "PrintImage">>
<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>>
<<set $associatedNPC to $npcs[$building.associatedNPC.key]>>
<<set $currentPassage.availableRelationships to lib.smithyData.get.customers>>
<<nobr>><h1 class="interactive-only">$building.name</h1>
<h1 class="interactive-only">$building.name</h1>
<<button "Edit $building.name" $building.initPassage>><</button>><br>
<<include "TownMicroEventsOutput">><p>You make your way down <<print lib.createTippyFull($town.roads[$building.road].description, $town.roads[$building.road].name)>>, and enter $building.name and see that inside, the $building.structure.descriptor is $building.size. <<print lib.closestMatch(lib.smithyData.get.lookAround($building), 'note', 'cleanliness', 'wealth', $building.roll.cleanliness, $building.roll.wealtYh)>> There is a blacksmith currently <<print $associatedNPC.idle.random()>>.</p>
<p><<print lib.closestMatch(lib.smithyData.get.expertise($building), 'note', 'expertise', 'wealth', $building.roll.expertise, $building.roll.wealth)>>
<section><h3>Blacksmith</h3><p>The blacksmith <<print $associatedNPC.greeting.random()>> <<print ['when you come inside', 'after finishing with another customer', 'as soon as you come through the door', 'when you come up to the counter', 'while you look around'].random()>>. <<print $associatedNPC.heshe.toUpperFirst()>> introduces $associatedNPC.himherself as <<profile $associatedNPC>>, the $associatedNPC.owner of the smithy, and asks what $associatedNPC.heshe can do for you.</p>
<<include "BlacksmithTalk">></section>
<span class="temporarily-removed click-and-remove-link"><<link "<h4>Generate plothook</h4>">><<set $associatedNPC.plot to setup.blacksmithMission($town)>><<update>><</link>></span><<liveblock>><<if def $associatedNPC.plot>><div id="plothook"><<print ["When you say that you're adventurers, $associatedNPC.hisher $associatedNPC.eyes eyes light up, and $associatedNPC.heshe says", "You chat for a while, and then $associatedNPC.firstName says ", "You discuss business, and when you talk about your adventures, $associatedNPC.firstName asks "].random()>> "$associatedNPC.plot"</div><</if>><</liveblock>>
<<include "SmithySell">>
<<details "CreateNewNpc" "Customers">><</nobr>>
<<details "CreateNewNpc" "Customers">>
1 change: 1 addition & 0 deletions src/Buildings/Components/CreateNewNPC.twee
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<<update>>
<<replace "#BuildingRelationshipsTable">><<include "BuildingRelationshipsTable">><</replace>>
<<replace "#NPCListboxes">><<include "NPCListboxes">><</replace>>
<<run tippy('.tip')>>
<</button>>
<<liveblock>>
<<if $currentPassage.randomNPC>>
Expand Down
1 change: 1 addition & 0 deletions src/Buildings/GenericPassage.twee
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
:: GenericPassage
\<<include "PrintImage">>
<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>><h1 class="interactive-only">$building.name</h1>
<<for _i to 0; _i < $building.PassageFormat.length; _i++>>
<<print $building.PassageFormat[_i]>>
Expand Down
3 changes: 2 additions & 1 deletion src/Castle/CastleOutput.twee
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
:: CastleOutput
<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>>
\<<include "PrintImage">>
\<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>>
\<h1 class="interactive-only"><<print lib.toTitleCase($building.name)>></h1>
<p>This $building.size $building.wordNoun was built by $building.builtBy $building.age, and is $building.condition. As you approach, <<print setup.castle.location[$town.location].vignette.random()>>.</p>
<<if $building.namesake>><p>It is named after <<profile $building.namesake>>, <<print lib.articles.output($building.namesake.profession)>>.</p><</if>><p>It is known for $building.knownFor, and is worth defending because $building.defense.reason. The castle needs assistance $building.lookingFor.</p>
Expand Down
1 change: 1 addition & 0 deletions src/Docks/DocksOutput.twee
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
:: DocksOutput
\<<include "PrintImage">>
\<<set $building to lib.findInArray($town.buildings, "key", $currentPassage.key)>>
\<<set $currentPassage.availableRelationships to setup.docks.get.customers>>
\<h1 class="interactive-only"><<print $building.name.toUpperFirst()>></h1>
Expand Down
1 change: 1 addition & 0 deletions src/Factions/FactionProfile.twee
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
:: FactionProfile
\<<include "PrintImage">>
\<<set $currentPassage to $town.factions[$currentPassage.key]>><<run console.log($currentPassage)>>
\<<set $currentPassage.availableRelationships to lib.factionData.types[$currentPassage.type].members.professions>>
\<h1 class="interactive-only">$currentPassage.name</h1>
Expand Down
Loading

0 comments on commit 0b1a500

Please sign in to comment.