Scenario generator for vore roleplay and story ideas. https://scenario-generator.deliciousreya.net/responses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

244 lines
5.8 KiB

import {
type InProgressGeneratedState, RolledValues, RollSelections,
type RollTableAuthor,
type RollTableDetailsNoResults,
type RollTableLimited,
type RollTableResult,
type RollTableResultSet
} from '../common/rolltable';
export function asBoolean(s: string|undefined): boolean|undefined {
if (typeof s === "undefined") {
return
}
switch (s.toLowerCase()) {
case "true":
return true
case "false":
return false
default:
return
}
}
export function asInteger(s: string|undefined): number|undefined {
if (typeof s === "undefined") {
return
}
const result = parseInt(s)
if (Number.isNaN(result)) {
return
}
return result
}
export function asTimestamp(s: string|undefined): Date|undefined {
const i = asInteger(s)
if (typeof i === "undefined") {
return
}
const date = new Date(i)
if (Number.isNaN(date.valueOf())) {
return
}
return date
}
export function textFrom(e: HTMLElement|null): string|undefined {
if (!e) {
return
}
return e.innerText.trim()
}
export function hrefFrom(e: HTMLAnchorElement|null): string | null {
if (!e) {
return null
}
return e.href
}
export function checkedFrom(e: HTMLInputElement|null): boolean | null {
if (!e) {
return null
}
return e.checked
}
// element to find here is .author
export function scrapeAuthor(author: HTMLElement|null): RollTableAuthor|null|undefined {
if (!author) {
return null
}
const id = asInteger(author.dataset["id"])
const name = textFrom(author.querySelector(".authorName"))
const url = hrefFrom(author.querySelector<HTMLAnchorElement>("a[href]"))
const relation = textFrom(author.querySelector(".authorRelation"))
if (typeof id === "undefined" || typeof name === "undefined" || typeof relation === 'undefined') {
return
}
return {
id,
name,
url,
relation
}
}
// element to find here is .resultSet
export function scrapeResultSet(set: HTMLElement|null): RollTableResultSet|null|undefined {
if (!set) {
return null
}
const id = asInteger(set.dataset["id"])
const name = textFrom(set.querySelector(".setName"))
const global = asBoolean(set.dataset["global"])
if (typeof id === "undefined" || typeof global === "undefined") {
return
}
return {
id,
name: name ?? null,
description: null,
global,
}
}
// element to find here is .tableHeader
export function scrapeTableHeader(head: HTMLElement|null): RollTableLimited|RollTableDetailsNoResults|null|undefined {
if (!head) {
return null
}
const emoji = textFrom(head.querySelector(".tableEmoji"))
const title = textFrom(head.querySelector(".tableTitle"))
const ordinal = asInteger(head.dataset["ordinal"])
const id = asInteger(head.dataset["id"])
const identifier = head.dataset["identifier"]
const name = head.dataset["name"]
if (typeof emoji === 'undefined' || typeof title === 'undefined' || typeof ordinal === 'undefined') {
return
}
const header = `${emoji} ${title}`
if (typeof id === 'undefined' || typeof identifier === 'undefined' || typeof name === 'undefined') {
return {
full: false,
emoji,
title,
header,
ordinal,
}
}
return {
full: 'details',
id,
identifier,
emoji,
title,
header,
ordinal,
name,
}
}
export function scrapeGeneratedHead(head: HTMLElement|null): {table: RollTableLimited|RollTableDetailsNoResults, selected: boolean|null}|null|undefined {
if (!head) {
return null
}
const table = scrapeTableHeader(head.querySelector(".tableHeader"))
if (!table) {
return
}
const selected = checkedFrom(head.querySelector("input[type=checkbox].generatedSelect"))
return {
table,
selected,
}
}
// element to find here is .resultText
export function scrapeResultText(result: HTMLElement|null): {full: false, text: string}|{full: true, mappingId: number, textId: number, updated: Date, text: string}|undefined|null {
if (!result) {
return null
}
const text = textFrom(result)
const mappingId = asInteger(result.dataset["mappingid"])
const textId = asInteger(result.dataset["textid"])
const updated = asTimestamp(result.dataset["updated"])
if (typeof text === 'undefined') {
return
}
if (typeof mappingId === 'undefined' || typeof textId === 'undefined' || typeof updated == 'undefined') {
return {
full: false,
text,
}
}
return {
full: true,
text,
textId,
mappingId,
updated: new Date(updated)
}
}
// element to find here is .generatedElement
export function scrapeGeneratedElement(generated: HTMLElement|null): {result: RollTableResult, selected: boolean|null}|null|undefined {
if (!generated) {
return null
}
const result = scrapeResultText(generated.querySelector(".resultText"))
const author = scrapeAuthor(generated.querySelector(".author"))
const set = scrapeResultSet(generated.querySelector(".resultSet"))
const header = scrapeGeneratedHead(generated.querySelector(".generatedHead"))
if (!header || !result) {
return
}
const {table, selected} = header
if (!set || typeof author === "undefined" || !result.full) {
return {
result: {
full: false,
table,
text: result.text,
},
selected
}
}
return {
result: {
...result,
author,
set,
table,
},
selected,
}
}
export function scrapeGeneratedScenario(scenario: HTMLElement): InProgressGeneratedState|undefined
export function scrapeGeneratedScenario(scenario: null): null
// element to find here is #generatedScenario
export function scrapeGeneratedScenario(scenario: HTMLElement|null): InProgressGeneratedState|null|undefined {
if (!scenario) {
return null
}
const rolls = new RolledValues()
const selection = new RollSelections()
for (const item of scenario.querySelectorAll<HTMLElement>(".generatedElement")) {
const element = scrapeGeneratedElement(item)
if (!element) {
return
}
const {result, selected} = element
rolls.add(result)
if (selected) {
selection.add(result.table)
}
}
return {
final: false,
rolled: rolls,
selected: selection,
}
}