Ajust database schema to recent changes
This commit is contained in:
parent
da93fcd82d
commit
042d4479ee
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
23
db/schema.ts
23
db/schema.ts
|
|
@ -1,5 +1,6 @@
|
|||
import { relations } from 'drizzle-orm';
|
||||
import { int, text, sqliteTable as table, primaryKey, blob } from 'drizzle-orm/sqlite-core';
|
||||
import { ABILITIES, MAIN_STATS } from '~/shared/character.util';
|
||||
|
||||
export const usersTable = table("users", {
|
||||
id: int().primaryKey({ autoIncrement: true }),
|
||||
|
|
@ -54,10 +55,9 @@ export const characterTable = table("character", {
|
|||
owner: int().notNull().references(() => usersTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
||||
people: text().notNull(),
|
||||
level: int().notNull().default(1),
|
||||
variables: text({ mode: 'json' }).notNull().default('{"health": 0,"mana": 0,"spells": [],"equipment": [],"exhaustion": 0,"sickness": []}'),
|
||||
aspect: int(),
|
||||
notes: text(),
|
||||
health: int().notNull().default(0),
|
||||
mana: int().notNull().default(0),
|
||||
|
||||
visibility: text({ enum: ['private', 'public'] }).notNull().default('private'),
|
||||
thumbnail: blob(),
|
||||
|
|
@ -83,17 +83,6 @@ export const characterAbilitiesTable = table("character_abilities", {
|
|||
max: int().notNull().default(0),
|
||||
}, (table) => [primaryKey({ columns: [table.character, table.ability] })]);
|
||||
|
||||
export const characterModifiersTable = table("character_modifiers", {
|
||||
character: int().notNull().references(() => characterTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
||||
modifier: text({ enum: ["strength","dexterity","constitution","intelligence","curiosity","charisma","psyche"] }).notNull(),
|
||||
value: int().notNull().default(0),
|
||||
}, (table) => [primaryKey({ columns: [table.character, table.modifier] })]);
|
||||
|
||||
export const characterSpellsTable = table("character_spell", {
|
||||
character: int().notNull().references(() => characterTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
||||
value: text().notNull(),
|
||||
}, (table) => [primaryKey({ columns: [table.character, table.value] })]);
|
||||
|
||||
export const characterChoicesTable = table("character_choices", {
|
||||
character: int().notNull().references(() => characterTable.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
|
||||
id: text().notNull(),
|
||||
|
|
@ -123,8 +112,6 @@ export const characterRelation = relations(characterTable, ({ one, many }) => ({
|
|||
training: many(characterTrainingTable),
|
||||
levels: many(characterLevelingTable),
|
||||
abilities: many(characterAbilitiesTable),
|
||||
modifiers: many(characterModifiersTable),
|
||||
spells: many(characterSpellsTable),
|
||||
choices: many(characterChoicesTable)
|
||||
}));
|
||||
|
||||
|
|
@ -137,12 +124,6 @@ export const characterLevelingRelation = relations(characterLevelingTable, ({ on
|
|||
export const characterAbilitiesRelation = relations(characterAbilitiesTable, ({ one }) => ({
|
||||
character: one(characterTable, { fields: [characterAbilitiesTable.character], references: [characterTable.id] })
|
||||
}));
|
||||
export const characterModifierRelation = relations(characterModifiersTable, ({ one }) => ({
|
||||
character: one(characterTable, { fields: [characterModifiersTable.character], references: [characterTable.id] })
|
||||
}));
|
||||
export const characterSpellsRelation = relations(characterSpellsTable, ({ one }) => ({
|
||||
character: one(characterTable, { fields: [characterSpellsTable.character], references: [characterTable.id] })
|
||||
}));
|
||||
export const characterChoicesRelation = relations(characterChoicesTable, ({ one }) => ({
|
||||
character: one(characterTable, { fields: [characterChoicesTable.character], references: [characterTable.id] })
|
||||
}));
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
DROP TABLE `character_modifiers`;--> statement-breakpoint
|
||||
DROP TABLE `character_spell`;--> statement-breakpoint
|
||||
ALTER TABLE `character` ADD `variables` text DEFAULT '{"health": 0,"mana": 0,"spells": [],"equipment": [],"exhaustion": 0,"sickness": []}' NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE `character` DROP COLUMN `health`;--> statement-breakpoint
|
||||
ALTER TABLE `character` DROP COLUMN `mana`;
|
||||
|
|
@ -0,0 +1,702 @@
|
|||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "05b549e7-5b3f-40f4-9461-05db59391e20",
|
||||
"prevId": "6651137c-a198-4538-86be-7cb8b88ca998",
|
||||
"tables": {
|
||||
"character_abilities": {
|
||||
"name": "character_abilities",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"ability": {
|
||||
"name": "ability",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
},
|
||||
"max": {
|
||||
"name": "max",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_abilities_character_character_id_fk": {
|
||||
"name": "character_abilities_character_character_id_fk",
|
||||
"tableFrom": "character_abilities",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_abilities_character_ability_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"ability"
|
||||
],
|
||||
"name": "character_abilities_character_ability_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_choices": {
|
||||
"name": "character_choices",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"choice": {
|
||||
"name": "choice",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_choices_character_character_id_fk": {
|
||||
"name": "character_choices_character_character_id_fk",
|
||||
"tableFrom": "character_choices",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_choices_character_id_choice_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"id",
|
||||
"choice"
|
||||
],
|
||||
"name": "character_choices_character_id_choice_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_leveling": {
|
||||
"name": "character_leveling",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"level": {
|
||||
"name": "level",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"choice": {
|
||||
"name": "choice",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_leveling_character_character_id_fk": {
|
||||
"name": "character_leveling_character_character_id_fk",
|
||||
"tableFrom": "character_leveling",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_leveling_character_level_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"level"
|
||||
],
|
||||
"name": "character_leveling_character_level_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character": {
|
||||
"name": "character",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"owner": {
|
||||
"name": "owner",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"people": {
|
||||
"name": "people",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"level": {
|
||||
"name": "level",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 1
|
||||
},
|
||||
"variables": {
|
||||
"name": "variables",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'{}'"
|
||||
},
|
||||
"aspect": {
|
||||
"name": "aspect",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"notes": {
|
||||
"name": "notes",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"visibility": {
|
||||
"name": "visibility",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'private'"
|
||||
},
|
||||
"thumbnail": {
|
||||
"name": "thumbnail",
|
||||
"type": "blob",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_owner_users_id_fk": {
|
||||
"name": "character_owner_users_id_fk",
|
||||
"tableFrom": "character",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"owner"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"character_training": {
|
||||
"name": "character_training",
|
||||
"columns": {
|
||||
"character": {
|
||||
"name": "character",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"stat": {
|
||||
"name": "stat",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"level": {
|
||||
"name": "level",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"choice": {
|
||||
"name": "choice",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"character_training_character_character_id_fk": {
|
||||
"name": "character_training_character_character_id_fk",
|
||||
"tableFrom": "character_training",
|
||||
"tableTo": "character",
|
||||
"columnsFrom": [
|
||||
"character"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"character_training_character_stat_level_pk": {
|
||||
"columns": [
|
||||
"character",
|
||||
"stat",
|
||||
"level"
|
||||
],
|
||||
"name": "character_training_character_stat_level_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"email_validation": {
|
||||
"name": "email_validation",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"project_content": {
|
||||
"name": "project_content",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "blob",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"project_files": {
|
||||
"name": "project_files",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"path": {
|
||||
"name": "path",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"owner": {
|
||||
"name": "owner",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"navigable": {
|
||||
"name": "navigable",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": true
|
||||
},
|
||||
"private": {
|
||||
"name": "private",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"order": {
|
||||
"name": "order",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"project_files_path_unique": {
|
||||
"name": "project_files_path_unique",
|
||||
"columns": [
|
||||
"path"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"project_files_owner_users_id_fk": {
|
||||
"name": "project_files_owner_users_id_fk",
|
||||
"tableFrom": "project_files",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"owner"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"user_permissions": {
|
||||
"name": "user_permissions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"permission": {
|
||||
"name": "permission",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"user_permissions_id_users_id_fk": {
|
||||
"name": "user_permissions_id_users_id_fk",
|
||||
"tableFrom": "user_permissions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"user_permissions_id_permission_pk": {
|
||||
"columns": [
|
||||
"id",
|
||||
"permission"
|
||||
],
|
||||
"name": "user_permissions_id_permission_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"user_sessions": {
|
||||
"name": "user_sessions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"user_sessions_user_id_users_id_fk": {
|
||||
"name": "user_sessions_user_id_users_id_fk",
|
||||
"tableFrom": "user_sessions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"user_sessions_id_user_id_pk": {
|
||||
"columns": [
|
||||
"id",
|
||||
"user_id"
|
||||
],
|
||||
"name": "user_sessions_id_user_id_pk"
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users_data": {
|
||||
"name": "users_data",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"signin": {
|
||||
"name": "signin",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"lastTimestamp": {
|
||||
"name": "lastTimestamp",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"users_data_id_users_id_fk": {
|
||||
"name": "users_data_id_users_id_fk",
|
||||
"tableFrom": "users_data",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "cascade"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"hash": {
|
||||
"name": "hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"state": {
|
||||
"name": "state",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"users_hash_unique": {
|
||||
"name": "users_hash_unique",
|
||||
"columns": [
|
||||
"hash"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +113,13 @@
|
|||
"when": 1756214160038,
|
||||
"tag": "0015_typical_blade",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 16,
|
||||
"version": "6",
|
||||
"when": 1756221197092,
|
||||
"tag": "0016_wild_the_anarchist",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -13,7 +13,6 @@ const config = characterConfig as CharacterConfig;
|
|||
|
||||
const id = useRouter().currentRoute.value.params.id;
|
||||
const { user } = useUserSession();
|
||||
const { add } = useToast();
|
||||
|
||||
const { data, status, error } = await useFetch(`/api/character/${id}`);
|
||||
const compiler = new CharacterCompiler(data.value ?? defaultCharacter);
|
||||
|
|
@ -52,7 +51,7 @@ text-light-purple dark:text-dark-purple border-light-purple dark:border-dark-pur
|
|||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Niveau {{ character.level }}</span>
|
||||
<span>{{ character.race === -1 ? "Race inconnue" : config.peoples[character.race]!.name }}</span>
|
||||
<span>{{ config.peoples[character.race]?.name ?? 'Peuple inconnu' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col lg:border-l border-light-30 dark:border-dark-30 py-4 ps-4">
|
||||
|
|
@ -132,7 +131,7 @@ text-light-purple dark:text-dark-purple border-light-purple dark:border-dark-pur
|
|||
<TabsTrigger value="notes" class="px-2 py-1 border-b border-transparent hover:border-accent-blue">Notes</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="features">
|
||||
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
||||
<div class="flex flex-1 flex-col ps-8 gap-4 py-4">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-lg font-semibold">Actions</span>
|
||||
|
|
@ -157,9 +156,10 @@ text-light-purple dark:text-dark-purple border-light-purple dark:border-dark-pur
|
|||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent v-if="character.spellslots > 0" value="spells">
|
||||
<div class="flex flex-1 flex-col ps-8 gap-4 py-8">
|
||||
<div class="flex flex-col" v-if="character.lists.spells && character.lists.spells.length > 0">
|
||||
<div class="pb-4 px-2 mt-4 border-b last:border-none border-light-30 dark:border-dark-30 flex flex-col" v-for="spell of character.lists.spells.map(e => config.spells.find((f: SpellConfig) => f.id === e)).filter(e => !!e)">
|
||||
<div class="flex flex-1 flex-col ps-8 gap-4 py-2">
|
||||
<div class="flex flex-1 justify-between items-center"><span class="italic text-light-70 dark:text-dark-70 text-sm">{{ character.variables.spells.length }} / {{ character.spellslots }} sorts maitrisés</span><Button icon><Icon icon="radix-icons:plus" class="w-6 h-6"/></Button></div>
|
||||
<div class="flex flex-col" v-if="[...(character.lists.spells ?? []), ...character.variables.spells].length > 0">
|
||||
<div class="pb-4 px-2 mt-4 border-b last:border-none border-light-30 dark:border-dark-30 flex flex-col" v-for="spell of [...(character.lists.spells ?? []), ...character.variables.spells].map(e => config.spells.find((f: SpellConfig) => f.id === e)).filter(e => !!e)">
|
||||
<div class="flex flex-row justify-between">
|
||||
<span class="text-lg font-bold">{{ spell.name }}</span>
|
||||
<div class="flex flex-row items-center gap-6">
|
||||
|
|
@ -170,7 +170,7 @@ text-light-purple dark:text-dark-purple border-light-purple dark:border-dark-pur
|
|||
<span class="">Rang {{ spell.rank }}</span><span>/</span>
|
||||
<span class="">{{ spellTypeTexts[spell.type] }}</span><span>/</span>
|
||||
<span class="">{{ spell.cost }} mana</span><span>/</span>
|
||||
<span class="">{{ typeof spell.speed === 'string' ? spell.speed : `${spell.speed} minutes` }}</span>
|
||||
<span class="capitalize">{{ typeof spell.speed === 'string' ? spell.speed : `${spell.speed} minutes` }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import useDatabase from '~/composables/useDatabase';
|
|||
import { characterTable, userPermissionsTable } from '~/db/schema';
|
||||
import { hasPermissions } from '~/shared/auth.util';
|
||||
import { group } from '~/shared/general.util';
|
||||
import type { Character, DoubleIndex, Level, MainStat, TrainingLevel } from '~/types/character';
|
||||
import type { Character, Level, MainStat, TrainingLevel } from '~/types/character';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
let { visibility } = getQuery(e) as { visibility?: "public" | "own" | "admin" };
|
||||
|
|
@ -55,8 +55,6 @@ export default defineEventHandler(async (e) => {
|
|||
with: {
|
||||
abilities: true,
|
||||
levels: true,
|
||||
modifiers: true,
|
||||
spells: true,
|
||||
training: true,
|
||||
choices: true,
|
||||
user: {
|
||||
|
|
@ -76,14 +74,11 @@ export default defineEventHandler(async (e) => {
|
|||
level: character.level,
|
||||
aspect: character.aspect,
|
||||
notes: character.notes,
|
||||
health: character.health,
|
||||
mana: character.mana,
|
||||
variables: character.variables,
|
||||
|
||||
training: character.training.reduce((p, v) => { if(!(v.stat in p)) p[v.stat] = []; p[v.stat].push([v.level as TrainingLevel, v.choice]); return p; }, {} as Record<MainStat, DoubleIndex<TrainingLevel>[]>),
|
||||
leveling: character.levels.map(e => [e.level as Level, e.choice] as DoubleIndex<Level>),
|
||||
training: character.training.reduce((p, v) => { p[v.stat] ??= {}; p[v.stat][v.level as TrainingLevel] = v.choice; return p; }, {} as Record<MainStat, Partial<Record<TrainingLevel, number>>>),
|
||||
leveling: group(character.levels, "level", "choice"),
|
||||
abilities: group(character.abilities, "ability", "value"),
|
||||
spells: character.spells.map(e => e.value),
|
||||
modifiers: group(character.modifiers, "modifier", "value"),
|
||||
choices: character.choices.reduce((p, v) => { p[v.id] ??= []; p[v.id]?.push(v.choice); return p; }, {} as Record<string, number[]>),
|
||||
|
||||
owner: character.owner,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod/v4';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterAbilitiesTable, characterLevelingTable, characterModifiersTable, characterSpellsTable, characterTable, characterTrainingTable } from '~/db/schema';
|
||||
import { characterAbilitiesTable, characterLevelingTable, characterTable, characterTrainingTable } from '~/db/schema';
|
||||
import { CharacterValidation } from '#shared/character.util';
|
||||
import { type Ability, type MainStat } from '~/types/character';
|
||||
|
||||
|
|
@ -32,8 +32,7 @@ export default defineEventHandler(async (e) => {
|
|||
level: body.data.level,
|
||||
aspect: body.data.aspect,
|
||||
notes: body.data.notes,
|
||||
health: body.data.health,
|
||||
mana: body.data.mana,
|
||||
variables: body.data.variables,
|
||||
visibility: body.data.visibility,
|
||||
thumbnail: body.data.thumbnail,
|
||||
}).returning({ id: characterTable.id }).get().id;
|
||||
|
|
@ -43,8 +42,6 @@ export default defineEventHandler(async (e) => {
|
|||
const training = Object.entries(body.data.training).flatMap(e => Object.entries(e[1]).map(_e => ({ character: id, stat: e[0] as MainStat, level: parseInt(_e[0], 10), choice: _e[1]! })));
|
||||
if(training.length > 0) tx.insert(characterTrainingTable).values(training).run();
|
||||
|
||||
if(body.data.spells.length > 0) tx.insert(characterSpellsTable).values(body.data.spells.map(e => ({ character: id, value: e }))).run();
|
||||
|
||||
const abilities = Object.entries(body.data.abilities).map(e => ({ character: id, ability: e[0] as Ability, value: e[1] }));
|
||||
if(abilities.length > 0) tx.insert(characterAbilitiesTable).values(abilities).run();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { and, eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
import { group } from '~/shared/general.util';
|
||||
import type { Character, DoubleIndex, Level, MainStat, TrainingLevel } from '~/types/character';
|
||||
import type { Character, CharacterVariables, Level, MainStat, TrainingLevel } from '~/types/character';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
|
|
@ -26,9 +25,8 @@ export default defineEventHandler(async (e) => {
|
|||
with: {
|
||||
abilities: true,
|
||||
levels: true,
|
||||
modifiers: true,
|
||||
spells: true,
|
||||
training: true,
|
||||
choices: true,
|
||||
user: {
|
||||
columns: { username: true }
|
||||
}
|
||||
|
|
@ -46,15 +44,12 @@ export default defineEventHandler(async (e) => {
|
|||
level: character.level,
|
||||
aspect: character.aspect,
|
||||
notes: character.notes,
|
||||
health: character.health,
|
||||
mana: character.mana,
|
||||
variables: character.variables,
|
||||
|
||||
training: character.training.reduce((p, v) => { p[v.stat] ??= {}; p[v.stat][v.level as TrainingLevel] = v.choice; return p; }, {} as Record<MainStat, Partial<Record<TrainingLevel, number>>>),
|
||||
leveling: character.levels.reduce((p, v) => { p[v.level as Level] = v.choice; return p; }, {} as Partial<Record<Level, number>>),
|
||||
abilities: group(character.abilities.map(e => ({ ...e, value: e.value })), "ability", "value"),
|
||||
spells: character.spells.map(e => e.value),
|
||||
modifiers: group(character.modifiers, "modifier", "value"),
|
||||
choices: {},
|
||||
leveling: group(character.levels, "level", "choice"),
|
||||
abilities: group(character.abilities, "ability", "value"),
|
||||
choices: character.choices.reduce((p, v) => { p[v.id] ??= []; p[v.id]?.push(v.choice); return p; }, {} as Record<string, number[]>),
|
||||
|
||||
owner: character.owner,
|
||||
username: character.user.username,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { eq } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterAbilitiesTable, characterChoicesTable, characterLevelingTable, characterModifiersTable, characterSpellsTable, characterTable, characterTrainingTable } from '~/db/schema';
|
||||
import { characterAbilitiesTable, characterChoicesTable, characterLevelingTable, characterTable, characterTrainingTable } from '~/db/schema';
|
||||
import { CharacterValidation } from '#shared/character.util';
|
||||
import { type Ability, type MainStat } from '~/types/character';
|
||||
|
||||
|
|
@ -43,16 +43,13 @@ export default defineEventHandler(async (e) => {
|
|||
level: body.data.level,
|
||||
aspect: body.data.aspect,
|
||||
notes: body.data.notes,
|
||||
health: body.data.health,
|
||||
mana: body.data.mana,
|
||||
variables: body.data.variables,
|
||||
visibility: body.data.visibility,
|
||||
thumbnail: body.data.thumbnail,
|
||||
}).where(eq(characterTable.id, id)).run();
|
||||
|
||||
tx.delete(characterLevelingTable).where(eq(characterLevelingTable.character, id)).run();
|
||||
tx.delete(characterTrainingTable).where(eq(characterTrainingTable.character, id)).run();
|
||||
tx.delete(characterModifiersTable).where(eq(characterModifiersTable.character, id)).run();
|
||||
tx.delete(characterSpellsTable).where(eq(characterSpellsTable.character, id)).run();
|
||||
tx.delete(characterAbilitiesTable).where(eq(characterAbilitiesTable.character, id)).run();
|
||||
tx.delete(characterChoicesTable).where(eq(characterChoicesTable.character, id)).run();
|
||||
|
||||
|
|
@ -62,11 +59,6 @@ export default defineEventHandler(async (e) => {
|
|||
const training = Object.entries(body.data.training).flatMap(e => Object.entries(e[1]).filter(_e => _e[1] !== undefined).map(_e => ({ character: id, stat: e[0] as MainStat, level: parseInt(_e[0]), choice: _e[1]! })));
|
||||
if(training.length > 0) tx.insert(characterTrainingTable).values(training).run();
|
||||
|
||||
const modifiers = Object.entries(body.data.modifiers).filter(e => e[1] !== undefined).map((e) => ({ character: id, modifier: e[0] as MainStat, value: e[1] }));
|
||||
if(modifiers.length > 0) tx.insert(characterModifiersTable).values(modifiers).run();
|
||||
|
||||
if(body.data.spells.length > 0) tx.insert(characterSpellsTable).values(body.data.spells.map(e => ({ character: id, value: e }))).run();
|
||||
|
||||
const abilities = Object.entries(body.data.abilities).filter(e => e[1] !== undefined).map(e => ({ character: id, ability: e[0] as Ability, value: e[1], max: 0 }));
|
||||
if(abilities.length > 0) tx.insert(characterAbilitiesTable).values(abilities).run();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { eq } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterAbilitiesTable, characterLevelingTable, characterModifiersTable, characterSpellsTable, characterTable, characterTrainingTable } from '~/db/schema';
|
||||
import { characterAbilitiesTable, characterLevelingTable, characterTable, characterTrainingTable } from '~/db/schema';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
|
|
@ -36,8 +36,7 @@ export default defineEventHandler(async (e) => {
|
|||
level: old.level,
|
||||
aspect: old.aspect,
|
||||
notes: old.notes,
|
||||
health: old.health,
|
||||
mana: old.mana,
|
||||
variables: old.variables,
|
||||
visibility: old.visibility,
|
||||
thumbnail: old.thumbnail,
|
||||
}).returning({ id: characterTable.id }).get().id;
|
||||
|
|
@ -48,12 +47,6 @@ export default defineEventHandler(async (e) => {
|
|||
const training = tx.select().from(characterTrainingTable).where(eq(characterTrainingTable.character, parseInt(id, 10))).all();
|
||||
if(training.length > 0) tx.insert(characterTrainingTable).values(training.map(e => ({ character: _id, stat: e.stat, level: e.level, choice: e.choice }))).run();
|
||||
|
||||
const modifiers = tx.select().from(characterModifiersTable).where(eq(characterModifiersTable.character, parseInt(id, 10))).all();
|
||||
if(modifiers.length > 0) tx.insert(characterModifiersTable).values(modifiers.map(e => ({ character: _id, modifier: e.modifier, value: e.value }))).run();
|
||||
|
||||
const spells = tx.select().from(characterSpellsTable).where(eq(characterSpellsTable.character, parseInt(id, 10))).all();
|
||||
if(spells.length > 0) tx.insert(characterSpellsTable).values(spells.map(e => ({ character: _id, value: e.value }))).run();
|
||||
|
||||
const abilities = tx.select().from(characterAbilitiesTable).where(eq(characterAbilitiesTable.character, parseInt(id, 10))).all();
|
||||
if(abilities.length > 0) tx.insert(characterAbilitiesTable).values(abilities.map(e => ({ character: _id, ability: e.ability, value: e.value, max: e.max }))).run();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { and, eq, sql } from 'drizzle-orm';
|
||||
import useDatabase from '~/composables/useDatabase';
|
||||
import { characterTable } from '~/db/schema';
|
||||
import type { Character, CharacterValues } from '~/types/character';
|
||||
import type { CharacterVariables } from '~/types/character';
|
||||
|
||||
export default defineEventHandler(async (e) => {
|
||||
const id = getRouterParam(e, "id");
|
||||
|
|
@ -27,7 +27,7 @@ export default defineEventHandler(async (e) => {
|
|||
|
||||
if(character !== undefined)
|
||||
{
|
||||
return character as CharacterValues;
|
||||
return character as CharacterVariables;
|
||||
}
|
||||
|
||||
setResponseStatus(e, 404);
|
||||
|
|
|
|||
|
|
@ -2675,6 +2675,89 @@
|
|||
"damage"
|
||||
],
|
||||
"effect": "Place une anomalie visuelle à 3 cases émettant une [[6. Visibilité et lumière#Lumière intense|lumière vive]] à 9 cases. Lorsqu'un être vivant rentre en contact avec l'anomalie, il absorbe toute l'énergie magique et subit 4d8 points de dégâts magique"
|
||||
},
|
||||
{
|
||||
"id": "9jq3pkj7sgfgq6q4ovwoanig6ha8g2ic",
|
||||
"name": "Dévastation élémentaire",
|
||||
"rank": 1,
|
||||
"type": "precision",
|
||||
"cost": 8,
|
||||
"speed": "action",
|
||||
"elements": [
|
||||
"fire",
|
||||
"ice",
|
||||
"thunder"
|
||||
],
|
||||
"effect": "Faites un jet d'attaque soit la [[1. Entrainement#Dextérité|dextérité]], soit l'[[1. Entrainement#L'intelligence|intelligence]], soit la [[1. Entrainement#La psyché|psyché]]. Inflige 10+3d10 dégâts. Si vous attaquez avec la dextérité, vous infligez des dégâts de feu. Si vous attaquez avec l'intelligence, vous infligez des dégâts de glace et si vous attaquez avec la psyché, vous faites des dégâts de foudre.",
|
||||
"concentration": false,
|
||||
"tags": [
|
||||
"damage",
|
||||
"debuff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "zltvtru98sm0ad9whiw5tty0gy4q2jur",
|
||||
"name": "Soin",
|
||||
"rank": 4,
|
||||
"type": "precision",
|
||||
"cost": 8,
|
||||
"speed": "action",
|
||||
"elements": [
|
||||
"nature"
|
||||
],
|
||||
"effect": "Soigne 10+1d10 PV et guérit l'[[2. Liste des effets#Hébètement|hébètement]], le [[2. Liste des effets#Le saignement|saignement]] et les [[2. Liste des effets#L'empoisonnement|poisons]]. En soignant un personnage agonisant, vous pouvez choisir à la place de le stabiliser et de le ramener à 0 PV.",
|
||||
"concentration": false,
|
||||
"tags": [
|
||||
"support"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "bgm3c8vd2xqcwpcul1cakab89p5bfu4t",
|
||||
"name": "Contresort",
|
||||
"rank": 4,
|
||||
"type": "knowledge",
|
||||
"cost": 4,
|
||||
"speed": "reaction",
|
||||
"elements": [
|
||||
"arcana"
|
||||
],
|
||||
"effect": "Perturbe les flux magique pour interrompre une canalisation en cours que vous voyez à portée. Le lanceur de sort doit faire un jet d'attaque avec l'[[1. Entrainement#L'intelligence|intelligence]] maintenir sa canalisation. Vous pouvez augmenter le coût du sort pour augmenter les chances de réussite. La difficulté est égale à 6 - le cout du sort à interrompre + le cout du contresort.",
|
||||
"concentration": false,
|
||||
"tags": [
|
||||
"debuff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "kd84l3gujh4evsyriti4g9sk1zwbxu8d",
|
||||
"name": "Focalisation destructrice",
|
||||
"rank": 4,
|
||||
"type": "knowledge",
|
||||
"cost": 12,
|
||||
"speed": "action",
|
||||
"elements": [
|
||||
"arcana"
|
||||
],
|
||||
"effect": "Vous focalisez les énergies magiques sur vous, rendant l'utilisation de sort plus complexe pour les autres durant 1 minute. La densité d'énergie anormale vous fait subir 5 points de dégâts par tour. Toute personne à 18 cases de vous subit un malus de -4 pour se [[1. Aspect#Transformations|transformer]], à ces jets d'attaques de sort et à ces difficulté de jet de résistance de sort.",
|
||||
"concentration": true,
|
||||
"tags": [
|
||||
"debuff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "wj2rxkbw85zd9st8k2w3eezqc1naoy5g",
|
||||
"name": "Domination mentale",
|
||||
"rank": 4,
|
||||
"type": "instinct",
|
||||
"cost": 8,
|
||||
"speed": "action",
|
||||
"elements": [
|
||||
"psyche"
|
||||
],
|
||||
"effect": "La cible touchée doit réussir un [[3. Résistance aux chocs#Le jet de résistance|jet de résistance]] (d12/7 + mod. d'[[1. Entrainement#L'intelligence|intelligence]]) de [[1. Entrainement#La psyché|psyché]] ou est [[2. Liste des effets#Possédé|possédé]].",
|
||||
"concentration": true,
|
||||
"tags": [
|
||||
"debuff"
|
||||
]
|
||||
}
|
||||
],
|
||||
"aspects": [
|
||||
|
|
|
|||
|
|
@ -25,15 +25,19 @@ export const defaultCharacter: Character = {
|
|||
name: "",
|
||||
people: undefined,
|
||||
level: 1,
|
||||
health: 0,
|
||||
mana: 0,
|
||||
|
||||
training: MAIN_STATS.reduce((p, v) => { p[v] = { 0: 0 }; return p; }, {} as Record<MainStat, Partial<Record<TrainingLevel, number>>>),
|
||||
leveling: { 1: 0 },
|
||||
abilities: {},
|
||||
spells: [],
|
||||
modifiers: {},
|
||||
choices: {},
|
||||
variables: {
|
||||
health: 0,
|
||||
mana: 0,
|
||||
spells: [],
|
||||
equipment: [],
|
||||
exhaustion: 0,
|
||||
sickness: [],
|
||||
},
|
||||
|
||||
owner: -1,
|
||||
visibility: "private",
|
||||
|
|
@ -48,13 +52,7 @@ const defaultCompiledCharacter: (character: Character) => CompiledCharacter = (c
|
|||
race: character.people!,
|
||||
modifier: MAIN_STATS.reduce((p, v) => { p[v] = 0; return p; }, {} as Record<MainStat, number>),
|
||||
level: character.level,
|
||||
variables: {
|
||||
health: character.health,
|
||||
mana: character.mana,
|
||||
equipment: [],
|
||||
exhaustion: 0,
|
||||
sickness: [],
|
||||
},
|
||||
variables: character.variables,
|
||||
action: 0,
|
||||
reaction: 0,
|
||||
exhaust: 0,
|
||||
|
|
@ -121,7 +119,7 @@ const defaultCompiledCharacter: (character: Character) => CompiledCharacter = (c
|
|||
freeaction: [],
|
||||
reaction: [],
|
||||
passive: [],
|
||||
spells: character.spells,
|
||||
spells: character.variables.spells,
|
||||
},
|
||||
aspect: "",
|
||||
notes: character.notes ?? "",
|
||||
|
|
@ -174,17 +172,26 @@ export const spellTypeTexts: Record<SpellType, string> = { "instinct": "Instinct
|
|||
export const CharacterValidation = z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
people: z.number().nullable(),
|
||||
people: z.string().nullable(),
|
||||
level: z.number().min(1).max(20),
|
||||
aspect: z.number().nullable().optional(),
|
||||
notes: z.string().nullable().optional(),
|
||||
health: z.number().default(0),
|
||||
mana: z.number().default(0),
|
||||
training: z.record(z.enum(MAIN_STATS), z.record(z.enum(TRAINING_LEVELS.map(String)), z.number())),
|
||||
leveling: z.record(z.enum(LEVELS.map(String)), z.number()),
|
||||
abilities: z.record(z.enum(ABILITIES), z.number()),
|
||||
spells: z.string().array(),
|
||||
choices: z.record(z.string(), z.array(z.number())),
|
||||
variables: z.object({
|
||||
health: z.number(),
|
||||
mana: z.number(),
|
||||
exhaustion: z.number(),
|
||||
|
||||
sickness: z.array(z.object({
|
||||
id: z.string(),
|
||||
state: z.number().min(1).max(7).or(z.literal(true)),
|
||||
})),
|
||||
spells: z.array(z.string()),
|
||||
equipment: z.array(z.string()),
|
||||
}),
|
||||
owner: z.number(),
|
||||
username: z.string().optional(),
|
||||
visibility: z.enum(["public", "private"]),
|
||||
|
|
@ -332,15 +339,17 @@ export class CharacterCompiler
|
|||
protected compile(properties: string[])
|
||||
{
|
||||
const queue = properties;
|
||||
queue.forEach(property => {
|
||||
for(let i = 0; i < queue.length; i++)
|
||||
{
|
||||
const property = queue[i]!;
|
||||
const buffer = this._buffer[property];
|
||||
|
||||
if(property === "")
|
||||
return
|
||||
continue
|
||||
|
||||
if(buffer && buffer._dirty === true)
|
||||
{
|
||||
let sum = 0;
|
||||
let sum = 0, shortcut = false;
|
||||
for(let i = 0; i < buffer.list.length; i++)
|
||||
{
|
||||
if(typeof buffer.list[i]!.value === 'string') // Add or set a modifier
|
||||
|
|
@ -349,13 +358,16 @@ export class CharacterCompiler
|
|||
if(!modifier)
|
||||
{
|
||||
queue.push(property);
|
||||
return;
|
||||
shortcut = true;
|
||||
break;
|
||||
}
|
||||
else if(modifier._dirty)
|
||||
{
|
||||
//Put it back in queue since its dependencies haven't been resolved yet
|
||||
queue.push(buffer.list[i]!.value as string);
|
||||
queue.push(property);
|
||||
return;
|
||||
shortcut = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -374,6 +386,9 @@ export class CharacterCompiler
|
|||
}
|
||||
}
|
||||
|
||||
if(shortcut === true)
|
||||
continue;
|
||||
|
||||
const path = property.split("/");
|
||||
const object = path.length === 1 ? this._result : path.slice(0, -1).reduce((p, v) => { p[v] ??= {}; return p[v]; }, this._result as any);
|
||||
|
||||
|
|
@ -383,7 +398,7 @@ export class CharacterCompiler
|
|||
this._buffer[property]!.value = sum;
|
||||
this._buffer[property]!._dirty = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
export class CharacterBuilder extends CharacterCompiler
|
||||
|
|
|
|||
|
|
@ -10,8 +10,11 @@ export type SpellElement = typeof SPELL_ELEMENTS[number];
|
|||
export type Alignment = typeof ALIGNMENTS[number];
|
||||
|
||||
export type FeatureID = string;
|
||||
export type TextID = string;
|
||||
export type Resistance = string;
|
||||
|
||||
export type Dice = `${number}d${4 | 6 | 8 | 10 | 12 | 20}`;
|
||||
|
||||
export type Character = {
|
||||
id: number;
|
||||
|
||||
|
|
@ -20,16 +23,12 @@ export type Character = {
|
|||
level: number;
|
||||
aspect?: number;
|
||||
notes?: string | null;
|
||||
health: number;
|
||||
mana: number;
|
||||
|
||||
training: Record<MainStat, Partial<Record<TrainingLevel, number>>>;
|
||||
leveling: Partial<Record<Level, number>>;
|
||||
abilities: Partial<Record<Ability, number>>; //First is the ability, second is the max increment
|
||||
spells: string[]; //Spell ID
|
||||
modifiers: Partial<Record<MainStat, number>>;
|
||||
|
||||
choices: Record<string, number[]>;
|
||||
abilities: Partial<Record<Ability, number>>;
|
||||
variables: CharacterVariables;
|
||||
choices: Record<FeatureID, number[]>;
|
||||
|
||||
owner: number;
|
||||
username?: string;
|
||||
|
|
@ -40,8 +39,9 @@ export type CharacterVariables = {
|
|||
mana: number;
|
||||
exhaustion: number;
|
||||
|
||||
sickness: Array<{ id: string, progress: number | true }>;
|
||||
equipment: Array<string>;
|
||||
sickness: Array<{ id: string, state: number | true }>;
|
||||
spells: string[]; //Spell ID
|
||||
equipment: string[]; //Equipment ID
|
||||
};
|
||||
export type CharacterConfig = {
|
||||
peoples: Record<string, RaceConfig>;
|
||||
|
|
@ -51,8 +51,35 @@ export type CharacterConfig = {
|
|||
spells: SpellConfig[];
|
||||
aspects: AspectConfig[];
|
||||
features: Record<FeatureID, Feature>;
|
||||
enchantments: Record<string, { name: string, effect: FeatureEffect[] }>; //TODO
|
||||
items: Record<string, ItemConfig & { enchantments: string[] }>;
|
||||
lists: Record<string, { id: string, name: string, [key: string]: any }[]>;
|
||||
texts: Record<string, Localized>;
|
||||
texts: Record<TextID, Localized>;
|
||||
};
|
||||
export type ItemConfig = { id: string, weight?: number, price?: number, power: number } & (ArmorConfig | WeaponConfig | WondrousConfig | MundaneConfig);
|
||||
type ArmorConfig = {
|
||||
category: 'armor';
|
||||
name: string; //TODO -> TextID
|
||||
description: TextID;
|
||||
life: number;
|
||||
absorb: number;
|
||||
};
|
||||
type WeaponConfig = {
|
||||
category: 'armor';
|
||||
name: string; //TODO -> TextID
|
||||
description: TextID;
|
||||
damage: Dice;
|
||||
};
|
||||
type WondrousConfig = {
|
||||
category: 'armor';
|
||||
name: string; //TODO -> TextID
|
||||
description: TextID;
|
||||
effect: FeatureEffect[];
|
||||
};
|
||||
type MundaneConfig = {
|
||||
category: 'armor';
|
||||
name: string; //TODO -> TextID
|
||||
description: TextID;
|
||||
};
|
||||
export type SpellConfig = {
|
||||
id: string;
|
||||
|
|
|
|||
Loading…
Reference in New Issue