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
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,
|
|
}
|
|
}
|
|
|