import * as ko from "knockout" ; import * as _ from "lodash" ; import { CombatantState } from "../../common/CombatantState" ; import { EncounterState } from "../../common/EncounterState" ; import { PersistentCharacter } from "../../common/PersistentCharacter" ; import { Spell } from "../../common/Spell" ; import { StatBlock } from "../../common/StatBlock" ; import { concatenatedStringRegex , probablyUniqueString } from "../../common/Toolbox" ; import { VariantMaximumHP } from "../Combatant/GetOrRollMaximumHP" ; import { Libraries , LibraryType } from "../Library/Libraries" ; import { Listing } from "../Library/Listing" ; import { TrackerViewModel } from "../TrackerViewModel" ; import { Metrics } from "../Utility/Metrics" ; import { EncounterCommander } from "./EncounterCommander" ; import { MoveEncounterPrompt } from "../Prompts/MoveEncounterPrompt" ; import { SaveEncounterPrompt } from "../Prompts/SaveEncounterPrompt" ; import { SpellPrompt } from "../Prompts/SpellPrompt" ; import { ConditionReferencePrompt } from "../Prompts/ConditionReferencePrompt" ; import { SavedEncounter } from "../../common/SavedEncounter" ; import { now } from "moment" ; import { Library } from "../Library/useLibrary" ; export class LibrariesCommander { private libraries : Libraries ; constructor ( private tracker , private encounterCommander ) { } public SetLibraries = ( libraries ) => { this . libraries = libraries ; } ; public ShowLibraries = ( ) => this . tracker . LibrariesVisible ( true ) ; public HideLibraries = ( ) => this . tracker . LibrariesVisible ( false ) ; public OpenLibraryManagerPane = ( startPane ) => this . tracker . LibraryManagerPane ( startPane ) ; public AddStatBlockFromListing = ( listing , hideOnAdd , variantMaximumHP ) => { listing . GetAsyncWithUpdatedId ( unsafeStatBlock => { const statBlock = { ... StatBlock . Default ( ) , ... unsafeStatBlock } ; this . tracker . Encounter . AddCombatantFromStatBlock ( statBlock , hideOnAdd , variantMaximumHP ) ; Metrics . TrackEvent ( "CombatantAdded" , { Name : statBlock . Name } ) ; this . tracker . EventLog . AddEvent ( `${ statBlock . Name } added to combat.` ) ; } ) ; return true ; } ; public CanAddPersistentCharacter = ( listing ) => { return this . tracker . Encounter . CanAddCombatant ( listing . Meta ( ) . Id ) ; } ; public AddPersistentCharacterFromListing = async ( listing , hideOnAdd ) => { const character = await listing . GetWithTemplate ( PersistentCharacter . Default ( ) ) ; this . tracker . Encounter . AddCombatantFromPersistentCharacter ( character , this . UpdatePersistentCharacter , hideOnAdd ) ; Metrics . TrackEvent ( "PersistentCharacterAdded" , { Name : character . Name } ) ; this . tracker . EventLog . AddEvent ( `Character ${ character . Name } added to combat.` ) ; } ; public UpdatePersistentCharacter = async ( persistentCharacterId , updates ) => { if ( updates . StatBlock ) { updates . Name = updates . StatBlock . Name ; updates . Path = updates . StatBlock . Path ; updates . Version = updates . StatBlock . Version ; } const currentCharacterListing = await this . libraries . PersistentCharacters . GetOrCreateListingById ( persistentCharacterId ) ; const currentCharacter = await currentCharacterListing . GetWithTemplate ( PersistentCharacter . Default ( ) ) ; const updatedCharacter = { ... currentCharacter , ... updates , LastUpdateMs : now ( ) } ; return await this . libraries . PersistentCharacters . SaveEditedListing ( currentCharacterListing , updatedCharacter ) ; } ; public CreateAndEditStatBlock = ( library ) => { const statBlock = StatBlock . Default ( ) ; const newId = probablyUniqueString ( ) ; statBlock . Name = "New Creature" ; statBlock . Id = newId ; this . tracker . EditStatBlock ( { editorTarget : "library" , statBlock , onSave : library . SaveNewListing , currentListings : library . GetAllListings ( ) } ) ; } ; public EditStatBlock = ( listing , library ) => { if ( this . tracker . TutorialVisible ( ) ) { return ; } listing . GetAsyncWithUpdatedId ( statBlock => { if ( listing . Origin === "server" ) { const statBlockWithNewId = { ... StatBlock . Default ( ) , ... statBlock , Id : probablyUniqueString ( ) } ; this . tracker . EditStatBlock ( { editorTarget : "library" , statBlock : statBlockWithNewId , onSave : library . SaveNewListing , onSaveAsCharacter : this . saveStatblockAsPersistentCharacter , currentListings : library . GetAllListings ( ) } ) ; } else { this . tracker . EditStatBlock ( { editorTarget : "library" , statBlock : { ... StatBlock . Default ( ) , ... statBlock } , onSave : s => library . SaveEditedListing ( listing , s ) , currentListings : library . GetAllListings ( ) , onDelete : this . deleteSavedStatBlock ( listing . Meta ( ) . Id ) , onSaveAsCopy : library . SaveNewListing , onSaveAsCharacter : this . saveStatblockAsPersistentCharacter } ) ; } } ) ; } ; public CreatePersistentCharacter = async ( ) => { const statBlock = StatBlock . Default ( ) ; const newId = probablyUniqueString ( ) ; statBlock . Name = "New Character" ; statBlock . Player = "player" ; statBlock . Id = newId ; const persistentCharacter = PersistentCharacter . Initialize ( statBlock ) ; return await this . libraries . PersistentCharacters . SaveNewListing ( persistentCharacter ) ; } ; public EditPersistentCharacterStatBlock ( persistentCharacterId ) { if ( this . tracker . TutorialVisible ( ) ) { return ; } this . tracker . EditPersistentCharacterStatBlock ( persistentCharacterId ) ; } public UpdatePersistentCharacterStatBlockInLibraryAndEncounter = ( persistentCharacterId , updatedStatBlock , hpDifference ? ) => { this . UpdatePersistentCharacter ( persistentCharacterId , { StatBlock : updatedStatBlock , CurrentHP : updatedStatBlock . HP . Value - ( hpDifference ?? 0 ) } ) ; this . tracker . Encounter . UpdatePersistentCharacterStatBlock ( persistentCharacterId , updatedStatBlock ) ; } ; public CreateAndEditSpell = ( ) => { const newSpell = { ... Spell . Default ( ) , Name : "New Spell" , Source : "Custom" , Id : probablyUniqueString ( ) } ; this . tracker . EditSpell ( { spell : newSpell , onSave : this . libraries . Spells . SaveNewListing , onDelete : this . libraries . Spells . DeleteListing } ) ; } ; public EditSpell = ( listing ) => { listing . GetAsyncWithUpdatedId ( spell => { this . tracker . EditSpell ( { spell : { ... Spell . Default ( ) , ... spell } , onSave : spell => this . libraries . Spells . SaveEditedListing ( listing , spell ) , onDelete : this . libraries . Spells . DeleteListing } ) ; } ) ; } ; public ReferenceSpell = ( spellListing ) => { spellListing . GetWithTemplate ( Spell . Default ( ) ) . then ( spell => { const prompt = SpellPrompt ( spell , this . tracker . StatBlockTextEnricher ) ; this . tracker . PromptQueue . Add ( prompt ) ; } ) ; return true ; } ; public GetSpellsByNameRegex = ko . pureComputed ( ( ) => concatenatedStringRegex ( this . libraries . Spells . GetAllListings ( ) . map ( s => s . Meta ( ) . Name ) . filter ( n => n . length > 2 ) ) ) ; public LoadEncounter = ( savedEncounter ) => { this . encounterCommander . LoadSavedEncounter ( savedEncounter ) ; } ; public SaveEncounter = ( ) => { const prompt = SaveEncounterPrompt ( this . tracker . Encounter . FullEncounterState ( ) , this . tracker . Encounter . TemporaryBackgroundImageUrl ( ) , this . libraries . Encounters . SaveNewListing , this . tracker . EventLog . AddEvent , _ . uniq ( this . libraries . Encounters . GetAllListings ( ) . map ( e => e . Meta ( ) . Path ) ) ) ; this . tracker . PromptQueue . Add ( prompt ) ; } ; public MoveEncounter = async ( encounterListing ) => { const folderNames = _ ( this . libraries . Encounters . GetAllListings ( ) ) . map ( e => e . Meta ( ) . Path ) . uniq ( ) . compact ( ) . value ( ) ; const encounter = await encounterListing . GetWithTemplate ( SavedEncounter . Default ( ) ) ; const prompt = MoveEncounterPrompt ( encounter , ( encounter , oldId ) => { this . libraries . Encounters . DeleteListing ( oldId ) ; this . libraries . Encounters . SaveNewListing ( encounter ) ; } , folderNames ) ; this . tracker . PromptQueue . Add ( prompt ) ; } ; public ReferenceCondition = ( conditionName ) => { const promptProps = ConditionReferencePrompt ( conditionName ) ; if ( promptProps ) { this . tracker . PromptQueue . Add ( promptProps ) ; } } ; public LaunchQuickAddPrompt = ( ) => { this . encounterCommander . QuickAddStatBlock ( ) ; } ; private deleteSavedStatBlock = ( statBlockId ) => ( ) => { this . libraries . StatBlocks . DeleteListing ( statBlockId ) ; Metrics . TrackEvent ( "StatBlockDeleted" , { Id : statBlockId } ) ; } ; private saveStatblockAsPersistentCharacter = ( statBlock ) => { const persistentCharacter = PersistentCharacter . Initialize ( statBlock ) ; this . libraries . PersistentCharacters . SaveNewListing ( persistentCharacter ) ; } ; }