From 53787b82bde939c7c01328cc6998153c31a03732 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:01:58 -0500 Subject: [PATCH 01/26] Player Vendor AI --- data/dictionaries/dictionary.CSY | 109 + data/dictionaries/dictionary.ENG | 109 + data/dictionaries/dictionary.FRE | 106 + data/dictionaries/dictionary.GER | 109 + data/dictionaries/dictionary.ITA | 109 + data/dictionaries/dictionary.POL | 109 + data/dictionaries/dictionary.PTG | 109 + data/dictionaries/dictionary.SPA | 107 + data/dictionaries/dictionary.ZRO | 109 + data/js/coreDefinitions.json | 6 + data/js/definitions.d.ts | 1 + data/js/npc/ai/playervendor.js | 2318 ++++++++++++++++++++++ data/js/server/house/playerVendorDeed.js | 42 +- docs/jsdocs.html | 4 + source/UOXJSPropertyEnums.h | 1 + source/UOXJSPropertyFuncs.cpp | 2 + source/UOXJSPropertySpecs.h | 1 + 17 files changed, 3344 insertions(+), 7 deletions(-) create mode 100644 data/js/npc/ai/playervendor.js diff --git a/data/dictionaries/dictionary.CSY b/data/dictionaries/dictionary.CSY index 4c66d7eec..275b350cc 100644 --- a/data/dictionaries/dictionary.CSY +++ b/data/dictionaries/dictionary.CSY @@ -5693,5 +5693,114 @@ 30003=Šampion padl! 30004=Byl jsi odměněn Svitkem moci! 30005=Energie svatyně ubývá, protože nejsou přítomni žádní vyzyvatelé... +// [ 40000 - 40200 ] Hráč Prodejce +40000=%s si již nemůže dovolit údržbu a byl propuštěn. +40001=Nelze vytvořit prodejní listinu. Propuštění prodejce bylo zrušeno. +40002=Vrácené předměty prodejce - banka: %i, pozemek: %i. +40003=Vrácené předměty prodejce - balíček: %i, banka: %i, pozemek: %i. +40004=Vráceno %i zlata do vašeho balíčku. +40005=Vráceno %i zlata do vaší bankovní schránky. +40006=V lokaci prodejce bylo odloženo %i zlata. +40007=Listina prodejce byla umístěna do vašeho balíčku. +40008=Listina prodejce byla umístěna do vaší bankovní schránky. +40009=Listina prodejce byla odložena do lokace prodejce. +40010=%s si nemohl dovolit údržbu a byl propuštěn. +40011=Na prodejcově lokaci bylo odloženo %i prodejních předmětů. +40012=Tento prodejce nemá žádné zlato k vyzvednutí. +40013=Vaše bankovní schránka momentálně nemůže přijímat platby od prodejce. +40014=Nelze vytvořit bankovní šek na prodejní zlato. +40015=Ve vaší bankovní schránce bylo shromážděno %i zlata jako bankovní šek. +40016=Nelze vložit prodejní zlato do vaší bankovní schránky. +40017=Ve vaší bankovní schránce bylo shromážděno %i zlata. +40018=Neplatná částka vkladu. +40019=Nemáte batoh. +40020=Ve vašem batohu není dostatek zlata. +40021=Bankovní účet prodejce je plný. +40022=Nelze odebrat zlato z vašeho batohu. Vklad zrušen. +40023=Na bankovní účet dodavatele vloženo %i zlata. +40024=Banka dodavatele dosáhla maximálního zůstatku. +40025=Bankovní účet dodavatele je prázdný. +40026=Přesunuto %i zlata z bankovního účtu dodavatele do rezervovaného zlata. +40027=Nelze vytvořit smlouvu s dodavatelem. Zrušení zrušeno. +40028=Nepracuji pro vás! +40029=Zobrazit zboží +40030=Přizpůsobit +40031=Sbírat zlato +40032=Vložit 1000 +40033=Vyprázdnit účet +40034=Zavřít +40035=Počet dnů, které mohu pracovat: +40036=Hodin, které mohu pracovat: +40037=Zlato držené pro vás: +40038=Zlato držené na mém účtu: +40039=Údržba dodavatele: +40040=Můj poplatek za období je: +40041=Hodiny účtovaného období: +40042=Celkový poplatek za položku: +40043=Neomezeně +40044=Zakázáno +40045=HLAVNÍ +40046=PŘIZPŮSOBENÍ DODAVATELEM MENU +40047=VLASY +40048=Krátké +40049=Dlouhé +40050=Culík +40051=Mohawk +40052=Páža +40053=Kudrnaté +40054=Ustupující +40055=Dva culíky +40056=Knír +40057=Krátké vousy +40058=Krátké vousy a knír +40059=Dlouhé vousy +40060=Květina +40061=Dlouhé peří +40062=Parfinále +40063=Duplík +40064=Dlouhý cop +40065=Drdoly +40066=S hroty +40067=Středně dlouhé +40068=Dlouhé vousy a Knír +40069=Kozí bradka +40070=Vandyke +40071=Odstranit ochlupení +40072=Barvení vlasů +40073=VOUSY +40074=Odstranit vousy +40075=Barvení vousů +40076=Změnit na muže +40077=Změnit na ženu +40078=Změnit na člověka +40079=Změnit na elfa +40080=Změnit oblečení +40081=ZAVŘÍT +40082=BARVA VLASŮ +40083=BARVA VOUSŮ +40084=Vlasy - %s +40085=Vousy - %s +40086=NABÍDKA OBLEČENÍ PRODEJCE +40087=Barva +40088=Odstranit +40089=KATEGORIE BAREV +40090=HOTOVO +40091=OBLEČENÍ BARVA +40092=Černá +40093=Béžová +40094=Zlatá +40095=Tmavě hnědá +40096=Červená +40097=Kaštanová +40098=Hnědá +40099=Světle blond +40100=Speciální fialová +40101=Speciální červená +40102=Speciální oranžová +40103=Speciální žlutá +40104=Speciální limetková +40105=Speciální tmavě limetková +40106=Speciální ledově modrá +40107=Speciální ledově bílá } EOF diff --git a/data/dictionaries/dictionary.ENG b/data/dictionaries/dictionary.ENG index 7c6a7ef35..4cf70287e 100644 --- a/data/dictionaries/dictionary.ENG +++ b/data/dictionaries/dictionary.ENG @@ -5693,5 +5693,114 @@ 30003=The Champion has fallen! 30004=You have been rewarded with a Scroll of Power! 30005=The shrine's energy wanes with no challengers present... +// [ 40000 - 40200 ] Player Vendor +40000=%s can no longer afford upkeep and has been dismissed. +40001=Unable to create vendor deed. Vendor dismissal aborted. +40002=Vendor items returned - bank: %i, ground: %i. +40003=Vendor items returned - pack: %i, bank: %i, ground: %i. +40004=Returned %i gold to your pack. +40005=Returned %i gold to your bank box. +40006=Dropped %i gold at vendor location. +40007=Placed vendor deed in your pack. +40008=Placed vendor deed in your bank box. +40009=Dropped vendor deed at vendor location. +40010=%s could not afford upkeep and was dismissed. +40011=Dropped %i vendor item(s) at vendor location. +40012=This vendor has no held gold to collect. +40013=Your bank box cannot receive vendor payouts right now. +40014=Unable to create a bank check for vendor gold. +40015=Collected %i gold as a bank check in your bank box. +40016=Unable to deposit vendor gold into your bank box. +40017=Collected %i gold to your bank box. +40018=Invalid deposit amount. +40019=You have no backpack. +40020=You do not have enough gold in your pack. +40021=Vendor bank account is full. +40022=Unable to remove gold from your pack. Deposit cancelled. +40023=Deposited %i gold into vendor bank account. +40024=Vendor bank reached its maximum balance. +40025=Vendor bank account is empty. +40026=Moved %i gold from vendor bank account to held gold. +40027=Unable to create vendor deed. Dismiss cancelled. +40028=I don't work for you! +40029=See goods +40030=Customize +40031=Collect Gold +40032=Deposit 1000 +40033=Flush Bank +40034=Dismiss +40035=Amount of days I can work: +40036=Hours I can work: +40037=Gold held for you: +40038=Gold held in my account: +40039=Vendor upkeep: +40040=My charge per period is: +40041=Charge period hours: +40042=Item fee total: +40043=Unlimited +40044=Disabled +40045=MAIN +40046=VENDOR CUSTOMIZATION MENU +40047=HAIR +40048=Short +40049=Long +40050=Ponytail +40051=Mohawk +40052=Pageboy +40053=Curly +40054=Receding +40055=2-Tails +40056=Mustache +40057=Short Beard +40058=Short Beard and Mustache +40059=Long Beard +40060=Flower +40061=Long Feather +40062=Mullet +40063=Topknot +40064=Long Braid +40065=Buns +40066=Spiked +40067=Mid Long +40068=Long Beard and Mustache +40069=Goatee +40070=Vandyke +40071=Remove Hair +40072=Color Hair +40073=BEARD +40074=Remove Beard +40075=Color Beard +40076=Change to Male +40077=Change to Female +40078=Change to Human +40079=Change to Elf +40080=Change Clothing +40081=CLOSE +40082=HAIR COLOR +40083=BEARD COLOR +40084=Hair - %s +40085=Beard - %s +40086=VENDOR CLOTHING MENU +40087=Color +40088=Remove +40089=COLOR CATEGORY +40090=DONE +40091=CLOTHING COLOR +40092=Black +40093=Beige +40094=Golden +40095=Dark Brown +40096=Red +40097=Auburn +40098=Brown +40099=Blonde +40100=Special Purple +40101=Special Red +40102=Special Orange +40103=Special Yellow +40104=Special Lime +40105=Special Dark Lime +40106=Special Ice Blue +40107=Special Ice White } EOF diff --git a/data/dictionaries/dictionary.FRE b/data/dictionaries/dictionary.FRE index 33f64c63b..ce9a26769 100644 --- a/data/dictionaries/dictionary.FRE +++ b/data/dictionaries/dictionary.FRE @@ -5857,5 +5857,111 @@ 30003=Le Champion est tombé ! 30004=Vous avez reçu un Parchemin de Puissance ! 30005=L'énergie du sanctuaire s'affaiblit en l'absence de challengers... +// [ 40000 - 40200 ] Vendeur du joueur +40000=%s n'a plus les moyens de s'entretenir et a été renvoyé. +40001=Impossible de créer l'acte de vendeur. Renvoi du vendeur annulé. +40002=Objets du vendeur retournés - banque : %i, terrain : %i. +40003=Objets du vendeur retournés - sac : %i, banque : %i, terrain : %i. +40004=%i pièces d'or retournées dans votre sac. +40005=%i pièces d'or retournées dans votre coffre. +40006=%i pièces d'or déposées à l'emplacement du vendeur. +40007=Acte de vendeur placé dans votre sac. +40008=Acte de vendeur placé dans votre coffre. +40009=Acte de vendeur déposé à l'emplacement du vendeur. 40010 = %s n'avait plus les moyens de payer l'entretien et a été renvoyé. +40011=%i objets déposés chez le vendeur. +40012=Ce vendeur n'a plus d'or à encaisser. +40013=Votre coffre bancaire ne peut pas recevoir les paiements des vendeurs pour le moment. +40014=Impossible de créer un chèque bancaire pour l'or du vendeur. +40015=%i pièces d'or encaissées sous forme de chèque bancaire dans votre coffre bancaire. +40016 = Impossible de déposer l'or du vendeur dans votre coffre bancaire. +40017=%i pièces d'or encaissées dans votre coffre bancaire. +40018=Montant du dépôt invalide. +40019=Vous n'avez pas de sac à dos. +40020=Vous n'avez pas assez d'or dans votre sac à dos. +40021=Le compte bancaire du vendeur est plein. 40022 = Impossible de retirer l'or de votre inventaire. Dépôt annulé. +40023=%i pièces d'or déposées sur le compte bancaire du vendeur. +40024=Solde maximum atteint sur le compte bancaire du vendeur. +40025=Compte bancaire du vendeur vide. +40026=%i pièces d'or transférées du compte bancaire du vendeur vers votre réserve. +40027=Impossible de créer l'acte de vente. Renvoi annulé. +40028=Je ne travaille pas pour vous ! 40029=Voir les articles +40030=Personnaliser +40031=Collecter de l'or +40032=Déposer 1000 +40033=Vider la banque +40034=Annuler +40035=Nombre de jours ouvrables : +40036=Heures ouvrables : +40037=Or détenu pour vous : +40038=Or détenu sur mon compte : +40039=Frais d'entretien du vendeur : +40040=Tarif par période : +40041=Heures de facturation : +40042=Total des frais par article : +40043=Illimité +40044=Désactivé +40045=PRINCIPAL +40046=PERSONNALISATION DU VENDEUR MENU +40047=CHEVEUX +40048=Courts +40049=Longs +40050=Queue de cheval +40051=Mohawk +40052=Coupe au carré +40053=Bouclés +40054=Calvé-né +40055=Deux queues de cheval +40056=Moustache +40057=Barbe courte +40058=Barbe et moustache courtes +40059=Barbe longue +40060=Fleur +40061=Longue plume +40062=Mulet +40063=Chignon haut +40064=Longue tresse +40065=Chignons +40066=Épicés +40067=Mi-longs +40068=Barbe et Moustache +40069=Bouquet +40070=Barbe Van Dyke +40071=Enlever les cheveux +40072=Colorer les cheveux +40073=Barbe +40074=Enlever la barbe +40075=Colorer la barbe +40076=Changer pour un homme +40077=Changer pour une femme +40078=Changer pour un humain +40079=Changer pour un elfe +40080=Changer de vêtements +40081=FERMER +40082=COULEUR DES CHEVEUX +40083=COULEUR DE LA BARBE +40084=Cheveux - %s +40085=Barbe - %s +40086=MENU VÊTEMENTS DU VENDEUR +40087=Colorer +40088=Enlever +40089=CATÉGORIE DE COULEUR +40090=TERMINÉ +40091=VÊTEMENTS COULEUR +40092=Noir +40093=Beige +40094=Doré +40095=Brun foncé +40096=Rouge +40097=Auburn +40098=Brun +40099=Blond +40100=Violet spécial +40101=Rouge spécial +40102=Orange spécial +40103=Jaune spécial +40104=Vert citron spécial +40105=Vert citron foncé spécial +40106=Bleu glacier spécial +40107=Blanc glacier spécial } EOF diff --git a/data/dictionaries/dictionary.GER b/data/dictionaries/dictionary.GER index 8cec50d60..b4db55b3b 100644 --- a/data/dictionaries/dictionary.GER +++ b/data/dictionaries/dictionary.GER @@ -5693,5 +5693,114 @@ 30003=Der Champion ist besiegt! 30004=Du wurdest mit einer Schriftrolle der Macht belohnt! 30005=Die Energie des Schreins schwindet, da keine Herausforderer anwesend sind... +// [ 40000 - 40200 ] Spielerhändler +40000=%s kann sich den Unterhalt nicht mehr leisten und wurde entlassen. +40001=Händlerurkunde konnte nicht erstellt werden. Händlerentlassung abgebrochen. +40002=Händlergegenstände zurückgegeben – Bank: %i, Boden: %i. +40003=Händlergegenstände zurückgegeben – Rucksack: %i, Bank: %i, Boden: %i. +40004=%i Gold wurden deinem Rucksack hinzugefügt. +40005=%i Gold wurden deiner Bank hinzugefügt. +40006=%i Gold wurden am Händlerstandort abgelegt. +40007=Händlerurkunde wurde deinem Rucksack hinzugefügt. +40008=Händlerurkunde wurde deiner Bank hinzugefügt. +40009=Händlerurkunde wurde am Händlerstandort abgelegt. +40010=%s konnte sich den Unterhalt nicht leisten und wurde entlassen. +40011=%i Händlerartikel wurden am Händlerstandort abgelegt. +40012=Dieser Händler hat kein Gold zum Einsammeln. +40013=Ihr Bankfach kann derzeit keine Händlerauszahlungen empfangen. +40014=Es konnte kein Bankscheck für Händlergold erstellt werden. +40015=%i Gold wurden als Bankscheck in Ihrem Bankfach eingesammelt. +40016=Es konnte kein Händlergold in Ihr Bankfach eingezahlt werden. +40017=%i Gold wurden in Ihrem Bankfach eingesammelt. +40018=Ungültiger Einzahlungsbetrag. +40019=Sie haben keinen Rucksack. +40020=Sie haben nicht genügend Gold in Ihrem Rucksack. +40021=Das Händlerbankkonto ist voll. +40022=Gold konnte nicht aus Ihrem Paket entnommen werden. Einzahlung abgebrochen. +40023=%i Gold wurden auf das Händlerbankkonto eingezahlt. +40024=Das Händlerbankkonto hat seinen maximalen Kontostand erreicht. +40025=Das Händlerbankkonto ist leer. +40026=%i Gold wurden vom Händlerbankkonto auf das gehaltene Goldkonto übertragen. +40027=Händlervertrag konnte nicht erstellt werden. Kündigung abgebrochen. +40028=Ich arbeite nicht für Sie! +40029=Waren ansehen +40030=Anpassen +40031=Gold sammeln +40032=1000 einzahlen +40033=Bank leeren +40034=Schließen +40035=Anzahl der Tage, an denen ich arbeiten kann: +40036=Stunden, die ich arbeiten kann: +40037=Für Sie reserviertes Gold: +40038=Gold auf meinem Konto: +40039=Händlerunterhalt: +40040=Meine Gebühr pro Periode: +40041=Stunden der Abrechnungsperiode: +40042=Gesamtgebühr für Artikel: +40043=Unbegrenzt +40044=Deaktiviert +40045=HAUPT +40046=HÄNDLERANPASSUNG MENÜ +40047=HAAR +40048=Kurz +40049=Lang +40050=Pferdeschwanz +40051=Irokesenschnitt +40052=Pageboy +40053=Lockig +40054=Rückgang +40055=Zwei Zöpfe +40056=Schnurrbart +40057=Kurzer Bart +40058=Kurzer Bart und Schnurrbart +40059=Langer Bart +40060=Blumenfrisur +40061=Lange Federfrisur +40062=Vokuhila +40063=Dutt +40064=Langer Zopf +40065=Dutt +40066=Stachelhaarfrisur +40067=Mittellang +40068=Langer Bart und Schnurrbart Schnurrbart +40069=Ziegenbart +40070=Vandyke +40071=Haare entfernen +40072=Haare färben +40073=BART +40074=Bart entfernen +40075=Bart färben +40076=Zu Mann wechseln +40077=Zu Frau wechseln +40078=Zu Mensch wechseln +40079=Zu Elf wechseln +40080=Kleidung ändern +40081=SCHLIESSEN +40082=HAARFARBE +40083=BARTFARBE +40084=Haare - %s +40085=Bart - %s +40086=KLEIDUNGSMENÜ DES HÄNDLERS +40087=Farbe +40088=Entfernen +40089=FARBKATEGORIE +40090=FERTIG +40091=KLEIDUNG FARBE +40092=Schwarz +40093=Beige +40094=Golden +40095=Dunkelbraun +40096=Rot +40097=Kastanienbraun +40098=Braun +40099=Blond +40100=Speziallila +40101=Spezialrot +40102=Spezialorange +40103=Spezialgelb +40104=Speziallimette +40105=Spezialdunkellimette +40106=Spezialeisblau +40107=Spezialeisweiß } EOF diff --git a/data/dictionaries/dictionary.ITA b/data/dictionaries/dictionary.ITA index fded04dd5..49d1b068e 100644 --- a/data/dictionaries/dictionary.ITA +++ b/data/dictionaries/dictionary.ITA @@ -5693,5 +5693,114 @@ 30003=Il Campione è stato sconfitto! 30004=Hai ricevuto in ricompensa una Pergamena del Potere! 30005=L'energia del santuario si affievolisce in assenza di sfidanti... +// [ 40000 - 40200 ] Venditore +40000=%s non può più permettersi il mantenimento ed è stato licenziato. +40001=Impossibile creare l'atto di vendita. Licenziamento del venditore annullato. +40002=Oggetti del venditore restituiti - banca: %i, terreno: %i. +40003=Oggetti del venditore restituiti - pacco: %i, banca: %i, terreno: %i. +40004=Restituito %i oro nel tuo pacco. +40005=Restituito %i oro nella tua banca. +40006=Lasciato %i oro nella posizione del venditore. +40007=Atto di vendita inserito nel tuo pacco. +40008=Atto di vendita inserito nella tua banca. +40009=Atto di vendita inserito nella posizione del venditore. +40010=%s non poteva permettersi il mantenimento ed è stato licenziato. +40011=Ha lasciato %i oggetti del venditore nella posizione del venditore. +40012=Questo venditore non ha oro da riscuotere. +40013=La tua cassetta della posta non può ricevere pagamenti dal venditore in questo momento. +40014=Impossibile creare un assegno bancario per l'oro del venditore. +40015=Hai raccolto %i oro come assegno bancario nella tua cassetta della posta. +40016=Impossibile depositare l'oro del venditore nella tua cassetta della posta. +40017=Hai raccolto %i oro nella tua cassetta della posta. +40018=Importo del deposito non valido. +40019=Non hai uno zaino. +40020=Non hai abbastanza oro nel tuo zaino. +40021=Il conto bancario del venditore è pieno. +40022=Impossibile rimuovere l'oro dal tuo pacchetto. Deposito annullato. +40023=Depositato %i oro sul conto bancario del venditore. +40024=Il conto bancario del venditore ha raggiunto il saldo massimo. +40025=Il conto bancario del venditore è vuoto. +40026=Spostato %i oro dal conto bancario del venditore all'oro trattenuto. +40027=Impossibile creare l'atto di vendita del venditore. Ignora annullato. +40028=Non lavoro per te! +40029=Vedi beni +40030=Personalizza +40031=Raccogli oro +40032=Deposita 1000 +40033=Svuota banca +40034=Ignora +40035=Numero di giorni in cui posso lavorare: +40036=Ore in cui posso lavorare: +40037=Oro trattenuto per te: +40038=Oro trattenuto sul mio conto: +40039=Mantenimento venditore: +40040=La mia tariffa per periodo è: +40041=Ore del periodo di addebito: +40042=Totale commissione articolo: +40043=Illimitato +40044=Disabilitato +40045=PRINCIPALE +40046=PERSONALIZZAZIONE VENDITORE MENU +40047=CAPELLI +40048=Corti +40049=Lunghi +40050=Coda di cavallo +40051=Cresta +40052=Paggetto +40053=Ricci +40054=Sfuggenti +40055=2 code +40056=Baffi +40057=Barba corta +40058=Barba corta e baffi +40059=Barba lunga +40060=Fiore +40061=Piuma lunga +40062=Mullet +40063=Ciondolo +40064=Treccia lunga +40065=Chignon +40066=A punta +40067=Medio lungo +40068=Barba lunga e Baffi +40069=Pizzetto +40070=Vandyke +40071=Rimuovi peli +40072=Colora capelli +40073=BARBA +40074=Rimuovi barba +40075=Colora barba +40076=Cambia in maschile +40077=Cambia in femminile +40078=Cambia in umano +40079=Cambia in elfo +40080=Cambia abbigliamento +40081=CHIUDI +40082=COLORE CAPELLI +40083=COLORE BARBA +40084=Capelli - %s +40085=Barba - %s +40086=MENU ABBIGLIAMENTO VENDITORE +40087=Colore +40088=Rimuovi +40089=CATEGORIA COLORE +40090=FATTO +40091=ABBIGLIAMENTO COLORE +40092=Nero +40093=Beige +40094=Oro +40095=Marrone scuro +40096=Rosso +40097=Castano ramato +40098=Marrone +40099=Biondo +40100=Viola speciale +40101=Rosso speciale +40102=Arancione speciale +40103=Giallo speciale +40104=Lime speciale +40105=Lime scuro speciale +40106=Blu ghiaccio speciale +40107=Bianco ghiaccio speciale } EOF diff --git a/data/dictionaries/dictionary.POL b/data/dictionaries/dictionary.POL index 50af51c7c..a02be3ca8 100644 --- a/data/dictionaries/dictionary.POL +++ b/data/dictionaries/dictionary.POL @@ -5693,5 +5693,114 @@ 30003=Mistrz został pokonany! 30004=Otrzymałeś Zwoj mocy! 30005=Energia kapliczki słabnie z powodu braku pretendentów... +// [ 40000 - 40200 ] Gracz Sprzedawca +40000=%s nie jest już w stanie utrzymać się i został zwolniony. +40001=Nie można utworzyć aktu własności sprzedawcy. Zwolnienie sprzedawcy zostało przerwane. +40002=Zwrócono przedmioty sprzedawcy - bank: %i, ziemia: %i. +40003=Zwrócono przedmioty sprzedawcy - paczka: %i, bank: %i, ziemia: %i. +40004=Zwrócono %i złota do twojego pakietu. +40005=Zwrócono %i złota do twojego skarbca. +40006=Upuszczono %i złota u sprzedawcy. +40007=Umieszczono akt własności sprzedawcy w twoim pakiecie. +40008=Umieszczono akt własności sprzedawcy w twoim skarbcu. +40009=Upuszczono akt własności sprzedawcy u sprzedawcy. +40010=%s nie mógł sobie pozwolić na utrzymanie i został zwolniony. +40011=Upuścił %i przedmiotów u sprzedawcy. +40012=Ten sprzedawca nie ma złota do odebrania. +40013=Twoja skrytka bankowa nie może obecnie przyjmować wypłat od sprzedawcy. +40014=Nie można utworzyć czeku bankowego na złoto sprzedawcy. +40015=Zebrano %i złota jako czek bankowy w Twojej skrytce bankowej. +40016=Nie można wpłacić złota sprzedawcy do Twojej skrytki bankowej. +40017=Zebrano %i złota do Twojej skrytki bankowej. +40018=Nieprawidłowa kwota wpłaty. +40019=Nie masz plecaka. +40020=Nie masz wystarczającej ilości złota w plecaku. +40021=Konto bankowe sprzedawcy jest pełne. +40022=Nie można usunąć złota z paczki. Depozyt anulowany. +40023=Wpłacono %i złota na konto bankowe sprzedawcy. +40024=Saldo banku sprzedawcy osiągnęło maksymalne saldo. +40025=Konto bankowe sprzedawcy jest puste. +40026=Przeniesiono %i złota z konta bankowego sprzedawcy do posiadanego złota. +40027=Nie można utworzyć aktu własności sprzedawcy. Anulowano anulowanie. +40028=Nie pracuję dla ciebie! +40029=Zobacz towary +40030=Dostosuj +40031=Odbierz złoto +40032=Wpłać 1000 +40033=Opróżnij bank +40034=Odrzuć +40035=Liczba dni, w których mogę pracować: +40036=Godziny, w których mogę pracować: +40037=Złoto przechowywane dla Ciebie: +40038=Złoto przechowywane na moim koncie: +40039=Utrzymanie przez sprzedawcę: +40040=Moja opłata za okres wynosi: +40041=Godziny okresu rozliczeniowego: +40042=Całkowita opłata za przedmiot: +40043=Nieograniczony +40044=Wyłączony +40045=GŁÓWNY +40046=DOSTOSOWANIE PRZEZ SPRZEDAWCĘ MENU +40047=WŁOSY +40048=Krótkie +40049=Długie +40050=Kucyk +40051=Irokez +40052=Pazik +40053=Kręcone +40054=Cofające się +40055=2 ogony +40056=Wąsy +40057=Krótka broda +40058=Krótka broda i wąsy +40059=Długa broda +40060=Kwiat +40061=Długie pióro +40062=Mullet +40063=Kok +40064=Długi warkocz +40065=Koki +40066=Z kolcami +40067=Średniej długości +40068=Długa broda i Wąsy +40069=Kozia bródka +40070=Vandyke +40071=Usuń włosy +40072=Kolor włosów +40073=BRODA +40074=Usuń brodę +40075=Kolor brody +40076=Zmień na mężczyznę +40077=Zmień na kobietę +40078=Zmień na człowieka +40079=Zmień na elfa +40080=Zmień ubranie +40081=ZAMKNIJ +40082=KOLOR WŁOSÓW +40083=KOLOR BRODY +40084=Włosy - %s +40085=Broda - %s +40086=MENU ODZIEŻY U DOSTAWCY +40087=Kolor +40088=Usuń +40089=KOLOR KATEGORIA +40090=GOTOWE +40091=KOLOR ODZIEŻY +40092=Czarny +40093=Beżowy +40094=Złoty +40095=Ciemnobrązowy +40096=Czerwony +40097=Kasztanowy +40098=Brązowy +40099=Blond +40100=Specjalny fioletowy +40101=Specjalny czerwony +40102=Specjalny pomarańczowy +40103=Specjalny żółty +40104=Specjalny limonkowy +40105=Specjalny ciemnolimonkowy +40106=Specjalny lodowoniebieski +40107=Specjalny lodowobiały } EOF diff --git a/data/dictionaries/dictionary.PTG b/data/dictionaries/dictionary.PTG index b6987987f..05a177fee 100644 --- a/data/dictionaries/dictionary.PTG +++ b/data/dictionaries/dictionary.PTG @@ -5693,5 +5693,114 @@ 30003=O Campeão caiu! 30004=Foste recompensado com um Pergaminho de Poder! 30005=A energia do santuário diminui sem desafiantes presentes... +// [ 40000 - 40200 ] Vendedor do Jogador +40000=%s já não pode suportar a manutenção e foi dispensado. +40001=Não foi possível criar a escritura do vendedor. Dispensa do vendedor abortada. +40002=Artigos do vendedor devolvidos - banco: %i, chão: %i. +40003=Artigos do vendedor devolvidos - mochila: %i, banco: %i, chão: %i. +40004=Devolvido %i de ouro para a sua mochila. +40005=Devolvido %i de ouro para o seu cofre no banco. +40006=Depositado %i de ouro no local do vendedor. +40007=Escritura do vendedor colocada na sua mochila. +40008=Escritura do vendedor colocada no seu cofre no banco. +40009=Escritura do vendedor depositada no local do vendedor. +40010=%s não tinha condições para suportar os custos de manutenção e foi despedido. +40011=Deixou %i artigo(s) do vendedor no local do vendedor. +40012=Este vendedor não tem ouro para recolher. +40013=O seu ATM não pode receber pagamentos de vendedores no momento. +40014=Não foi possível criar um cheque bancário para o ouro do vendedor. +40015=Coletou %i de ouro como um cheque bancário no seu ATM. +40016=Não foi possível depositar o ouro do vendedor no seu ATM. +40017=Coletou %i de ouro no seu ATM. +40018=Valor de depósito inválido. +40019=Não tem mochila. +40020=Não tem ouro suficiente na sua mochila. +40021=A conta bancária do vendedor está cheia. +40022=Não foi possível remover o ouro do seu pacote. Depósito cancelado. +40023=Depositado %i de ouro na conta bancária do fornecedor. +40024=O saldo bancário do fornecedor atingiu o máximo permitido. +40025=A conta bancária do fornecedor está vazia. +40026=Movido %i de ouro da conta bancária do fornecedor para o ouro retido. +40027=Não foi possível criar a escritura do fornecedor. Dispensa cancelada. +40028=Eu não trabalho para ti! +40029=Ver mercadorias +40030=Personalizar +40031=Coletar Ouro +40032=Depositar 1000 +40033=Levantar dinheiro +40034=Dispensar +40035=Nº de dias que posso trabalhar: +40036=Horas em que posso trabalhar: +40037=Ouro reservado para si: +40038=Ouro mantido na minha conta: +40039=Manutenção do fornecedor: +40040=A minha faturação por período é: +40041=Horas do período de cobrança: +40042=Total da taxa do artigo: +40043=Ilimitado +40044=Desativado +40045=PRINCIPAL +40046=PERSONALIZAÇÃO DO FORNECEDOR MENU +40047=CABELO +40048=Curto +40049=Longo +40050=Rabo de cavalo +40051=Moicano +40052=Cabelo chanel +40053=Cacheado +40054=Cabelo recuado +40055=Duas tranças +40056=Bigode +40057=Barba curta +40058=Barba e bigode curtos +40059=Barba comprida +40060=Flor +40061=Pena longa +40062=Mullet +40063=Coque alto +40064=Trança longa +40065=Coques +40066=Espetado +40067=Comprimento médio +40068=Barba comprida e Bigode +40069=Cavahaque +40070=Vandyke +40071=Remover Cabelo +40072=Colorir Cabelo +40073=Barba +40074=Remover Barba +40075=Colorir Barba +40076=Mudar para Masculino +40077=Mudar para Feminino +40078=Mudar para Humano +40079=Mudar para Elfo +40080=Mudar Roupa +40081=FECHAR +40082=COR DO CABELO +40083=COR DA BARBA +40084=Cabelo - %s +40085=Barba - %s +40086=MENU DE VESTUÁRIO DO FORNECEDOR +40087=Colorir +40088=Remover +40089=COR CATEGORIA +40090=CONCLUÍDO +40091=COR DA ROUPA +40092=Preto +40093=Bege +40094=Dourado +40095=Castanho Escuro +40096=Vermelho +40097=Ruivo +40098=Castanho +40099=Loiro +40100=Roxo Especial +40101=Vermelho Especial +40102=Laranja Especial +40103=Amarelo Especial +40104=Verde Limão Especial +40105=Verde Limão Escuro Especial +40106=Azul Gelo Especial +40107=Branco Gelo Especial } EOF diff --git a/data/dictionaries/dictionary.SPA b/data/dictionaries/dictionary.SPA index 34f5560ab..cbeee4596 100644 --- a/data/dictionaries/dictionary.SPA +++ b/data/dictionaries/dictionary.SPA @@ -5693,5 +5693,112 @@ 30003=¡El Campeón ha caído! 30004=¡Has sido recompensado con un Pergamino de Poder! 30005=La energía del santuario disminuye al no haber desafiantes presentes... +// [ 40000 - 40200 ] Vendedor Jugador +40000=%s ya no puede costear el mantenimiento y ha sido despedido. +40001=No se pudo crear la escritura de vendedor. Se canceló la destitución del vendedor. +40002=Objetos de vendedor devueltos - banco: %i, suelo: %i. +40003=Objetos de vendedor devueltos - paquete: %i, banco: %i, suelo: %i. +40004=Se devolvieron %i de oro a tu paquete. +40005=Se devolvieron %i de oro a tu caja del banco. +40006=Se dejó %i de oro en la ubicación del vendedor. +40007=Se colocó la escritura de vendedor en tu paquete. +40008=Se colocó la escritura de vendedor en tu caja del banco. +40009=Se dejó la escritura de vendedor en la ubicación del vendedor. +40010=%s no pudo costear el mantenimiento y fue despedido. +40011=Se dejaron %i objetos de vendedor en la ubicación del vendedor. +40012=Este vendedor no tiene oro disponible para recolectar. +40013=Tu caja bancaria no puede recibir pagos de vendedor en este momento. +40014=No se puede crear un cheque bancario para el oro del vendedor. +40015=Se recaudó %i de oro como cheque bancario en tu caja bancaria. +40016=No se puede depositar oro de vendedor en tu caja bancaria. +40017=Se recaudó %i de oro en tu caja bancaria. +40018=Importe de depósito no válido. +40019=No tienes mochila. +40020=No tienes suficiente oro en tu mochila. +40021=La cuenta bancaria del vendedor está llena. 40022=No se pudo retirar oro de tu paquete. Depósito cancelado. +40023=Se depositó %i de oro en la cuenta bancaria del vendedor. +40024=El banco del vendedor alcanzó su saldo máximo. +40025=La cuenta bancaria del vendedor está vacía. +40026=Se transfirió %i de oro de la cuenta bancaria del vendedor al oro retenido. +40027=No se pudo crear la escritura del vendedor. Descartar cancelado. +40028=¡No trabajo para ti! 40029=Ver artículos +40030=Personalizar +40031=Recoger oro +40032=Depositar 1000 +40033=Fluir banco +40034=Descartar +40035=Días que puedo trabajar: +40036=Horas que puedo trabajar: +40037=Oro guardado para ti: +40038=Oro guardado en mi cuenta: +40039=Mantenimiento del vendedor: +40040=Mi cargo por período es: +40041=Horas del período de cobro: +40042=Total del cargo por artículo: +40043=Ilimitado +40044=Desactivado +40045=PRINCIPAL +40046=PERSONALIZACIÓN DEL VENDEDOR MENÚ +40047=CABELLO +40048=Corto +40049=Largo +40050=Cola de caballo +40051=Mohicano +40052=Paje +40053=Rizado +40054=Con entradas +40055=Dos colas +40056=Bigote +40057=Barba corta +40058=Barba corta y bigote +40059=Barba larga +40060=Flor +40061=Pluma larga +40062=Mullet +40063=Crochet +40064=Trenza larga +40065=Moños +40066=Puntos +40067=Media melena +40068=Barba larga y bigote Bigote +40069=Perilla +40070=Vandyke +40071=Quitar pelo +40072=Color de pelo +40073=BARBA +40074=Quitar barba +40075=Color de barba +40076=Cambiar a masculino +40077=Cambiar a femenino +40078=Cambiar a humano +40079=Cambiar a elfo +40080=Cambiar ropa +40081=CERRAR +40082=COLOR DE PELO +40083=COLOR DE BARBA +40084=Cabello - %s +40085=Barba - %s +40086=MENÚ DE ROPA DEL VENDEDOR +40087=Color +40088=Quitar +40089=COLOR CATEGORÍA +40090=HECHO +40091=COLOR DE LA ROPA +40092=Negro +40093=Beige +40094=Dorado +40095=Castaño oscuro +40096=Rojo +40097=Castaño rojizo +40098=Castaño +40099=Rubio +40100=Morado especial +40101=Rojo especial +40102=Naranja especial +40103=Amarillo especial +40104=Lima especial +40105=Lima oscuro especial +40106=Azul hielo especial +40107=Blanco hielo especial } EOF diff --git a/data/dictionaries/dictionary.ZRO b/data/dictionaries/dictionary.ZRO index a49b7576a..08b00afde 100644 --- a/data/dictionaries/dictionary.ZRO +++ b/data/dictionaries/dictionary.ZRO @@ -5693,5 +5693,114 @@ 30003=The Champion has fallen! 30004=You have been rewarded with a Scroll of Power! 30005=The shrine's energy wanes with no challengers present... +// [ 40000 - 40200 ] Player Vendor +40000=%s can no longer afford upkeep and has been dismissed. +40001=Unable to create vendor deed. Vendor dismissal aborted. +40002=Vendor items returned - bank: %i, ground: %i. +40003=Vendor items returned - pack: %i, bank: %i, ground: %i. +40004=Returned %i gold to your pack. +40005=Returned %i gold to your bank box. +40006=Dropped %i gold at vendor location. +40007=Placed vendor deed in your pack. +40008=Placed vendor deed in your bank box. +40009=Dropped vendor deed at vendor location. +40010=%s could not afford upkeep and was dismissed. +40011=Dropped %i vendor item(s) at vendor location. +40012=This vendor has no held gold to collect. +40013=Your bank box cannot receive vendor payouts right now. +40014=Unable to create a bank check for vendor gold. +40015=Collected %i gold as a bank check in your bank box. +40016=Unable to deposit vendor gold into your bank box. +40017=Collected %i gold to your bank box. +40018=Invalid deposit amount. +40019=You have no backpack. +40020=You do not have enough gold in your pack. +40021=Vendor bank account is full. +40022=Unable to remove gold from your pack. Deposit cancelled. +40023=Deposited %i gold into vendor bank account. +40024=Vendor bank reached its maximum balance. +40025=Vendor bank account is empty. +40026=Moved %i gold from vendor bank account to held gold. +40027=Unable to create vendor deed. Dismiss cancelled. +40028=I don't work for you! +40029=See goods +40030=Customize +40031=Collect Gold +40032=Deposit 1000 +40033=Flush Bank +40034=Dismiss +40035=Amount of days I can work: +40036=Hours I can work: +40037=Gold held for you: +40038=Gold held in my account: +40039=Vendor upkeep: +40040=My charge per period is: +40041=Charge period hours: +40042=Item fee total: +40043=Unlimited +40044=Disabled +40045=MAIN +40046=VENDOR CUSTOMIZATION MENU +40047=HAIR +40048=Short +40049=Long +40050=Ponytail +40051=Mohawk +40052=Pageboy +40053=Curly +40054=Receding +40055=2-Tails +40056=Mustache +40057=Short Beard +40058=Short Beard and Mustache +40059=Long Beard +40060=Flower +40061=Long Feather +40062=Mullet +40063=Topknot +40064=Long Braid +40065=Buns +40066=Spiked +40067=Mid Long +40068=Long Beard and Mustache +40069=Goatee +40070=Vandyke +40071=Remove Hair +40072=Color Hair +40073=BEARD +40074=Remove Beard +40075=Color Beard +40076=Change to Male +40077=Change to Female +40078=Change to Human +40079=Change to Elf +40080=Change Clothing +40081=CLOSE +40082=HAIR COLOR +40083=BEARD COLOR +40084=Hair - %s +40085=Beard - %s +40086=VENDOR CLOTHING MENU +40087=Color +40088=Remove +40089=COLOR CATEGORY +40090=DONE +40091=CLOTHING COLOR +40092=Black +40093=Beige +40094=Golden +40095=Dark Brown +40096=Red +40097=Auburn +40098=Brown +40099=Blonde +40100=Special Purple +40101=Special Red +40102=Special Orange +40103=Special Yellow +40104=Special Lime +40105=Special Dark Lime +40106=Special Ice Blue +40107=Special Ice White } EOF diff --git a/data/js/coreDefinitions.json b/data/js/coreDefinitions.json index 1e4710eb2..a689738aa 100644 --- a/data/js/coreDefinitions.json +++ b/data/js/coreDefinitions.json @@ -4248,6 +4248,12 @@ "cppType": "JSPROP_ENUMANDPERM", "type": "number" }, + { + "name": "vendorGoldHeld", + "cppName": "CCP_VENDORGOLDHELD", + "cppType": "JSPROP_ENUMANDPERM", + "type": "number" + }, { "name": "willhunger", "cppName": "CCP_HUNGERSTATUS", diff --git a/data/js/definitions.d.ts b/data/js/definitions.d.ts index ef7ee4836..3e06cb1dd 100644 --- a/data/js/definitions.d.ts +++ b/data/js/definitions.d.ts @@ -357,6 +357,7 @@ declare global { trainer: boolean; vulnerable: boolean; wandertype: number; + vendorGoldHeld: number; willhunger: boolean; willthirst: boolean; AddAggressorFlag( target: Character ): void; diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js new file mode 100644 index 000000000..e6e378a09 --- /dev/null +++ b/data/js/npc/ai/playervendor.js @@ -0,0 +1,2318 @@ +/// +// @ts-check +// Version: 1.1.5 + +// Max amount of money the vendor can hold in the bank. +// Held gold is not included in this limit, but will +// be used first to pay upkeep before bank funds are used. +var vendorMaxFunds = 1000000; + +// If true, returned vendor belongings skip player backpack entirely. +// Items, gold and vendor deed will try bank box first, then drop at vendor location. +// If false, belongings try backpack first, then bank box, then ground. +var onlyReturnToBank = true; + +// Vendor upkeep settings +var vendorChargesEnabled = true; // Master toggle for vendor upkeep charges +var vendorBaseCharge = 60; // Flat fee per charge period +var vendorChargeHours = 24; // Charge every X real hours +var vendorUseItemFees = true; // Add item-based fee from listed item prices +var vendorItemFeeDivisor = 500; // 3 gold per 500 worth of one item +var vendorItemFeeAmount = 3; // Fee added per divisor step + +var layerOneHand = 0x01; +var layerTwoHand = 0x02; +var layerShoes = 0x03; +var layerPants = 0x04; +var layerShirt = 0x05; +var layerHelm = 0x06; +var layerGloves = 0x07; +var layerRing = 0x08; +var layerNeck = 0x0A; +var layerHair = 0x0B; +var layerWaist = 0x0C; +var layerInnerTorso = 0x0D; +var layerBracelet = 0x0E; +var layerBeard = 0x10; +var layerMiddleTorso = 0x11; +var layerEarrings = 0x12; +var layerArms = 0x13; +var layerCloak = 0x14; +var layerOuterTorso = 0x16; +var layerOuterLegs = 0x17; + +/** @constructor @param {string|null} name @param {number[] } hues @param {number|null} dictID */ +function VendorHueCategory( name, hues, dictID ) +{ + this.name = name; + this.hues = hues; + this.dictID = dictID; +} + +/** @param {VendorHueCategory} entry @param {Socket|null} socket @returns {string} */ +function GetVendorHueCategoryName( entry, socket ) +{ + if( entry.dictID && socket ) + return GetDictionaryEntry( entry.dictID, socket.language ); + + return entry.name || ""; +} + +var vendorHairHueCategories = [ + new VendorHueCategory( null, [ 0x044E, 0x044F, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454 ], 40092 ), // Black + new VendorHueCategory( null, [ 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C ], 40093 ), // Beige + new VendorHueCategory( null, [ 0x045D, 0x045E, 0x045F, 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468, 0x0469, 0x046A, 0x046B, 0x046C ], 40094 ), // Golden + new VendorHueCategory( null, [ 0x046D, 0x046E, 0x046F, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478, 0x0479, 0x047A, 0x047B, 0x047C ], 40095 ), // Dark Brown + new VendorHueCategory( null, [ 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7, 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF, 0x04C0 ], 40096 ), // Red + new VendorHueCategory( null, [ 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC ], 40097 ), // Auburn + new VendorHueCategory( null, [ 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0657, 0x0658, 0x0659, 0x065A, 0x065B, 0x065C, 0x065D, 0x065E, 0x065F, 0x0660 ], 40098 ), // Brown + new VendorHueCategory( null, [ 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, 0x0961, 0x0962, 0x0963, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968 ], 40099 ), // Blonde + new VendorHueCategory( null, [ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ], 40100 ), // Special Purple + new VendorHueCategory( null, [ 32, 33, 34, 35, 36, 37 ], 40101 ), // Special Red + new VendorHueCategory( null, [ 38, 39, 40, 41, 42, 43, 44, 45, 46 ], 40102 ), // Special Orange + new VendorHueCategory( null, [ 54, 55, 56, 57 ], 40103 ), // Special Yellow + new VendorHueCategory( null, [ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 ], 40104 ), // Special Lime + new VendorHueCategory( null, [ 81, 82, 83 ], 40105 ), // Special Dark Lime + new VendorHueCategory( null, [ 89, 90, 91 ], 40106 ), // Special Ice Blue + new VendorHueCategory( null, [ 1153, 1154, 1155 ], 40107 ) // Special Ice White +]; + +/** @constructor @param {number} itemID @param {string} name */ +function HairOrBeard( itemID, name, dictID ) +{ + this.itemID = itemID; + this.name = name; + this.dictID = dictID; +} + +/** @param {HairOrBeard} entry @param {Socket} socket @returns {string} */ +function GetHairOrBeardName( entry, socket ) +{ + if( entry.dictID ) + return GetDictionaryEntry( entry.dictID, socket.language ); + + return entry.name || ""; +} + +var femaleElfHairStyles = [ + new HairOrBeard( 0x2FCC, null, 40060 ), // Flower + new HairOrBeard( 0x2FC0, null, 40061 ), // Long Feather + new HairOrBeard( 0x2FC1, null, 40048 ), // Short + new HairOrBeard( 0x2FC2, null, 40062 ), // Mullet + new HairOrBeard( 0x2FCE, null, 40063 ), // Topknot + new HairOrBeard( 0x2FCF, null, 40064 ), // Long Braid + new HairOrBeard( 0x2FD0, null, 40065 ), // Buns + new HairOrBeard( 0x2FD1, null, 40066 ) // Spiked +]; + +var maleElfHairStyles = [ + new HairOrBeard( 0x2FBF, null, 40067 ), // Mid Long + new HairOrBeard( 0x2FC0, null, 40061 ), // Long Feather + new HairOrBeard( 0x2FC1, null, 40048 ), // Short + new HairOrBeard( 0x2FC2, null, 40062 ), // Mullet + new HairOrBeard( 0x2FCE, null, 40063 ), // Topknot + new HairOrBeard( 0x2FCF, null, 40064 ), // Long Braid + new HairOrBeard( 0x2FCD, null, 40049 ), // Long + new HairOrBeard( 0x2FD1, null, 40066 ) // Spiked +]; + +var humanHairStyles = [ + new HairOrBeard( 0x203B, null, 40048 ), // Short + new HairOrBeard( 0x203C, null, 40049 ), // Long + new HairOrBeard( 0x203D, null, 40050 ), // Ponytail + new HairOrBeard( 0x2044, null, 40051 ), // Mohawk + new HairOrBeard( 0x2045, null, 40052 ), // Pageboy + new HairOrBeard( 0x204A, null, 40063 ), // Topknot + new HairOrBeard( 0x2047, null, 40053 ), // Curly + new HairOrBeard( 0x2048, null, 40054 ), // Receding + new HairOrBeard( 0x2049, null, 40055 ) // 2-Tails +]; + +var humanBeardStyles = [ + new HairOrBeard( 0x2041, null, 40056 ), // Mustache + new HairOrBeard( 0x203F, null, 40057 ), // Short Beard + new HairOrBeard( 0x204B, null, 40058 ), // Short Beard and Mustache + new HairOrBeard( 0x203E, null, 40059 ), // Long Beard + new HairOrBeard( 0x204C, null, 40068 ), // Long Beard and Mustache + new HairOrBeard( 0x2040, null, 40069 ), // Goatee + new HairOrBeard( 0x204D, null, 40070 ) // Vandyke +]; + +/** @constructor @param {number} itemID @param {string} name */ +function VendorClothingEntry( itemID, name ) +{ + this.itemID = itemID; + this.name = name; +} + +/** @constructor @param {number} layer @param {string} name @param {boolean} canDye @param {VendorClothingEntry[]} entries @param {boolean=} compactLayout*/ +function VendorClothingCategory( layer, name, canDye, entries, compactLayout ) +{ + this.layer = layer; + this.name = name; + this.canDye = canDye; + this.entries = entries; + this.compactLayout = compactLayout ? true : false; +} + +var vendorClothingCategories = [ + new VendorClothingCategory( layerInnerTorso, "Upper Torso", true, [ + new VendorClothingEntry( 0x1517, "Shirt" ), + new VendorClothingEntry( 0x1EFD, "Fancy Shirt" ), + new VendorClothingEntry( 0x1F01, "Plain Dress" ), + new VendorClothingEntry( 0x1EFF, "Fancy Dress" ), + new VendorClothingEntry( 0x1F03, "Robe" ) + ]), + + new VendorClothingCategory( layerMiddleTorso, "Over Chest", true, [ + new VendorClothingEntry( 0x1F7B, "Doublet" ), + new VendorClothingEntry( 0x1FA1, "Tunic" ), + new VendorClothingEntry( 0x1F9F, "Jester Suit" ), + new VendorClothingEntry( 0x1541, "Body Sash" ), + new VendorClothingEntry( 0x1FFD, "Surcoat" ), + new VendorClothingEntry( 0x153B, "Half Apron" ), + new VendorClothingEntry( 0x153D, "Full Apron" ) + ]), + + new VendorClothingCategory( layerShoes, "Footwear", true, [ + new VendorClothingEntry( 0x170D, "Sandals" ), + new VendorClothingEntry( 0x1710, "Shoes" ), + new VendorClothingEntry( 0x170B, "Boots" ), + new VendorClothingEntry( 0x1711, "Thigh Boots" ) + ]), + + new VendorClothingCategory( layerHelm, "Hats", true, [ + new VendorClothingEntry( 0x1544, "Skull Cap" ), + new VendorClothingEntry( 0x1540, "Bandana" ), + new VendorClothingEntry( 0x1713, "Floppy Hat" ), + new VendorClothingEntry( 0x1714, "Wide Brim Hat" ), + new VendorClothingEntry( 0x1715, "Cap" ), + new VendorClothingEntry( 0x1716, "Tall Straw Hat" ), + new VendorClothingEntry( 0x1717, "Straw Hat" ), + new VendorClothingEntry( 0x1718, "Wizard Hat" ), + new VendorClothingEntry( 0x1719, "Bonnet" ), + new VendorClothingEntry( 0x171A, "Feathered Hat" ), + new VendorClothingEntry( 0x171B, "Tricorne Hat" ), + new VendorClothingEntry( 0x171C, "Jester Hat" ) + ]), + + new VendorClothingCategory( layerPants, "Lower Torso", true, [ + new VendorClothingEntry( 0x1539, "Long Pants" ), + new VendorClothingEntry( 0x1537, "Kilt" ), + new VendorClothingEntry( 0x1516, "Skirt" ) + ]), + + new VendorClothingCategory( layerCloak, "Back", true, [ + new VendorClothingEntry( 0x1515, "Cloak" ) + ]), + + new VendorClothingCategory( layerOneHand, "Held Items", false, [ + new VendorClothingEntry( 0x0DBF, "Fishing Pole" ), + new VendorClothingEntry( 0x0E86, "Pickaxe" ), + new VendorClothingEntry( 0x0E87, "Pitchfork" ), + new VendorClothingEntry( 0x0EC3, "Cleaver" ), + new VendorClothingEntry( 0x0F5C, "Mace" ), + new VendorClothingEntry( 0x0F6B, "Torch" ), + new VendorClothingEntry( 0x102A, "Hammer" ), + new VendorClothingEntry( 0x0F61, "Longsword" ), + new VendorClothingEntry( 0x13F8, "Gnarled Staff" ), + new VendorClothingEntry( 0x0F4F, "Crossbow" ), + new VendorClothingEntry( 0x1407, "War Mace" ), + new VendorClothingEntry( 0x1443, "Two-Handed Axe" ), + new VendorClothingEntry( 0x0F62, "Spear" ), + new VendorClothingEntry( 0x13FF, "Katana" ), + new VendorClothingEntry( 0x0EFA, "Spellbook" ) + ], true) +]; + +/** @param {Character} vendor @returns {boolean} */ +function IsPlayerVendor( vendor ) +{ + return ValidateObject( vendor ) && vendor.aitype == 17; +} + +/** @param {Character} vendor @param {Character} pUser @returns {boolean} */ +function IsVendorOwner( vendor, pUser ) +{ + if( !IsPlayerVendor( vendor ) || !ValidateObject( pUser )) + return false; + + if( !ValidateObject( vendor.owner )) + return false; + + return vendor.owner.serial == pUser.serial; +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorHeldGold( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + return vendor.vendorGoldHeld || 0; +} + +/** @param {Character} vendor @param {number} amount */ +function SetVendorHeldGold( vendor, amount ) +{ + if( !IsPlayerVendor( vendor )) + return; + + if( amount < 0 ) + amount = 0; + + vendor.vendorGoldHeld = amount; +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorBankAccount( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + var bankAccount = vendor.GetTag( "VendorBankAccount" ); + if( bankAccount < 0 ) + return 0; + + return bankAccount; +} + +/** @param {Character} vendor @param {number} amount */ +function SetVendorBankAccount( vendor, amount ) +{ + if( !IsPlayerVendor( vendor )) + return; + + if( amount < 0 ) + amount = 0; + + vendor.SetTag( "VendorBankAccount", amount ); +} + +/** @returns {number} */ +function GetCurrentTimestamp() +{ + return Math.floor( GetCurrentClock() / 1000 ); +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorTotalFunds( vendor ) +{ + return GetVendorHeldGold( vendor ) + GetVendorBankAccount( vendor ); +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorLastChargeTime( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + return vendor.GetTag( "VendorLastChargeTime" ); +} + +/** @param {Character} vendor @param {number} timestamp */ +function SetVendorLastChargeTime( vendor, timestamp ) +{ + if( !IsPlayerVendor( vendor )) + return; + + vendor.SetTag( "VendorLastChargeTime", timestamp ); +} + +/** @param {Item} itemObj @returns {number} */ +function GetVendorItemPrice( itemObj ) +{ + if( !ValidateObject( itemObj )) + return 0; + + // Adjust this if your vendor sale price is stored elsewhere + if( itemObj.buyValue > 0 ) + return itemObj.buyValue; + + return 0; +} + +/** @param {Item} itemObj @returns {number} */ +function GetVendorItemPeriodFee( itemObj ) +{ + if( !ValidateObject( itemObj )) + return 0; + + var itemPrice = GetVendorItemPrice( itemObj ); + if( itemPrice <= 0 ) + return 0; + + return Math.floor( itemPrice / vendorItemFeeDivisor ) * vendorItemFeeAmount; +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorItemFeeTotal( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + var vendorPack = vendor.pack; + if( !ValidateObject( vendorPack )) + return 0; + + var totalFee = 0; + var packItem = vendorPack.FirstItem(); + + for( ; !vendorPack.FinishedItems(); packItem = vendorPack.NextItem() ) + { + if( !ValidateObject( packItem )) + continue; + + totalFee += GetVendorItemPeriodFee( packItem ); + } + + return totalFee; +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorChargePerPeriod( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + if( !vendorChargesEnabled ) + return 0; + + var overrideValue = vendor.GetTag( "VendorChargePerPeriod" ); + if( overrideValue > 0 ) + return overrideValue; + + var totalCharge = vendorBaseCharge; + + if( vendorUseItemFees ) + totalCharge += GetVendorItemFeeTotal( vendor ); + + return totalCharge; +} + +/** @param {Character} vendor @param {number} amount @returns {number} */ +function DepositVendorBankGold( vendor, amount ) +{ + if( !IsPlayerVendor( vendor ) || amount <= 0 ) + return 0; + + var bankAccount = GetVendorBankAccount( vendor ); + var roomLeft = vendorMaxFunds - bankAccount; + + if( roomLeft <= 0 ) + return 0; + + if( amount > roomLeft ) + amount = roomLeft; + + SetVendorBankAccount( vendor, bankAccount + amount ); + return amount; +} + +/** @param {Character} vendor @param {number} amount @returns {number} */ +function WithdrawVendorBankGold( vendor, amount ) +{ + if( !IsPlayerVendor( vendor ) || amount <= 0 ) + return 0; + + var bankAccount = GetVendorBankAccount( vendor ); + if( amount > bankAccount ) + amount = bankAccount; + + SetVendorBankAccount( vendor, bankAccount - amount ); + return amount; +} + +/** @param {Character} vendor @param {number} charge @returns {boolean} */ +function PayVendorCharge( vendor, charge ) +{ + if( !IsPlayerVendor( vendor ) || charge <= 0 ) + return false; + + var bankAccount = GetVendorBankAccount( vendor ); + var heldGold = GetVendorHeldGold( vendor ); + + if(( bankAccount + heldGold ) < charge ) + return false; + + if( bankAccount >= charge ) + { + SetVendorBankAccount( vendor, bankAccount - charge ); + return true; + } + + charge -= bankAccount; + SetVendorBankAccount( vendor, 0 ); + SetVendorHeldGold( vendor, heldGold - charge ); + return true; +} + +/** @param {Character} vendor @param {number} amount @returns {number} */ +function MoveBankToHeldGold( vendor, amount ) +{ + if( !IsPlayerVendor( vendor ) || amount <= 0 ) + return 0; + + var bankAccount = GetVendorBankAccount( vendor ); + if( amount > bankAccount ) + amount = bankAccount; + + SetVendorBankAccount( vendor, bankAccount - amount ); + SetVendorHeldGold( vendor, GetVendorHeldGold( vendor ) + amount ); + return amount; +} + +/** @param {Character} vendor @returns {number} */ +function FlushVendorBankToHeldGold( vendor ) +{ + var bankAccount = GetVendorBankAccount( vendor ); + if( bankAccount <= 0 ) + return 0; + + SetVendorBankAccount( vendor, 0 ); + SetVendorHeldGold( vendor, GetVendorHeldGold( vendor ) + bankAccount ); + return bankAccount; +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorPeriodsAffordable( vendor ) +{ + var perPeriod = GetVendorChargePerPeriod( vendor ); + if( perPeriod <= 0 ) + return 0; + + return Math.floor( GetVendorTotalFunds( vendor ) / perPeriod ); +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorHoursAffordable( vendor ) +{ + return GetVendorPeriodsAffordable( vendor ) * vendorChargeHours; +} + +/** @param {Character} vendor @returns {number} */ +function GetVendorDaysAffordable( vendor ) +{ + var hoursAffordable = GetVendorHoursAffordable( vendor ); + return Math.floor( hoursAffordable / 24 ); +} + +/** @param {Item} itemObj @param {Character} vendor */ +function DropItemAtVendorLocation( itemObj, vendor ) +{ + if( !ValidateObject( itemObj ) || !ValidateObject( vendor )) + return; + + itemObj.container = null; + itemObj.x = vendor.x; + itemObj.y = vendor.y; + itemObj.z = vendor.z; + itemObj.worldnumber = vendor.worldnumber; + itemObj.instanceID = vendor.instanceID; +} + +/** @param {Character} pUser @returns {Item|null} */ +function GetBankBox( pUser ) +{ + if( !ValidateObject( pUser )) + return null; + + var bankBox = pUser.FindItemLayer( 29 ); + if( !ValidateObject( bankBox )) + return null; + + return bankBox; +} + +/** @param {Item} container @param {Item} itemObj @returns {boolean} */ +function CanContainerReceiveItem( container, itemObj ) +{ + if( !ValidateObject( container ) || !ValidateObject( itemObj )) + return false; + + if( container.totalItemCount >= container.maxItems ) + return false; + + var itemWeight = itemObj.weight * itemObj.amount; + if(( container.weight + itemWeight ) > container.weightMax ) + return false; + + return true; +} + +/** @param {Item} itemObj @param {Item} container @returns {boolean} */ +function TryMoveItemToContainer( itemObj, container ) +{ + if( !ValidateObject( itemObj ) || !ValidateObject( container )) + return false; + + if( !CanContainerReceiveItem( container, itemObj )) + return false; + + itemObj.container = container; + + return ValidateObject( itemObj.container ) && itemObj.container.serial == container.serial; +} + +/** @param {Item} itemObj @param {Character} pUser @param {Character} vendor @returns {number} */ +function PlaceItemForOwnerOrDrop( itemObj, pUser, vendor ) +{ + if( !ValidateObject( itemObj ) || !ValidateObject( pUser ) || !ValidateObject( vendor )) + return 0; + + var bankBox; + var pPack; + + if( onlyReturnToBank ) + { + bankBox = GetBankBox( pUser ); + if( ValidateObject( bankBox ) && TryMoveItemToContainer( itemObj, bankBox )) + return 2; + + DropItemAtVendorLocation( itemObj, vendor ); + return 3; + } + + pPack = pUser.pack; + if( ValidateObject( pPack ) && TryMoveItemToContainer( itemObj, pPack )) + return 1; + + bankBox = GetBankBox( pUser ); + if( ValidateObject( bankBox ) && TryMoveItemToContainer( itemObj, bankBox )) + return 2; + + DropItemAtVendorLocation( itemObj, vendor ); + return 3; +} + +/** @param {Character} vendor @param {Character} pUser @returns {{pack:number, bank:number, ground:number}} */ +function ReturnVendorItemsToOwner( vendor, pUser ) +{ + var results = { pack:0, bank:0, ground:0 }; + + if( !IsPlayerVendor( vendor ) || !ValidateObject( pUser )) + return results; + + var vendorPack = vendor.pack; + if( !ValidateObject( vendorPack )) + return results; + + var itemList = []; + var packItem = vendorPack.FirstItem(); + + for( ; !vendorPack.FinishedItems(); packItem = vendorPack.NextItem() ) + { + if( ValidateObject( packItem )) + itemList.push( packItem ); + } + + for( var i = 0; i < itemList.length; ++i ) + { + var moveItem = itemList[i]; + if( !ValidateObject( moveItem )) + continue; + + var placeResult = PlaceItemForOwnerOrDrop( moveItem, pUser, vendor ); + if( placeResult == 1 ) + results.pack++; + else if( placeResult == 2 ) + results.bank++; + else if( placeResult == 3 ) + results.ground++; + } + + return results; +} + +/** @param {Character} vendor @returns {number} */ +function DropVendorItemsAtLocation( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + var vendorPack = vendor.pack; + if( !ValidateObject( vendorPack )) + return 0; + + var itemList = []; + var packItem = vendorPack.FirstItem(); + + for( ; !vendorPack.FinishedItems(); packItem = vendorPack.NextItem() ) + { + if( ValidateObject( packItem )) + itemList.push( packItem ); + } + + for( var i = 0; i < itemList.length; ++i ) + { + if( ValidateObject( itemList[i] )) + DropItemAtVendorLocation( itemList[i], vendor ); + } + + return itemList.length; +} + +/** @param {Character} vendor @returns {Item|null} */ +function CreateVendorDismissDeedAtLocation( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return null; + + var tempName = "A vendor deed for " + vendor.name + "."; + var pvDeed = CreateBlankItem( null, vendor, 1, tempName, 0x14F0, 0x0, "ITEM", false ); + if( !ValidateObject( pvDeed )) + return null; + + pvDeed.type = 217; + pvDeed.buyValue = 2000; + pvDeed.SetTag( "vendorName", vendor.name ); + + DropItemAtVendorLocation( pvDeed, vendor ); + return pvDeed; +} + +/** @param {Character} pUser @param {Character} vendor @returns {Item|null} */ +function CreateVendorDismissDeedForOwner( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return null; + + var socket = pUser.socket; + var tempName; + + if( socket ) + { + tempName = GetDictionaryEntry( 580, socket.language ); + tempName = tempName.replace( /%s/gi, vendor.name ); + } + else + { + tempName = "A vendor deed for " + vendor.name + "."; + } + + var pvDeed = CreateBlankItem( null, pUser, 1, tempName, 0x14F0, 0x0, "ITEM", false ); + if( !ValidateObject( pvDeed )) + return null; + + pvDeed.type = 217; + pvDeed.buyValue = 2000; + pvDeed.SetTag( "vendorName", vendor.name ); + + return pvDeed; +} + +/** @param {Character} vendor @returns {number} */ +function DropVendorGoldAtLocation( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return 0; + + var holdGold = GetVendorHeldGold( vendor ); + var bankGold = GetVendorBankAccount( vendor ); + var totalGold = holdGold + bankGold; + + if( totalGold <= 0 ) + return 0; + + var goldItem = CreateDFNItem( null, vendor, "0x0EED", totalGold, "ITEM", false ); + if( !ValidateObject( goldItem )) + return 0; + + SetVendorHeldGold( vendor, 0 ); + SetVendorBankAccount( vendor, 0 ); + + DropItemAtVendorLocation( goldItem, vendor ); + return totalGold; +} + +/** @param {Character} pUser @param {Character} vendor @returns {{amount:number, location:number}} */ +function ReturnVendorGoldToOwner( pUser, vendor ) +{ + var result = { amount:0, location:0 }; + + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return result; + + var holdGold = GetVendorHeldGold( vendor ); + var bankGold = GetVendorBankAccount( vendor ); + var totalGold = holdGold + bankGold; + + if( totalGold <= 0 ) + return result; + + var goldItem = CreateDFNItem( null, pUser, "0x0EED", totalGold, "ITEM", false ); + if( !ValidateObject( goldItem )) + return result; + + var placeResult = PlaceItemForOwnerOrDrop( goldItem, pUser, vendor ); + if( placeResult == 0 ) + return result; + + SetVendorHeldGold( vendor, 0 ); + SetVendorBankAccount( vendor, 0 ); + + result.amount = totalGold; + result.location = placeResult; + return result; +} + +/** @param {Character} vendor */ +function FinalizeVendorRemoval( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return; + + var iMulti = null; + if( ValidateObject( vendor.multi )) + iMulti = vendor.multi; + + if( ValidateObject( iMulti )) + iMulti.RemoveVendor( vendor ); + + vendor.Delete(); +} + +/** @param {Character} vendor @param {Character|null} notifyChar */ +function RemoveVendorForNoFunds( vendor, notifyChar ) +{ + if( !IsPlayerVendor( vendor )) + return; + + var ownerChar = null; + if( ValidateObject( vendor.owner )) + ownerChar = vendor.owner; + + if( ValidateObject( ownerChar ) && ownerChar.socket ) + { + var socket = ownerChar.socket; + socket.SysMessage( GetDictionaryEntry( 40000, socket.language ), vendor.name ); // %s can no longer afford upkeep and has been dismissed. + + var pvDeed = CreateVendorDismissDeedForOwner( ownerChar, vendor ); + if( !ValidateObject( pvDeed )) + { + socket.SysMessage( GetDictionaryEntry( 40001, socket.language )); // Unable to create vendor deed. Vendor dismissal aborted. + return; + } + + var itemResults = ReturnVendorItemsToOwner( vendor, ownerChar ); + var goldResult = ReturnVendorGoldToOwner( ownerChar, vendor ); + var deedLocation = PlaceItemForOwnerOrDrop( pvDeed, ownerChar, vendor ); + + if(( itemResults.pack + itemResults.bank + itemResults.ground ) > 0 ) + { + if( onlyReturnToBank ) + { + socket.SysMessage( GetDictionaryEntry( 40002, socket.language ), itemResults.bank, itemResults.ground ); // Vendor items returned - bank: %i, ground: %i. + } + else + { + socket.SysMessage( GetDictionaryEntry( 40003, socket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); // Vendor items returned - pack: %i, bank: %i, ground: %i. + } + } + + if( goldResult.amount > 0 ) + { + if( goldResult.location == 1 ) + socket.SysMessage( GetDictionaryEntry( 40004, socket.language ), goldResult.amount ); // Returned %i gold to your pack. + else if( goldResult.location == 2 ) + socket.SysMessage( GetDictionaryEntry( 40005, socket.language ), goldResult.amount ); // Returned %i gold to your bank box. + else if( goldResult.location == 3 ) + socket.SysMessage( GetDictionaryEntry( 40006, socket.language ), goldResult.amount ); // Dropped %i gold at vendor location. + } + + if( deedLocation == 1 ) + socket.SysMessage( GetDictionaryEntry( 40007, socket.language )); // Placed vendor deed in your pack. + else if( deedLocation == 2 ) + socket.SysMessage( GetDictionaryEntry( 40008, socket.language )); // Placed vendor deed in your bank box. + else if( deedLocation == 3 ) + socket.SysMessage( GetDictionaryEntry( 40009, socket.language )); // Dropped vendor deed at vendor location. + + FinalizeVendorRemoval( vendor ); + return; + } + + var itemCount = DropVendorItemsAtLocation( vendor ); + var totalGold = DropVendorGoldAtLocation( vendor ); + var pvDeedOffline = CreateVendorDismissDeedAtLocation( vendor ); + + if( ValidateObject( notifyChar ) && notifyChar.socket ) + { + notifyChar.socket.SysMessage( GetDictionaryEntry( 40010, notifyChar.socket.language ), vendor.name ); // %s could not afford upkeep and was dismissed. + + if( itemCount > 0 ) + notifyChar.socket.SysMessage( GetDictionaryEntry( 40011, notifyChar.socket.language ), itemCount ); // Dropped %i vendor item(s) at vendor location. + + if( totalGold > 0 ) + notifyChar.socket.SysMessage( GetDictionaryEntry( 40006, notifyChar.socket.language ), totalGold ); // Dropped %i gold at vendor location. + + if( ValidateObject( pvDeedOffline )) + notifyChar.socket.SysMessage( GetDictionaryEntry( 40009, notifyChar.socket.language )); // Dropped vendor deed at vendor location. + } + + FinalizeVendorRemoval( vendor ); +} + +/** @param {Character} vendor @param {Character|null} notifyChar @returns {boolean} */ +function CheckVendorUpkeep( vendor, notifyChar ) +{ + if( !IsPlayerVendor( vendor )) + return false; + + if( !vendorChargesEnabled ) + return true; + + var currentTime = GetCurrentTimestamp(); + var lastChargeTime = GetVendorLastChargeTime( vendor ); + var chargeInterval = vendorChargeHours * 60 * 60; + + if( chargeInterval <= 0 ) + return true; + + if( lastChargeTime <= 0 ) + { + SetVendorLastChargeTime( vendor, currentTime ); + return true; + } + + if( currentTime <= lastChargeTime ) + return true; + + var elapsed = currentTime - lastChargeTime; + var periodsOwed = Math.floor( elapsed / chargeInterval ); + + if( periodsOwed <= 0 ) + return true; + + for( var i = 0; i < periodsOwed; ++i ) + { + if( !PayVendorCharge( vendor, GetVendorChargePerPeriod( vendor ))) + { + RemoveVendorForNoFunds( vendor, notifyChar ); + return false; + } + } + + SetVendorLastChargeTime( vendor, lastChargeTime + ( periodsOwed * chargeInterval )); + return true; +} + +/** @param {Character} pUser @param {Character} vendor */ +function StoreVendorForGump( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + pUser.SetTempTag( "PlayerVendorGumpSerial", vendor.serial ); +} + +/** @param {Character} pUser @returns {Character|null} */ +function GetStoredVendorForGump( pUser ) +{ + if( !ValidateObject( pUser )) + return null; + + var vendorSerial = pUser.GetTempTag( "PlayerVendorGumpSerial" ); + if( !vendorSerial ) + return null; + + var vendor = CalcCharFromSer( vendorSerial ); + if( !IsPlayerVendor( vendor )) + return null; + + return vendor; +} + +/** @param {Character} pUser @param {Character} vendor */ +function OpenVendorBackpack( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + var pPack = vendor.pack; + if( ValidateObject( pPack )) + socket.OpenContainer( pPack ); +} + +/** @param {Socket} socket @param {Character} vendor */ +function ShowPlayerVendorOwnerGump( socket, vendor ) +{ + if( !socket || !IsPlayerVendor( vendor )) + return; + + var holdGold = GetVendorHeldGold( vendor ); + var bankAccount = GetVendorBankAccount( vendor ); + var perPeriod = GetVendorChargePerPeriod( vendor ); + var days = GetVendorDaysAffordable( vendor ); + var hours = GetVendorHoursAffordable( vendor ); + var itemFeeTotal = GetVendorItemFeeTotal( vendor ); + + var myGump = new Gump; + myGump.AddPage( 0 ); + myGump.AddBackground( 25, 10, 555, 190, 5054 ); + myGump.AddCheckerTrans( 32, 20, 537, 170 ); + myGump.NoResize(); + + myGump.AddButton( 390, 25, 4005, 4007, 1, 0, 1 ); + myGump.AddHTMLGump( 425, 25, 120, 20, false, false, "" + GetDictionaryEntry( 40029, socket.language ) + "" ); // See goods + + myGump.AddButton( 390, 48, 4005, 4007, 1, 0, 2 ); + myGump.AddHTMLGump( 425, 48, 120, 20, false, false, "" + GetDictionaryEntry( 40030, socket.language ) + "" ); // Customize + + myGump.AddButton( 390, 71, 4005, 4007, 1, 0, 3 ); + myGump.AddHTMLGump( 425, 72, 120, 20, false, false, "" + GetDictionaryEntry( 40031, socket.language ) + "" ); // Collect Gold + + myGump.AddButton( 390, 94, 4005, 4007, 1, 0, 4 ); + myGump.AddHTMLGump( 425, 95, 120, 20, false, false, "" + GetDictionaryEntry( 40032, socket.language ) + "" ); // Deposit 1000 + + myGump.AddButton( 390, 117, 4005, 4007, 1, 0, 5 ); + myGump.AddHTMLGump( 425, 118, 120, 20, false, false, "" + GetDictionaryEntry( 40033, socket.language ) + "" ); // Flush Bank + + myGump.AddButton( 390, 140, 4005, 4007, 1, 0, 6 ); + myGump.AddHTMLGump( 425, 141, 120, 20, false, false, "" + GetDictionaryEntry( 40034, socket.language ) + "" ); // Dismiss + + myGump.AddButton( 390, 163, 4005, 4007, 1, 0, 0 ); + myGump.AddHTMLGump( 425, 164, 120, 20, false, false, "" + GetDictionaryEntry( 18762, socket.language ) + "" ); // CANCEL + + if( !vendorChargesEnabled ) + { + myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); // Amount of days I can work: + myGump.AddText( 300, 25, 2603, GetDictionaryEntry( 40043, socket.language ) ); // Unlimited + + myGump.AddHTMLGump( 40, 48, 260, 20, false, false, "" + GetDictionaryEntry( 40036, socket.language ) + "" ); // Hours I can work: + myGump.AddText( 300, 48, 2603, GetDictionaryEntry( 40043, socket.language ) ); // Unlimited + + myGump.AddHTMLGump( 40, 72, 260, 20, false, false, "" + GetDictionaryEntry( 40037, socket.language ) + "" ); // Gold held for you: + myGump.AddText( 300, 72, 1153, "" + holdGold ); + + myGump.AddHTMLGump( 40, 96, 260, 20, false, false, "" + GetDictionaryEntry( 40038, socket.language ) + "" ); // Gold held in my account: + myGump.AddText( 300, 96, 1153, "" + bankAccount ); + + myGump.AddHTMLGump( 40, 120, 260, 20, false, false, "" + GetDictionaryEntry( 40039, socket.language ) + "" ); // Vendor upkeep: + myGump.AddText( 300, 120, 2603, GetDictionaryEntry( 40044, socket.language ) ); // Disabled + } + else + { + myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); // Amount of days I can work: + myGump.AddText( 300, 25, 1153, "" + days ); + + myGump.AddHTMLGump( 40, 48, 260, 20, false, false, "" + GetDictionaryEntry( 40036, socket.language ) + "" ); // Hours I can work: + myGump.AddText( 300, 48, 1153, "" + hours ); + + myGump.AddHTMLGump( 40, 72, 260, 20, false, false, "" + GetDictionaryEntry( 40037, socket.language ) + "" ); // Gold held for you: + myGump.AddText( 300, 72, 1153, "" + holdGold ); + + myGump.AddHTMLGump( 40, 96, 260, 20, false, false, "" + GetDictionaryEntry( 40038, socket.language ) + "" ); // Gold held in my account: + myGump.AddText( 300, 96, 1153, "" + bankAccount ); + + myGump.AddHTMLGump( 40, 120, 260, 20, false, false, "" + GetDictionaryEntry( 40040, socket.language ) + "" ); // My charge per period is: + myGump.AddText( 300, 120, 1153, "" + perPeriod ); + + myGump.AddHTMLGump( 40, 144, 260, 20, false, false, "" + GetDictionaryEntry( 40041, socket.language ) + "" ); // Charge period hours: + myGump.AddText( 300, 144, 1153, "" + vendorChargeHours ); + + myGump.AddHTMLGump( 40, 168, 260, 20, false, false, "" + GetDictionaryEntry( 40042, socket.language ) + "" ); // Item fee total: + myGump.AddText( 300, 168, 1153, "" + itemFeeTotal ); + } + + myGump.Send( socket ); + myGump.Free(); +} + +/** @param {Character} pUser @returns {number} */ +function GetPackGoldAmount( pUser ) +{ + if( !ValidateObject( pUser )) + return 0; + + var pPack = pUser.pack; + if( !ValidateObject( pPack )) + return 0; + + var totalGold = 0; + var goldItem = pPack.FirstItem(); + + for( ; !pPack.FinishedItems(); goldItem = pPack.NextItem() ) + { + if( !ValidateObject( goldItem )) + continue; + + if( goldItem.id == 0x0EED ) + totalGold += goldItem.amount; + } + + return totalGold; +} + +/** @param {Character} pUser @param {number} amount @returns {boolean} */ +function RemoveGoldFromPack( pUser, amount ) +{ + if( !ValidateObject( pUser ) || amount <= 0 ) + return false; + + var pPack = pUser.pack; + if( !ValidateObject( pPack )) + return false; + + var totalGold = GetPackGoldAmount( pUser ); + if( totalGold < amount ) + return false; + + var goldStacks = []; + var goldItem = pPack.FirstItem(); + + for( ; !pPack.FinishedItems(); goldItem = pPack.NextItem() ) + { + if( ValidateObject( goldItem ) && goldItem.id == 0x0EED ) + goldStacks.push( goldItem ); + } + + for( var i = 0; i < goldStacks.length && amount > 0; ++i ) + { + var stack = goldStacks[i]; + if( !ValidateObject( stack )) + continue; + + if( stack.amount <= amount ) + { + amount -= stack.amount; + stack.Delete(); + } + else + { + stack.amount = stack.amount - amount; + amount = 0; + } + } + + return amount <= 0; +} + +/** @param {Character} pUser @returns {boolean} */ +function CanBankReceiveVendorPayout( pUser ) +{ + if( !ValidateObject( pUser )) + return false; + + var bankBox = GetBankBox( pUser ); + if( !ValidateObject( bankBox )) + return false; + + if( bankBox.totalItemCount >= bankBox.maxItems ) + return false; + + if( bankBox.weight > bankBox.weightMax ) + return false; + + return true; +} + +/** @param {Character} pUser @param {number} checkSize @returns {Item|null} */ +function CreateVendorBankCheck( pUser, checkSize ) +{ + if( !ValidateObject( pUser ) || checkSize <= 0 ) + return null; + + var socket = pUser.socket; + var bankBox = GetBankBox( pUser ); + if( !ValidateObject( bankBox )) + return null; + + var newCheck = CreateDFNItem( socket, pUser, "bankcheck", 1, "ITEM", false ); + if( !ValidateObject( newCheck )) + return null; + + newCheck.SetTag( "CheckSize", checkSize ); + newCheck.AddScriptTrigger( 5015 ); + newCheck.container = bankBox; + + return newCheck; +} + +/** @param {Character} pUser @param {number} goldAmount @returns {boolean} */ +function DepositVendorGoldToBankBox( pUser, goldAmount ) +{ + if( !ValidateObject( pUser ) || goldAmount <= 0 ) + return false; + + var bankBox = GetBankBox( pUser ); + if( !ValidateObject( bankBox )) + return false; + + if( bankBox.totalItemCount >= bankBox.maxItems ) + return false; + + if( bankBox.weight > bankBox.weightMax ) + return false; + + DivideDepositedGold( pUser, bankBox, goldAmount ); + return true; +} + +/** @param {Character} pTalking @param {Item} bankBox @param {number} depositAmt @returns {void} */ +function DivideDepositedGold( pTalking, bankBox, depositAmt ) +{ + var numOfGoldPiles = ( depositAmt / 65535 ); + var i = 0; + var newGoldPile; + var remainingGold = depositAmt; + for( i = 1; i < numOfGoldPiles + 1; i++ ) + { + if( remainingGold >= 65535 ) + { + newGoldPile = CreateDFNItem( pTalking.socket, pTalking, "0x0EED", 65535, "ITEM", false ); + remainingGold = remainingGold - 65535; + newGoldPile.container = bankBox; + } + else + { + newGoldPile = CreateDFNItem( pTalking.socket, pTalking, "0x0EED", remainingGold, "ITEM", false ); + newGoldPile.container = bankBox; + continue; + } + } +} + +/** @param {Character} pUser @param {Character} vendor */ +function CollectVendorGold( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + var holdGold = GetVendorHeldGold( vendor ); + if( holdGold <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 40012, socket.language )); // This vendor has no held gold to collect. + return; + } + + if( !CanBankReceiveVendorPayout( pUser )) + { + socket.SysMessage( GetDictionaryEntry( 40013, socket.language )); // Your bank box cannot receive vendor payouts right now. + return; + } + + if( holdGold > 2000 ) + { + var vendorCheck = CreateVendorBankCheck( pUser, holdGold ); + if( !ValidateObject( vendorCheck )) + { + socket.SysMessage( GetDictionaryEntry( 40014, socket.language )); // Unable to create a bank check for vendor gold. + return; + } + + SetVendorHeldGold( vendor, 0 ); + socket.SysMessage( GetDictionaryEntry( 40015, socket.language ), holdGold ); // Collected %i gold as a bank check in your bank box. + return; + } + + if( !DepositVendorGoldToBankBox( pUser, holdGold )) + { + socket.SysMessage( GetDictionaryEntry( 40016, socket.language )); // Unable to deposit vendor gold into your bank box. + return; + } + + SetVendorHeldGold( vendor, 0 ); + socket.SysMessage( GetDictionaryEntry( 40017, socket.language ), holdGold ); // Collected %i gold to your bank box. +} + +/** @param {Character} pUser @param {Character} vendor @param {number} amount */ +function DepositToVendorBank( pUser, vendor, amount ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + if( amount <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 40018, socket.language )); // Invalid deposit amount. + return; + } + + var pPack = pUser.pack; + if( !ValidateObject( pPack )) + { + socket.SysMessage( GetDictionaryEntry( 40019, socket.language )); // You have no backpack. + return; + } + + var totalPackGold = GetPackGoldAmount( pUser ); + if( totalPackGold < amount ) + { + socket.SysMessage( GetDictionaryEntry( 40020, socket.language )); // You do not have enough gold in your pack. + return; + } + + var deposited = DepositVendorBankGold( vendor, amount ); + if( deposited <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 40021, socket.language )); // Vendor bank account is full. + return; + } + + if( !RemoveGoldFromPack( pUser, deposited )) + { + WithdrawVendorBankGold( vendor, deposited ); + socket.SysMessage( GetDictionaryEntry( 40022, socket.language )); // Unable to remove gold from your pack. Deposit cancelled. + return; + } + + socket.SysMessage( GetDictionaryEntry( 40023, socket.language ), deposited ); // Deposited %i gold into vendor bank account. + + if( deposited < amount ) + socket.SysMessage( GetDictionaryEntry( 40024, socket.language )); // Vendor bank reached its maximum balance. +} + +/** @param {Character} pUser @param {Character} vendor */ +function FlushBankToHeld( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + var moved = FlushVendorBankToHeldGold( vendor ); + if( moved <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 40025, socket.language )); // Vendor bank account is empty. + return; + } + + socket.SysMessage( GetDictionaryEntry( 40026, socket.language ), moved ); // Moved %i gold from vendor bank account to held gold. +} + +/** @param {Character} pUser @param {Character} vendor */ +function DismissVendor( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + var pvDeed = CreateVendorDismissDeedForOwner( pUser, vendor ); + if( !ValidateObject( pvDeed )) + { + socket.SysMessage( GetDictionaryEntry( 40027, socket.language )); // Unable to create vendor deed. Dismiss cancelled. + return; + } + + var itemResults = ReturnVendorItemsToOwner( vendor, pUser ); + var goldResult = ReturnVendorGoldToOwner( pUser, vendor ); + var deedLocation = PlaceItemForOwnerOrDrop( pvDeed, pUser, vendor ); + + socket.SysMessage( GetDictionaryEntry( 581, socket.language ), pvDeed.name ); // Thy deed for %s has been placed in thy pack. + + if(( itemResults.pack + itemResults.bank + itemResults.ground ) > 0 ) + { + if( onlyReturnToBank ) + { + socket.SysMessage( GetDictionaryEntry( 40002, socket.language ), itemResults.bank, itemResults.ground ); // Vendor items returned - bank: %i, ground: %i. + } + else + { + socket.SysMessage( GetDictionaryEntry( 40003, socket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); // Vendor items returned - pack: %i, bank: %i, ground: %i. + } + } + + if( goldResult.amount > 0 ) + { + if( goldResult.location == 1 ) + socket.SysMessage( GetDictionaryEntry( 40004, socket.language ), goldResult.amount ); // Returned %i gold to your pack. + else if( goldResult.location == 2 ) + socket.SysMessage( GetDictionaryEntry( 40005, socket.language ), goldResult.amount ); // Returned %i gold to your bank box. + else if( goldResult.location == 3 ) + socket.SysMessage( GetDictionaryEntry( 40006, socket.language ), goldResult.amount ); // Dropped %i gold at vendor location. + } + + if( deedLocation == 1 ) + socket.SysMessage( GetDictionaryEntry( 40007, socket.language )); // Placed vendor deed in your pack. + else if( deedLocation == 2 ) + socket.SysMessage( GetDictionaryEntry( 40008, socket.language )); // Placed vendor deed in your bank box. + else if( deedLocation == 3 ) + socket.SysMessage( GetDictionaryEntry( 40009, socket.language )); // Dropped vendor deed at vendor location. + + FinalizeVendorRemoval( vendor ); +} + +/** @param {string} speech @returns {string} */ +function NormalizeSpeech( speech ) +{ + if( !speech ) + return ""; + + return ( "" + speech ).toLowerCase().replace( /^\s+|\s+$/g, "" ); +} + +/** @param {Character} vendor @param {string} speech @returns {string} */ +function StripVendorNamePrefix( vendor, speech ) +{ + if( !IsPlayerVendor( vendor )) + return speech; + + var vendorName = ""; + if( vendor.name ) + vendorName = ( "" + vendor.name ).toLowerCase(); + + if( vendorName == "" ) + return speech; + + if( speech.indexOf( vendorName + " " ) == 0 ) + return speech.substring( vendorName.length + 1 ); + + if( speech.indexOf( vendorName + "," ) == 0 ) + return speech.substring( vendorName.length + 1 ).replace( /^\s+|\s+$/g, "" ); + + return speech; +} + +/** @param {Character} pUser @param {Character} vendor @param {string} speech @returns {boolean} */ +function MatchVendorCommand( pUser, vendor, speech ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return false; + + var cmd = NormalizeSpeech( speech ); + cmd = StripVendorNamePrefix( vendor, cmd ); + + if( cmd == "view" || cmd == "browse" || cmd == "look" ) + return true; + + if( cmd == "buy" || cmd == "purchase" ) + return true; + + if( cmd == "gold" || cmd == "collect" || cmd == "get" ) + return true; + + if( cmd == "status" || cmd == "info" ) + return true; + + if( cmd == "dismiss" || cmd == "replace" ) + return true; + + return false; +} + +/** @param {Character} pUser @param {Character} vendor @param {string} speech @returns {number} */ +function HandleVendorSpeechCommand( pUser, vendor, speech ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return 0; + + var socket = pUser.socket; + var cmd = NormalizeSpeech( speech ); + cmd = StripVendorNamePrefix( vendor, cmd ); + + if( cmd == "view" || cmd == "browse" || cmd == "look" ) + { + if( !CheckVendorUpkeep( vendor, pUser )) + return 2; + + OpenVendorBackpack( pUser, vendor ); + return 2; + } + + if( cmd == "buy" || cmd == "purchase" ) + { + if( !CheckVendorUpkeep( vendor, pUser )) + return 2; + + pUser.BuyFrom( vendor ); + return 2; + } + + if( cmd == "gold" || cmd == "collect" || cmd == "get" ) + { + if( !IsVendorOwner( vendor, pUser )) + { + vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + return 2; + } + + if( !CheckVendorUpkeep( vendor, pUser )) + return 2; + + CollectVendorGold( pUser, vendor ); + return 2; + } + + if( cmd == "status" || cmd == "info" ) + { + if( !IsVendorOwner( vendor, pUser )) + { + vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + return 2; + } + + if( !CheckVendorUpkeep( vendor, pUser )) + return 2; + + if( socket ) + { + StoreVendorForGump( pUser, vendor ); + ShowPlayerVendorOwnerGump( socket, vendor ); + } + return 2; + } + + if( cmd == "dismiss" || cmd == "replace" ) + { + if( !IsVendorOwner( vendor, pUser )) + { + vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + return 2; + } + + DismissVendor( pUser, vendor ); + return 2; + } + + return 0; +} + +/** @type { ( pUser: Character, targChar: Character, nonMouseClickEvent: boolean ) => boolean } */ +function onCharDoubleClick( pUser, targChar, nonMouseClickEvent ) +{ + if( !ValidateObject( pUser ) || !ValidateObject( targChar )) + return false; + + if( nonMouseClickEvent ) + return true; + + if( !IsPlayerVendor( targChar )) + return true; + + if( !CheckVendorUpkeep( targChar, pUser )) + return false; + + if( IsVendorOwner( targChar, pUser )) + { + if( pUser.socket ) + { + StoreVendorForGump( pUser, targChar ); + ShowPlayerVendorOwnerGump( pUser.socket, targChar ); + } + return false; + } + + OpenVendorBackpack( pUser, targChar ); + return false; +} + +/** @param {string} speech @param {Character} personTalking @param {BaseObject} talkingTo @returns {number} */ +function onSpeech( speech, personTalking, talkingTo ) +{ + if( !ValidateObject( personTalking ) || !ValidateObject( talkingTo )) + return 0; + + if( !IsPlayerVendor( talkingTo )) + return 0; + + if( !MatchVendorCommand( personTalking, talkingTo, speech )) + return 0; + + return HandleVendorSpeechCommand( personTalking, talkingTo, speech ); +} + +/** @param {Character} socket @param {Gump} myGump @param {number} menuPage @param {number} categoryPageStart @param {string} title */ +function AddHairHueCategoryMenu( socket, myGump, menuPage, categoryPageStart, title ) +{ + myGump.AddPage( menuPage ); + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + title + "
" ); + + var columns = 2; + var startX = 20; + var startY = 70; + var colWidth = 160; + var rowHeight = 20; + + for( var i = 0; i < vendorHairHueCategories.length; ++i ) + { + var row = Math.floor( i / columns ); + var col = i % columns; + var x = startX + ( col * colWidth ); + var y = startY + ( row * rowHeight ); + + myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 0, categoryPageStart + i, 0 ); + myGump.AddHTMLGump( x + 30, y, 125, 18, false, false, "" + GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) + "" ); + } + + myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 1, 5007 ); + myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK +} + +/** @param {Character} socket @param {Gump} myGump @param {number} pageNumber @param {string} title @param {number[]} hueList @param {number} buttonBase @param {number} backPage */ +function AddHairHueCategoryPage( socket, myGump, pageNumber, title, hueList, buttonBase, backPage ) +{ + myGump.AddPage( pageNumber ); + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + title + "
" ); + + var hueColumns = 3; + var startX = 20; + var startY = 70; + var colWidth = 112; + var rowHeight = 18; + + for( var i = 0; i < hueList.length; ++i ) + { + var row = Math.floor( i / hueColumns ); + var col = i % hueColumns; + var x = startX + ( col * colWidth ); + var y = startY + ( row * rowHeight ); + var hueHex = hueList[i].toString( 16 ).toUpperCase(); + + myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 1, pageNumber, buttonBase + hueList[i] ); + myGump.AddText( x + 25, y, hueList[i], "0x" + hueHex ); + } + + myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 0, backPage, 0 ); + myGump.AddHTMLGump( 45, 342, 80, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK + + myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 1, 5007 ); + myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 40045, socket.language ) + "" ); // MAIN +} + +/** @param {Socket} pSock @param {number} pButton @param {GumpData} gumpData */ +function onGumpPress( pSock, pButton, gumpData ) +{ + var pUser = pSock.currentChar; + if( !ValidateObject( pUser )) + return; + + var vendor = GetStoredVendorForGump( pUser ); + if( !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + if( !CheckVendorUpkeep( vendor, pUser )) + return; + + if( pButton == 5000 || pButton == 5001 || pButton == 5002 || pButton == 5004 || pButton == 5006 || pButton == 5007 || + ( pButton >= 0x1000 && pButton < ( 0x1000 + 256 )) || + ( pButton >= 0x2000 && pButton < ( 0x2000 + 256 )) || + ( pButton >= 0x3000 && pButton < 0x4000 ) || + ( pButton >= 0x4000 && pButton < 0x5000 )) + { + HandleVendorCustomizeButton( pUser, vendor, pButton ); + return; + } + + if( pButton == 0x8FFF || pButton == 0x8FFE || + ( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 )) || + ( pButton >= 0x7000 && pButton < ( 0x7000 + 100 )) || + ( pButton >= 0x8000 && pButton < ( 0x8000 + vendorClothingCategories.length )) || + ( pButton >= 0x9000 && pButton < ( 0x9000 + 0x1000 ))) + { + HandleVendorClothingButton( pUser, vendor, pButton ); + return; + } + + switch( pButton ) + { + case 0: + break; + case 1: + OpenVendorBackpack( pUser, vendor ); + break; + case 2: + ShowVendorCustomizeGump( pUser, vendor ); + break; + case 3: + CollectVendorGold( pUser, vendor ); + ShowPlayerVendorOwnerGump( pSock, vendor ); + break; + case 4: + DepositToVendorBank( pUser, vendor, 1000 ); + ShowPlayerVendorOwnerGump( pSock, vendor ); + break; + case 5: + FlushBankToHeld( pUser, vendor ); + ShowPlayerVendorOwnerGump( pSock, vendor ); + break; + case 6: + DismissVendor( pUser, vendor ); + break; + case 7: + ShowVendorClothingGump( pUser, vendor ); + break; + default: + break; + } +} + +/** @param {Character} vendor @returns {boolean} */ +function IsFemaleVendor( vendor ) +{ + return vendor.id == 0x0191 || vendor.id == 0x025E; +} + +/** @param {Character} vendor @returns {boolean} */ +function IsElfVendor( vendor ) +{ + return vendor.id == 0x025D || vendor.id == 0x025E; +} + +/** @param {Character} vendor @param {boolean} isElf @param {boolean} isFemale */ +function SetVendorRaceGenderBody( vendor, isElf, isFemale ) +{ + if( isElf ) + vendor.id = ( isFemale ? 0x025E : 0x025D ); + else + vendor.id = ( isFemale ? 0x0191 : 0x0190 ); + + if( isFemale ) + RemoveVendorLayerItem( vendor, layerBeard ); + + vendor.Teleport(); +} + +/** @param {Character} vendor @returns {HairOrBeard[]} */ +function GetVendorHairStyles( vendor ) +{ + if( IsElfVendor( vendor )) + { + if( IsFemaleVendor( vendor )) + return femaleElfHairStyles; + + return maleElfHairStyles; + } + + return humanHairStyles; +} + +/** @param {Character} vendor @returns {boolean} */ +function VendorCanHaveBeard( vendor ) +{ + return !IsElfVendor( vendor ) && !IsFemaleVendor( vendor ); +} + +/** @param {Character} pUser @param {Character} vendor */ +function ShowVendorCustomizeGump( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + StoreVendorForGump( pUser, vendor ); + + var isElf = IsElfVendor( vendor ); + var isFemale = IsFemaleVendor( vendor ); + var hairStyles = GetVendorHairStyles( vendor ); + + var myGump = new Gump; + myGump.AddPage( 0 ); + myGump.AddBackground( 0, 0, 370, 370, 0x13BE ); + myGump.AddCheckerTrans( 10, 10, 350, 350 ); + myGump.AddHTMLGump( 10, 12, 350, 18, false, false, "
" + GetDictionaryEntry( 40046, socket.language ) + "
" ); // VENDOR CUSTOMIZATION MENU + + myGump.AddPage( 1 ); + myGump.AddHTMLGump( 10, 42, 150, 18, false, false, "
" + GetDictionaryEntry( 40047, socket.language ) + "
" ); // HAIR + + var i; + for( i = 0; i < hairStyles.length; ++i ) + { + myGump.AddButton( 10, 70 + ( i * 20 ), 0xFA5, 0xFA7, 1, 1, 0x1000 + i ); + myGump.AddHTMLGump( 45, 72 + ( i * 20 ), 110, 18, false, false, "" + GetHairOrBeardName( hairStyles[i], socket ) + "" ); + } + + myGump.AddButton( 10, 70 + ( hairStyles.length * 20 ), 0xFB1, 0xFB3, 1, 1, 5002 ); + myGump.AddHTMLGump( 45, 72 + ( hairStyles.length * 20 ), 110, 18, false, false, "" + GetDictionaryEntry( 40071, socket.language ) + "" ); // Remove Hair + + myGump.AddButton( 10, 70 + (( hairStyles.length + 1 ) * 20 ), 0xFA5, 0xFA7, 0, 2, 0 ); + myGump.AddHTMLGump( 45, 72 + (( hairStyles.length + 1 ) * 20 ), 110, 18, false, false, "" + GetDictionaryEntry( 40072, socket.language ) + "" ); // Color Hair + + if( VendorCanHaveBeard( vendor )) + { + myGump.AddHTMLGump( 160, 42, 190, 18, false, false, "
" + GetDictionaryEntry( 40073, socket.language ) + "
" ); // BEARD + + for( i = 0; i < humanBeardStyles.length; ++i ) + { + myGump.AddButton( 160, 70 + ( i * 20 ), 0xFA5, 0xFA7, 1, 1, 0x2000 + i ); + myGump.AddHTMLGump( 195, 72 + ( i * 20 ), 160, 18, false, false, "" + GetHairOrBeardName( hairStyles[i], socket ) + "" ); + } + + myGump.AddButton( 160, 70 + ( humanBeardStyles.length * 20 ), 0xFB1, 0xFB3, 1, 1, 5004 ); + myGump.AddHTMLGump( 195, 72 + ( humanBeardStyles.length * 20 ), 160, 18, false, false, "" + GetDictionaryEntry( 40074, socket.language ) + "" ); // Remove Beard + + myGump.AddButton( 160, 70 + (( humanBeardStyles.length + 1 ) * 20 ), 0xFA5, 0xFA7, 0, 100, 0 ); + myGump.AddHTMLGump( 195, 72 + (( humanBeardStyles.length + 1 ) * 20 ), 160, 18, false, false, "" + GetDictionaryEntry( 40075, socket.language ) + "" ); // Color Beard + } + + myGump.AddButton( 160, 290, 0xFA5, 0xFA7, 1, 1, 5001 ); + myGump.AddHTMLGump( 195, 292, 160, 18, false, false, isFemale ? "" + GetDictionaryEntry( 40076, socket.language ) + "" : "" + GetDictionaryEntry( 40077, socket.language ) + "" ); // Change to Male Change to Female + + myGump.AddButton( 160, 310, 0xFA5, 0xFA7, 1, 1, 5006 ); + myGump.AddHTMLGump( 195, 312, 160, 18, false, false, isElf ? "" + GetDictionaryEntry( 40078, socket.language ) + "" : "" + GetDictionaryEntry( 40079, socket.language ) + "" ); // Change to Human Change to Elf + + myGump.AddButton( 160, 330, 0xFA5, 0xFA7, 1, 0, 7 ); + myGump.AddHTMLGump( 195, 332, 160, 18, false, false, "" + GetDictionaryEntry( 40080, socket.language ) + "" ); // Change Clothing + + myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 1, 1, 5000 ); + myGump.AddHTMLGump( 45, 342, 305, 18, false, false, "" + GetDictionaryEntry( 40081, socket.language ) + "" ); // CLOSE + + AddHairHueCategoryMenu( socket, myGump, 2, 10, GetDictionaryEntry( 40082, socket.language )); // HAIR COLOR + AddHairHueCategoryMenu( socket, myGump, 100, 110, GetDictionaryEntry( 40083, socket.language )); // BEARD COLOR + + for( i = 0; i < vendorHairHueCategories.length; ++i ) + { + var hairTitle = GetDictionaryEntry( 40084, socket.language ); // Hair - %s + hairTitle = hairTitle.replace( /%s/gi, GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) ); + + var beardTitle = GetDictionaryEntry( 40085, socket.language ); // Beard - %s + beardTitle = beardTitle.replace( /%s/gi, GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) ); + + AddHairHueCategoryPage( socket, myGump, 10 + i, hairTitle, vendorHairHueCategories[i].hues, 0x3000, 2 ); + AddHairHueCategoryPage( socket, myGump, 110 + i, beardTitle, vendorHairHueCategories[i].hues, 0x4000, 100 ); + } + + myGump.Send( socket ); + myGump.Free(); +} + +/** @param {Character} pUser @param {Character} vendor @param {number} pButton */ +function HandleVendorCustomizeButton( pUser, vendor, pButton ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + var isElf = IsElfVendor( vendor ); + var isFemale = IsFemaleVendor( vendor ); + var hairStyles = GetVendorHairStyles( vendor ); + + if( pButton == 5000 ) + { + ShowPlayerVendorOwnerGump( socket, vendor ); + return; + } + + if( pButton == 5007 ) + { + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton == 5001 ) + { + RemoveVendorLayerItem( vendor, layerBeard ); + SetVendorRaceGenderBody( vendor, isElf, !isFemale ); + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton == 5006 ) + { + RemoveVendorLayerItem( vendor, layerHair ); + RemoveVendorLayerItem( vendor, layerBeard ); + + SetVendorRaceGenderBody( vendor, !isElf, isFemale ); + + var newHairStyles = GetVendorHairStyles( vendor ); + if( newHairStyles.length > 0 ) + SetVendorHairStyleByLayer( vendor, newHairStyles[0].itemID ); + + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton == 5002 ) + { + RemoveVendorLayerItem( vendor, layerHair ); + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton == 5004 ) + { + RemoveVendorLayerItem( vendor, layerBeard ); + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton >= 0x1000 && pButton < ( 0x1000 + 256 ) ) + { + var hairIndex = pButton - 0x1000; + if( hairIndex >= 0 && hairIndex < hairStyles.length ) + SetVendorHairStyleByLayer( vendor, hairStyles[hairIndex].itemID ); + + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton >= 0x2000 && pButton < ( 0x2000 + 256 ) ) + { + var beardIndex = pButton - 0x2000; + if( VendorCanHaveBeard( vendor ) && beardIndex >= 0 && beardIndex < humanBeardStyles.length ) + SetVendorBeardStyleByLayer( vendor, humanBeardStyles[beardIndex].itemID ); + + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton >= 0x3000 && pButton < 0x4000 ) + { + SetVendorHairHueByLayer( vendor, pButton - 0x3000 ); + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton >= 0x4000 && pButton < 0x5000 ) + { + if( VendorCanHaveBeard( vendor ) ) + SetVendorBeardHueByLayer( vendor, pButton - 0x4000 ); + + ShowVendorCustomizeGump( pUser, vendor ); + return; + } +} + +/** @param {Character} vendor @param {number} layer */ +function RemoveVendorLayerItem( vendor, layer ) +{ + if( !ValidateObject( vendor )) + return; + + var layerItem = vendor.FindItemLayer( layer ); + if( ValidateObject( layerItem )) + layerItem.Delete(); +} + +/** @param {Character} vendor @param {number} itemID @param {number} layer @param {number} hue @returns {boolean} */ +function EquipVendorLayerItem( vendor, itemID, layer, hue ) +{ + if( !ValidateObject( vendor )) + return false; + + var socket = null; + if( vendor.socket ) + socket = vendor.socket; + + var itemName = "vendor style item"; + var newItem = CreateBlankItem( socket, vendor, 1, itemName, itemID, hue, "ITEM", false ); + if( !ValidateObject( newItem )) + return false; + + newItem.container = vendor; + newItem.layer = layer; + return true; +} + +/** @param {Character} vendor @param {number} hairItemID */ +function SetVendorHairStyleByLayer( vendor, hairItemID ) +{ + if( !ValidateObject( vendor )) + return; + + var oldHair = vendor.FindItemLayer( layerHair ); + var oldHue = 0; + if( ValidateObject( oldHair )) + oldHue = oldHair.colour; + + RemoveVendorLayerItem( vendor, layerHair ); + + if( hairItemID != 0 ) + EquipVendorLayerItem( vendor, hairItemID, layerHair, oldHue ); +} + +/** @param {Character} vendor @param {number} beardItemID */ +function SetVendorBeardStyleByLayer( vendor, beardItemID ) +{ + if( !ValidateObject( vendor )) + return; + + var oldBeard = vendor.FindItemLayer( layerBeard ); + var oldHue = 0; + if( ValidateObject( oldBeard )) + oldHue = oldBeard.colour; + + RemoveVendorLayerItem( vendor, layerBeard ); + + if( beardItemID != 0 ) + EquipVendorLayerItem( vendor, beardItemID, layerBeard, oldHue ); +} + +/** @param {Character} vendor @param {number} hue */ +function SetVendorHairHueByLayer( vendor, hue ) +{ + if( !ValidateObject( vendor )) + return; + + var hairItem = vendor.FindItemLayer( layerHair ); + if( ValidateObject( hairItem )) + hairItem.colour = hue; +} + +/** @param {Character} vendor @param {number} hue */ +function SetVendorBeardHueByLayer( vendor, hue ) +{ + if( !ValidateObject( vendor )) + return; + + var beardItem = vendor.FindItemLayer( layerBeard ); + if( ValidateObject( beardItem )) + beardItem.colour = hue; +} + +/** @param {Character} vendor @param {number} layer */ +function RemoveVendorEquippedLayer( vendor, layer ) +{ + if( !ValidateObject( vendor )) + return; + + var oldItem = vendor.FindItemLayer( layer ); + if( ValidateObject( oldItem )) + oldItem.Delete(); +} + +/** @param {Character} vendor @param {number} itemID @param {number} layer @param {number} hue @returns {boolean} */ +function EquipVendorItemOnLayer( vendor, itemID, layer, hue ) +{ + if( !ValidateObject( vendor )) + return false; + + var socket = vendor.socket ? vendor.socket : null; + var newItem = CreateBlankItem( socket, vendor, 1, "vendor clothing", itemID, hue, "ITEM", false ); + if( !ValidateObject( newItem )) + return false; + + newItem.container = vendor; + newItem.layer = layer; + return true; +} + +/** @param {Character} vendor @param {number} layer @param {number} itemID */ +function SetVendorClothingByLayer( vendor, layer, itemID ) +{ + if( !ValidateObject( vendor )) + return; + + var oldItem = vendor.FindItemLayer( layer ); + var oldHue = 0; + + if( ValidateObject( oldItem )) + oldHue = oldItem.colour; + + RemoveVendorEquippedLayer( vendor, layer ); + + if( itemID != 0 ) + EquipVendorItemOnLayer( vendor, itemID, layer, oldHue ); +} + +/** @param {Character} vendor @param {number} layer @param {number} hue */ +function SetVendorClothingHueByLayer( vendor, layer, hue ) +{ + if( !ValidateObject( vendor )) + return; + + var layerItem = vendor.FindItemLayer( layer ); + if( ValidateObject( layerItem )) + layerItem.colour = hue; +} + +/** @param {Character} pUser @param {number} categoryIndex */ +function StoreClothingDyeCategory( pUser, categoryIndex ) +{ + if( !ValidateObject( pUser )) + return; + + pUser.SetTempTag( "PlayerVendorClothingDyeCategory", categoryIndex ); +} + +/** @param {Character} pUser @returns {number} */ +function GetStoredClothingDyeCategory( pUser ) +{ + if( !ValidateObject( pUser )) + return -1; + + var categoryIndex = pUser.GetTempTag( "PlayerVendorClothingDyeCategory" ); + if( categoryIndex === null || categoryIndex === undefined || categoryIndex === "" ) + return -1; + + return categoryIndex; +} + +/** @param {Character} pUser @param {Character} vendor */ +function ShowVendorClothingGump( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + StoreVendorForGump( pUser, vendor ); + + var myGump = new Gump; + myGump.AddPage( 0 ); + myGump.AddBackground( 0, 0, 585, 393, 5054 ); + myGump.AddBackground( 195, 36, 387, 275, 3000 ); + myGump.AddHTMLGump( 10, 10, 565, 18, false, false, "
" + GetDictionaryEntry( 40086, socket.language ) + "
" ); // VENDOR CLOTHING MENU + + myGump.AddHTMLGump( 60, 355, 150, 18, false, false, GetDictionaryEntry( 18718, socket.language ) ); // OKAY + myGump.AddButton( 25, 355, 4005, 4007, 1, 0, 5000 ); + + myGump.AddHTMLGump( 320, 355, 150, 18, false, false, GetDictionaryEntry( 10267, socket.language )); // BACK + myGump.AddButton( 285, 355, 4005, 4007, 1, 0, 0x8FFF ); + + var i; + var y = 35; + + for( i = 0; i < vendorClothingCategories.length; ++i ) + { + myGump.AddHTMLGump( 5, y, 150, 25, false, false, vendorClothingCategories[i].name ); + myGump.AddButton( 155, y, 4005, 4007, 0, 20 + i, 0 ); + y += 25; + } + + for( i = 0; i < vendorClothingCategories.length; ++i ) + { + var cat = vendorClothingCategories[i]; + myGump.AddPage( 20 + i ); + + var entryIndex; + for( entryIndex = 0; entryIndex < cat.entries.length; ++entryIndex ) + { + var entry = cat.entries[entryIndex]; + var cols = 3; + var startX = 198; + var startY = 38; + var colWidth = 129; + var rowHeight = 67; + var textWidth = 100; + var itemOffsetX = 20; + var itemOffsetY = 25; + var buttonOffsetY = 45; + + if( cat.name == "Held Items" ) + { + cols = 4; + startX = 205; + startY = 42; + colWidth = 92; + rowHeight = 52; + textWidth = 80; + itemOffsetX = 18; + itemOffsetY = 16; + buttonOffsetY = 30; + } + + var x = startX + ( entryIndex % cols ) * colWidth; + var ey = startY + Math.floor( entryIndex / cols ) * rowHeight; + + myGump.AddHTMLGump( x, ey, textWidth, 18, false, false, entry.name ); + myGump.AddPicture( x + itemOffsetX, ey + itemOffsetY, entry.itemID ); + myGump.AddButton( x, ey + buttonOffsetY, 4005, 4007, 1, 20 + i, 0x5000 + ( i * 100 ) + entryIndex ); + } + + if( cat.canDye ) + { + myGump.AddButton( 300, 315, 4005, 4007, 1, 0, 0x8000 + i ); + myGump.AddHTMLGump( 335, 317, 100, 18, false, false, GetDictionaryEntry( 40087, socket.language )); // Color + } + + myGump.AddButton( 430, 315, 4005, 4007, 1, 20 + i, 0x7000 + i ); + myGump.AddHTMLGump( 465, 317, 100, 18, false, false, GetDictionaryEntry( 40088, socket.language )); // Remove + } + + myGump.Send( socket ); + myGump.Free(); +} + +/** @param {Character} pUser @param {Character} vendor */ +function ShowVendorClothingDyeGump( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + StoreVendorForGump( pUser, vendor ); + + var categoryIndex = GetStoredClothingDyeCategory( pUser ); + var title = GetDictionaryEntry( 40091, socket.language ); + + if( categoryIndex >= 0 && categoryIndex < vendorClothingCategories.length ) + title = vendorClothingCategories[categoryIndex].name + " COLOR"; + + var myGump = new Gump; + myGump.AddPage( 0 ); + myGump.AddBackground( 0, 0, 370, 370, 0x13BE ); + myGump.AddCheckerTrans( 10, 10, 350, 350 ); + myGump.AddHTMLGump( 10, 12, 350, 18, false, false, "
" + title + "
" ); + + myGump.AddPage( 1 ); + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + GetDictionaryEntry( 40089, socket.language ) + "
" ); // COLOR CATEGORY + + var columns = 2; + var startX = 20; + var startY = 70; + var colWidth = 160; + var rowHeight = 20; + + var i; + for( i = 0; i < vendorHairHueCategories.length; ++i ) + { + var row = Math.floor( i / columns ); + var col = i % columns; + var x = startX + ( col * colWidth ); + var y = startY + ( row * rowHeight ); + + myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 0, 10 + i, 0 ); + myGump.AddHTMLGump( x + 30, y, 125, 18, false, false, "" + GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) + "" ); + } + + myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 1, 0, 0x8FFE ); + myGump.AddHTMLGump( 45, 342, 120, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK + + for( i = 0; i < vendorHairHueCategories.length; ++i ) + { + myGump.AddPage( 10 + i ); + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) + "
" ); + + var hues = vendorHairHueCategories[i].hues; + var hueColumns = 3; + var hueStartX = 20; + var hueStartY = 70; + var hueColWidth = 112; + var hueRowHeight = 18; + + var j; + for( j = 0; j < hues.length; ++j ) + { + var hueRow = Math.floor( j / hueColumns ); + var hueCol = j % hueColumns; + var hx = hueStartX + ( hueCol * hueColWidth ); + var hy = hueStartY + ( hueRow * hueRowHeight ); + var hueHex = hues[j].toString( 16 ).toUpperCase(); + + myGump.AddButton( hx, hy, 0x0A9A, 0x0A9A, 1, 10 + i, 0x9000 + hues[j] ); + myGump.AddText( hx + 25, hy, hues[j], "0x" + hueHex ); + } + + myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 0, 1, 0 ); + myGump.AddHTMLGump( 45, 342, 80, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK + + myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 0, 0x8FFE ); + myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 40090, socket.language ) + "" ); // DONE + } + + myGump.Send( socket ); + myGump.Free(); +} + +/** @param {Character} pUser @param {Character} vendor @param {number} pButton */ +function HandleVendorClothingButton( pUser, vendor, pButton ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + if( pButton == 0x8FFF ) + { + ShowVendorCustomizeGump( pUser, vendor ); + return; + } + + if( pButton == 0x8FFE ) + { + ShowVendorClothingGump( pUser, vendor ); + return; + } + + if( pButton >= 0x7000 && pButton < ( 0x7000 + 100 ) ) + { + var removeCatIndex = pButton - 0x7000; + if( removeCatIndex >= 0 && removeCatIndex < vendorClothingCategories.length ) + { + RemoveVendorEquippedLayer( vendor, vendorClothingCategories[removeCatIndex].layer ); + ShowVendorClothingGump( pUser, vendor ); + } + return; + } + + if( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 ) ) + { + var entryVal = pButton - 0x5000; + var catIndex = Math.floor( entryVal / 100 ); + var entryIndex = entryVal % 100; + + if( catIndex >= 0 && catIndex < vendorClothingCategories.length ) + { + var cat = vendorClothingCategories[catIndex]; + if( entryIndex >= 0 && entryIndex < cat.entries.length ) + { + SetVendorClothingByLayer( vendor, cat.layer, cat.entries[entryIndex].itemID ); + ShowVendorClothingGump( pUser, vendor ); + } + } + return; + } + + if( pButton >= 0x8000 && pButton < ( 0x8000 + vendorClothingCategories.length ) ) + { + var dyeCatIndex = pButton - 0x8000; + if( dyeCatIndex >= 0 && dyeCatIndex < vendorClothingCategories.length ) + { + StoreClothingDyeCategory( pUser, dyeCatIndex ); + ShowVendorClothingDyeGump( pUser, vendor ); + } + return; + } + + if( pButton >= 0x9000 && pButton < ( 0x9000 + 0x1000 ) ) + { + var hueValue = pButton - 0x9000; + var storedCatIndex = GetStoredClothingDyeCategory( pUser ); + + if( storedCatIndex >= 0 && storedCatIndex < vendorClothingCategories.length ) + { + var dyeCat = vendorClothingCategories[storedCatIndex]; + if( dyeCat.canDye ) + SetVendorClothingHueByLayer( vendor, dyeCat.layer, hueValue ); + } + + ShowVendorClothingDyeGump( pUser, vendor ); + return; + } +} \ No newline at end of file diff --git a/data/js/server/house/playerVendorDeed.js b/data/js/server/house/playerVendorDeed.js index 47e286204..b0f7af158 100644 --- a/data/js/server/house/playerVendorDeed.js +++ b/data/js/server/house/playerVendorDeed.js @@ -8,10 +8,10 @@ function onUseChecked( pUser, iUsed ) var pSocket = pUser.socket; if( pSocket != null && ValidateObject( iUsed ) && iUsed.isItem ) { - var itemOwner = GetPackOwner( iUsed, 0 ); - if( itemOwner == null || itemOwner.serial != pUser.serial ) + // Item must be in player's backpack, not just owned by player + if( !IsItemInPlayerBackpack( iUsed, pUser )) { - pUser.SysMessage( GetDictionaryEntry( 1763, pSocket.language )); // That item must be in your backpack before it can be used. + pSocket.SysMessage( GetDictionaryEntry( 1763, pSocket.language )); // That item must be in your backpack before it can be used. return false; } @@ -20,7 +20,7 @@ function onUseChecked( pUser, iUsed ) if( !ValidateObject( iMulti ) || !iMulti.IsInMulti( pUser )) { // Player vendors can only be placed in houses! - pUser.SysMessage( GetDictionaryEntry( 2857, pSocket.language )); // Player vendors can only be placed in houses! + pSocket.SysMessage( GetDictionaryEntry( 2857, pSocket.language )); // Player vendors can only be placed in houses! return false; } @@ -28,7 +28,7 @@ function onUseChecked( pUser, iUsed ) if( !iMulti.IsOwner( pUser )) { // Only the house owner can place player vendors in a house! - pUser.SysMessage( GetDictionaryEntry( 2858, pSocket.language )); // Only the house owner can place player vendors in a house! + pSocket.SysMessage( GetDictionaryEntry( 2858, pSocket.language )); // Only the house owner can place player vendors in a house! return false; } @@ -36,7 +36,7 @@ function onUseChecked( pUser, iUsed ) if( iMulti.vendors >= iMulti.maxVendors ) { // You cannot place any more player vendors in this house! - pUser.SysMessage( GetDictionaryEntry( 2859, pSocket.language )); // You cannot place any more player vendors in this house! + pSocket.SysMessage( GetDictionaryEntry( 2859, pSocket.language )); // You cannot place any more player vendors in this house! return false; } @@ -72,6 +72,13 @@ function onUseChecked( pUser, iUsed ) // Add the player vendor to the house's list of vendors iMulti.AddVendor( npcVendor ); + npcVendor.SetTag( "VendorBankAccount",1000 ); + npcVendor.AddScriptTrigger( 3110 ); + var vendorName = iUsed.GetTag( "vendorName" ); + if( vendorName ) + { + npcVendor.name = vendorName; + } // Delete the player vendor deed! iUsed.Delete(); @@ -85,6 +92,27 @@ function onUseChecked( pUser, iUsed ) return false; } +/** @param {Item} iUsed @param {Character} pUser @returns {boolean} */ +function IsItemInPlayerBackpack( iUsed, pUser ) +{ + if( !ValidateObject( iUsed ) || !ValidateObject( pUser )) + return false; + + var pPack = pUser.pack; + if( !ValidateObject( pPack )) + return false; + + var itemOwner = GetPackOwner( iUsed, 0 ); + if( !ValidateObject( itemOwner ) || itemOwner.serial != pUser.serial ) + return false; + + var rootContainer = iUsed; + while( ValidateObject( rootContainer.container ) && rootContainer.container.isItem ) + rootContainer = rootContainer.container; + + return rootContainer.serial == pPack.serial; +} + function CheckForNearbyDoors( pUser, itemToCheck, pSocket ) { if( ValidateObject( itemToCheck )) @@ -107,7 +135,7 @@ function CheckForNearbyDoors( pUser, itemToCheck, pSocket ) // Make sure to check against the distance from the door in it's closed state, rather than it's open state! var origX = itemToCheck.x - itemToCheck.GetTag( "DOOR_X" ); var origY = itemToCheck.y - itemToCheck.GetTag( "DOOR_Y" ); - if( pUser.x - origX < 2 || origX - pUser.x < 2 || pUser.y - origY < 2 || origY - pUser.y < 2 ) + if( Math.abs( pUser.x - origX ) < 2 && Math.abs( pUser.y - origY ) < 2 ) return true; } diff --git a/docs/jsdocs.html b/docs/jsdocs.html index 1418bb6ff..c0057cc33 100644 --- a/docs/jsdocs.html +++ b/docs/jsdocs.html @@ -16704,6 +16704,10 @@

Integer Types

.visible (int, 0 - 3)
Get/Set visibility of character to other players (0 = Visible, 1 = Hidden, 2 = Magically Invisible, 3 = Visible to GMs only)

+
+

.vendorGoldHeld (int)
+ Get/Set amount of gold the vendor is holding after a player buys an item.

+

.wandertype (int, 0 - 3)
Get/Set wandertype for NPC (0 = None, [1 = Follow], 2 = Free, 3 = Box, 4 = Circle, 5 = Frozen, [6 = Flee, 7 = Pathfind]. Types 1, 6 and 7 are set primarily by code)

diff --git a/source/UOXJSPropertyEnums.h b/source/UOXJSPropertyEnums.h index 9691e62ff..025466c05 100644 --- a/source/UOXJSPropertyEnums.h +++ b/source/UOXJSPropertyEnums.h @@ -362,6 +362,7 @@ enum CC_Properties CCP_AITYPE, CCP_SPLIT, CCP_SPLITCHANCE, + CCP_VENDORGOLDHELD, CCP_TRAINER, CCP_HIRELING, CCP_WEIGHT, diff --git a/source/UOXJSPropertyFuncs.cpp b/source/UOXJSPropertyFuncs.cpp index 7f75d31d7..98c8a1d37 100644 --- a/source/UOXJSPropertyFuncs.cpp +++ b/source/UOXJSPropertyFuncs.cpp @@ -2173,6 +2173,7 @@ JSBool CCharacterProps_getProperty( JSContext *cx, JSObject *obj, jsid id, jsval case CCP_AITYPE: *vp = INT_TO_JSVAL( gPriv->GetNpcAiType() ); break; case CCP_SPLIT: *vp = INT_TO_JSVAL( gPriv->GetSplit() ); break; case CCP_SPLITCHANCE: *vp = INT_TO_JSVAL( gPriv->GetSplitChance() ); break; + case CCP_VENDORGOLDHELD:*vp = INT_TO_JSVAL( gPriv->GetHoldG() ); break; case CCP_TRAINER: *vp = BOOLEAN_TO_JSVAL( gPriv->CanTrain() ); break; case CCP_HIRELING: *vp = BOOLEAN_TO_JSVAL( gPriv->CanBeHired() ); break; case CCP_WEIGHT: *vp = INT_TO_JSVAL( gPriv->GetWeight() ); break; @@ -2688,6 +2689,7 @@ JSBool CCharacterProps_setProperty( JSContext* cx, JSObject* obj, jsid id, JSBoo case CCP_AITYPE: gPriv->SetNPCAiType( static_cast( encaps.toInt() )); break; case CCP_SPLIT: gPriv->SetSplit( static_cast( encaps.toInt() )); break; case CCP_SPLITCHANCE: gPriv->SetSplitChance( static_cast( encaps.toInt() ));break; + case CCP_VENDORGOLDHELD:gPriv->SetHoldG( static_cast( encaps.toInt() )); break; case CCP_HIRELING: gPriv->SetCanHire( encaps.toBool() ); break; case CCP_TRAINER: gPriv->SetCanTrain( encaps.toBool() ); break; case CCP_WEIGHT: gPriv->SetWeight( static_cast( encaps.toInt() )); break; diff --git a/source/UOXJSPropertySpecs.h b/source/UOXJSPropertySpecs.h index f72efb85f..d502d4305 100644 --- a/source/UOXJSPropertySpecs.h +++ b/source/UOXJSPropertySpecs.h @@ -381,6 +381,7 @@ inline JSPropertySpec CCharacterProps[] = { "aitype", CCP_AITYPE, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "split", CCP_SPLIT, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "splitchance", CCP_SPLITCHANCE, JSPROP_ENUMANDPERM, nullptr, nullptr }, + { "vendorGoldHeld", CCP_VENDORGOLDHELD, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "hireling", CCP_HIRELING, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "trainer", CCP_TRAINER, JSPROP_ENUMANDPERM, nullptr, nullptr }, { "weight", CCP_WEIGHT, JSPROP_ENUMANDPERM, nullptr, nullptr }, From a787e2425f287dc0fe948160deaf434be04bcd42 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Thu, 12 Mar 2026 11:50:53 -0500 Subject: [PATCH 02/26] changes reqwuested --- data/dictionaries/dictionary.CSY | 31 +----------------- data/dictionaries/dictionary.ENG | 28 ----------------- data/dictionaries/dictionary.FRE | 28 ----------------- data/dictionaries/dictionary.GER | 28 ----------------- data/dictionaries/dictionary.ITA | 28 ----------------- data/dictionaries/dictionary.POL | 28 ----------------- data/dictionaries/dictionary.PTG | 28 ----------------- data/dictionaries/dictionary.SPA | 28 ----------------- data/dictionaries/dictionary.ZRO | 28 ----------------- data/js/server/house/playerVendorDeed.js | 40 +++++++++++++----------- 10 files changed, 23 insertions(+), 272 deletions(-) diff --git a/data/dictionaries/dictionary.CSY b/data/dictionaries/dictionary.CSY index 275b350cc..d8bf7a6a6 100644 --- a/data/dictionaries/dictionary.CSY +++ b/data/dictionaries/dictionary.CSY @@ -5741,30 +5741,9 @@ 40044=Zakázáno 40045=HLAVNÍ 40046=PŘIZPŮSOBENÍ DODAVATELEM MENU -40047=VLASY -40048=Krátké -40049=Dlouhé -40050=Culík -40051=Mohawk -40052=Páža -40053=Kudrnaté -40054=Ustupující -40055=Dva culíky -40056=Knír -40057=Krátké vousy -40058=Krátké vousy a knír -40059=Dlouhé vousy -40060=Květina -40061=Dlouhé peří -40062=Parfinále -40063=Duplík -40064=Dlouhý cop -40065=Drdoly -40066=S hroty -40067=Středně dlouhé +40047=VLASY40058=Krátké vousy a knír 40068=Dlouhé vousy a Knír 40069=Kozí bradka -40070=Vandyke 40071=Odstranit ochlupení 40072=Barvení vlasů 40073=VOUSY @@ -5786,14 +5765,6 @@ 40089=KATEGORIE BAREV 40090=HOTOVO 40091=OBLEČENÍ BARVA -40092=Černá -40093=Béžová -40094=Zlatá -40095=Tmavě hnědá -40096=Červená -40097=Kaštanová -40098=Hnědá -40099=Světle blond 40100=Speciální fialová 40101=Speciální červená 40102=Speciální oranžová diff --git a/data/dictionaries/dictionary.ENG b/data/dictionaries/dictionary.ENG index 4cf70287e..4fa2b919a 100644 --- a/data/dictionaries/dictionary.ENG +++ b/data/dictionaries/dictionary.ENG @@ -5742,29 +5742,9 @@ 40045=MAIN 40046=VENDOR CUSTOMIZATION MENU 40047=HAIR -40048=Short -40049=Long -40050=Ponytail -40051=Mohawk -40052=Pageboy -40053=Curly -40054=Receding -40055=2-Tails -40056=Mustache -40057=Short Beard 40058=Short Beard and Mustache -40059=Long Beard -40060=Flower -40061=Long Feather -40062=Mullet -40063=Topknot -40064=Long Braid -40065=Buns -40066=Spiked -40067=Mid Long 40068=Long Beard and Mustache 40069=Goatee -40070=Vandyke 40071=Remove Hair 40072=Color Hair 40073=BEARD @@ -5786,14 +5766,6 @@ 40089=COLOR CATEGORY 40090=DONE 40091=CLOTHING COLOR -40092=Black -40093=Beige -40094=Golden -40095=Dark Brown -40096=Red -40097=Auburn -40098=Brown -40099=Blonde 40100=Special Purple 40101=Special Red 40102=Special Orange diff --git a/data/dictionaries/dictionary.FRE b/data/dictionaries/dictionary.FRE index ce9a26769..a0d68c7f4 100644 --- a/data/dictionaries/dictionary.FRE +++ b/data/dictionaries/dictionary.FRE @@ -5903,29 +5903,9 @@ 40045=PRINCIPAL 40046=PERSONNALISATION DU VENDEUR MENU 40047=CHEVEUX -40048=Courts -40049=Longs -40050=Queue de cheval -40051=Mohawk -40052=Coupe au carré -40053=Bouclés -40054=Calvé-né -40055=Deux queues de cheval -40056=Moustache -40057=Barbe courte 40058=Barbe et moustache courtes -40059=Barbe longue -40060=Fleur -40061=Longue plume -40062=Mulet -40063=Chignon haut -40064=Longue tresse -40065=Chignons -40066=Épicés -40067=Mi-longs 40068=Barbe et Moustache 40069=Bouquet -40070=Barbe Van Dyke 40071=Enlever les cheveux 40072=Colorer les cheveux 40073=Barbe @@ -5947,14 +5927,6 @@ 40089=CATÉGORIE DE COULEUR 40090=TERMINÉ 40091=VÊTEMENTS COULEUR -40092=Noir -40093=Beige -40094=Doré -40095=Brun foncé -40096=Rouge -40097=Auburn -40098=Brun -40099=Blond 40100=Violet spécial 40101=Rouge spécial 40102=Orange spécial diff --git a/data/dictionaries/dictionary.GER b/data/dictionaries/dictionary.GER index b4db55b3b..68ffaa0ce 100644 --- a/data/dictionaries/dictionary.GER +++ b/data/dictionaries/dictionary.GER @@ -5742,29 +5742,9 @@ 40045=HAUPT 40046=HÄNDLERANPASSUNG MENÜ 40047=HAAR -40048=Kurz -40049=Lang -40050=Pferdeschwanz -40051=Irokesenschnitt -40052=Pageboy -40053=Lockig -40054=Rückgang -40055=Zwei Zöpfe -40056=Schnurrbart -40057=Kurzer Bart 40058=Kurzer Bart und Schnurrbart -40059=Langer Bart -40060=Blumenfrisur -40061=Lange Federfrisur -40062=Vokuhila -40063=Dutt -40064=Langer Zopf -40065=Dutt -40066=Stachelhaarfrisur -40067=Mittellang 40068=Langer Bart und Schnurrbart Schnurrbart 40069=Ziegenbart -40070=Vandyke 40071=Haare entfernen 40072=Haare färben 40073=BART @@ -5786,14 +5766,6 @@ 40089=FARBKATEGORIE 40090=FERTIG 40091=KLEIDUNG FARBE -40092=Schwarz -40093=Beige -40094=Golden -40095=Dunkelbraun -40096=Rot -40097=Kastanienbraun -40098=Braun -40099=Blond 40100=Speziallila 40101=Spezialrot 40102=Spezialorange diff --git a/data/dictionaries/dictionary.ITA b/data/dictionaries/dictionary.ITA index 49d1b068e..6ae8345f0 100644 --- a/data/dictionaries/dictionary.ITA +++ b/data/dictionaries/dictionary.ITA @@ -5742,29 +5742,9 @@ 40045=PRINCIPALE 40046=PERSONALIZZAZIONE VENDITORE MENU 40047=CAPELLI -40048=Corti -40049=Lunghi -40050=Coda di cavallo -40051=Cresta -40052=Paggetto -40053=Ricci -40054=Sfuggenti -40055=2 code -40056=Baffi -40057=Barba corta 40058=Barba corta e baffi -40059=Barba lunga -40060=Fiore -40061=Piuma lunga -40062=Mullet -40063=Ciondolo -40064=Treccia lunga -40065=Chignon -40066=A punta -40067=Medio lungo 40068=Barba lunga e Baffi 40069=Pizzetto -40070=Vandyke 40071=Rimuovi peli 40072=Colora capelli 40073=BARBA @@ -5786,14 +5766,6 @@ 40089=CATEGORIA COLORE 40090=FATTO 40091=ABBIGLIAMENTO COLORE -40092=Nero -40093=Beige -40094=Oro -40095=Marrone scuro -40096=Rosso -40097=Castano ramato -40098=Marrone -40099=Biondo 40100=Viola speciale 40101=Rosso speciale 40102=Arancione speciale diff --git a/data/dictionaries/dictionary.POL b/data/dictionaries/dictionary.POL index a02be3ca8..b543e3dcf 100644 --- a/data/dictionaries/dictionary.POL +++ b/data/dictionaries/dictionary.POL @@ -5742,29 +5742,9 @@ 40045=GŁÓWNY 40046=DOSTOSOWANIE PRZEZ SPRZEDAWCĘ MENU 40047=WŁOSY -40048=Krótkie -40049=Długie -40050=Kucyk -40051=Irokez -40052=Pazik -40053=Kręcone -40054=Cofające się -40055=2 ogony -40056=Wąsy -40057=Krótka broda 40058=Krótka broda i wąsy -40059=Długa broda -40060=Kwiat -40061=Długie pióro -40062=Mullet -40063=Kok -40064=Długi warkocz -40065=Koki -40066=Z kolcami -40067=Średniej długości 40068=Długa broda i Wąsy 40069=Kozia bródka -40070=Vandyke 40071=Usuń włosy 40072=Kolor włosów 40073=BRODA @@ -5786,14 +5766,6 @@ 40089=KOLOR KATEGORIA 40090=GOTOWE 40091=KOLOR ODZIEŻY -40092=Czarny -40093=Beżowy -40094=Złoty -40095=Ciemnobrązowy -40096=Czerwony -40097=Kasztanowy -40098=Brązowy -40099=Blond 40100=Specjalny fioletowy 40101=Specjalny czerwony 40102=Specjalny pomarańczowy diff --git a/data/dictionaries/dictionary.PTG b/data/dictionaries/dictionary.PTG index 05a177fee..709b44c5b 100644 --- a/data/dictionaries/dictionary.PTG +++ b/data/dictionaries/dictionary.PTG @@ -5742,29 +5742,9 @@ 40045=PRINCIPAL 40046=PERSONALIZAÇÃO DO FORNECEDOR MENU 40047=CABELO -40048=Curto -40049=Longo -40050=Rabo de cavalo -40051=Moicano -40052=Cabelo chanel -40053=Cacheado -40054=Cabelo recuado -40055=Duas tranças -40056=Bigode -40057=Barba curta 40058=Barba e bigode curtos -40059=Barba comprida -40060=Flor -40061=Pena longa -40062=Mullet -40063=Coque alto -40064=Trança longa -40065=Coques -40066=Espetado -40067=Comprimento médio 40068=Barba comprida e Bigode 40069=Cavahaque -40070=Vandyke 40071=Remover Cabelo 40072=Colorir Cabelo 40073=Barba @@ -5786,14 +5766,6 @@ 40089=COR CATEGORIA 40090=CONCLUÍDO 40091=COR DA ROUPA -40092=Preto -40093=Bege -40094=Dourado -40095=Castanho Escuro -40096=Vermelho -40097=Ruivo -40098=Castanho -40099=Loiro 40100=Roxo Especial 40101=Vermelho Especial 40102=Laranja Especial diff --git a/data/dictionaries/dictionary.SPA b/data/dictionaries/dictionary.SPA index cbeee4596..774985a02 100644 --- a/data/dictionaries/dictionary.SPA +++ b/data/dictionaries/dictionary.SPA @@ -5740,29 +5740,9 @@ 40045=PRINCIPAL 40046=PERSONALIZACIÓN DEL VENDEDOR MENÚ 40047=CABELLO -40048=Corto -40049=Largo -40050=Cola de caballo -40051=Mohicano -40052=Paje -40053=Rizado -40054=Con entradas -40055=Dos colas -40056=Bigote -40057=Barba corta 40058=Barba corta y bigote -40059=Barba larga -40060=Flor -40061=Pluma larga -40062=Mullet -40063=Crochet -40064=Trenza larga -40065=Moños -40066=Puntos -40067=Media melena 40068=Barba larga y bigote Bigote 40069=Perilla -40070=Vandyke 40071=Quitar pelo 40072=Color de pelo 40073=BARBA @@ -5784,14 +5764,6 @@ 40089=COLOR CATEGORÍA 40090=HECHO 40091=COLOR DE LA ROPA -40092=Negro -40093=Beige -40094=Dorado -40095=Castaño oscuro -40096=Rojo -40097=Castaño rojizo -40098=Castaño -40099=Rubio 40100=Morado especial 40101=Rojo especial 40102=Naranja especial diff --git a/data/dictionaries/dictionary.ZRO b/data/dictionaries/dictionary.ZRO index 08b00afde..07b59052f 100644 --- a/data/dictionaries/dictionary.ZRO +++ b/data/dictionaries/dictionary.ZRO @@ -5742,29 +5742,9 @@ 40045=MAIN 40046=VENDOR CUSTOMIZATION MENU 40047=HAIR -40048=Short -40049=Long -40050=Ponytail -40051=Mohawk -40052=Pageboy -40053=Curly -40054=Receding -40055=2-Tails -40056=Mustache -40057=Short Beard 40058=Short Beard and Mustache -40059=Long Beard -40060=Flower -40061=Long Feather -40062=Mullet -40063=Topknot -40064=Long Braid -40065=Buns -40066=Spiked -40067=Mid Long 40068=Long Beard and Mustache 40069=Goatee -40070=Vandyke 40071=Remove Hair 40072=Color Hair 40073=BEARD @@ -5786,14 +5766,6 @@ 40089=COLOR CATEGORY 40090=DONE 40091=CLOTHING COLOR -40092=Black -40093=Beige -40094=Golden -40095=Dark Brown -40096=Red -40097=Auburn -40098=Brown -40099=Blonde 40100=Special Purple 40101=Special Red 40102=Special Orange diff --git a/data/js/server/house/playerVendorDeed.js b/data/js/server/house/playerVendorDeed.js index b0f7af158..7a70f9d68 100644 --- a/data/js/server/house/playerVendorDeed.js +++ b/data/js/server/house/playerVendorDeed.js @@ -8,8 +8,8 @@ function onUseChecked( pUser, iUsed ) var pSocket = pUser.socket; if( pSocket != null && ValidateObject( iUsed ) && iUsed.isItem ) { - // Item must be in player's backpack, not just owned by player - if( !IsItemInPlayerBackpack( iUsed, pUser )) + var itemOwner = GetPackOwner( iUsed, 0 ); + if( itemOwner == null || itemOwner.serial != pUser.serial || !ValidateObject( iUsed.container) || iUsed.container.layer == 0x1D ) { pSocket.SysMessage( GetDictionaryEntry( 1763, pSocket.language )); // That item must be in your backpack before it can be used. return false; @@ -56,6 +56,14 @@ function onUseChecked( pUser, iUsed ) return false; } + // Make sure there is not already an NPC on the exact tile + var foundNPC = AreaCharacterFunction( "CheckForNPCAtVendorSpot", pUser, 0, pSocket ); + if( foundNPC ) + { + pSocket.SysMessage( "You cannot place a player vendor on top of another NPC." ); + return false; + } + // Create player vendor at player's current location var npcVendor = SpawnNPC( "playervendor", pUser.x, pUser.y, pUser.z, pUser.worldnumber, pUser.instanceID ); if( ValidateObject( npcVendor )) @@ -92,25 +100,21 @@ function onUseChecked( pUser, iUsed ) return false; } -/** @param {Item} iUsed @param {Character} pUser @returns {boolean} */ -function IsItemInPlayerBackpack( iUsed, pUser ) +/** @type { ( srcChar: Character, trgChar: Character, pSocket: Socket ) => boolean } */ +function CheckForNPCAtVendorSpot( srcChar, trgChar, pSocket ) { - if( !ValidateObject( iUsed ) || !ValidateObject( pUser )) + if( !ValidateObject( srcChar ) || !ValidateObject( trgChar )) return false; - var pPack = pUser.pack; - if( !ValidateObject( pPack )) + // Ignore the player placing the vendor + if( trgChar.serial == srcChar.serial ) return false; - var itemOwner = GetPackOwner( iUsed, 0 ); - if( !ValidateObject( itemOwner ) || itemOwner.serial != pUser.serial ) - return false; - - var rootContainer = iUsed; - while( ValidateObject( rootContainer.container ) && rootContainer.container.isItem ) - rootContainer = rootContainer.container; + // Only block NPCs already standing on the exact placement tile + if( trgChar.npc && trgChar.x == srcChar.x && trgChar.y == srcChar.y && trgChar.z == srcChar.z ) + return true; - return rootContainer.serial == pPack.serial; + return false; } function CheckForNearbyDoors( pUser, itemToCheck, pSocket ) @@ -135,11 +139,11 @@ function CheckForNearbyDoors( pUser, itemToCheck, pSocket ) // Make sure to check against the distance from the door in it's closed state, rather than it's open state! var origX = itemToCheck.x - itemToCheck.GetTag( "DOOR_X" ); var origY = itemToCheck.y - itemToCheck.GetTag( "DOOR_Y" ); - if( Math.abs( pUser.x - origX ) < 2 && Math.abs( pUser.y - origY ) < 2 ) - return true; + if( Math.abs( pUser.x - origX ) < 1 && Math.abs( pUser.y - origY ) < 1 ) + return true; } - if( pUser.DistanceTo( itemToCheck ) <= 2 ) + if( pUser.DistanceTo( itemToCheck ) <= 1 ) return true; } } From c74b1e677cf7f9e763537bbe66d9d0feaa367cf1 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Thu, 12 Mar 2026 12:00:40 -0500 Subject: [PATCH 03/26] Update playervendor.js --- data/js/npc/ai/playervendor.js | 84 +++++++++++++++++----------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index e6e378a09..53d36b2f8 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -59,14 +59,14 @@ function GetVendorHueCategoryName( entry, socket ) } var vendorHairHueCategories = [ - new VendorHueCategory( null, [ 0x044E, 0x044F, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454 ], 40092 ), // Black - new VendorHueCategory( null, [ 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C ], 40093 ), // Beige - new VendorHueCategory( null, [ 0x045D, 0x045E, 0x045F, 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468, 0x0469, 0x046A, 0x046B, 0x046C ], 40094 ), // Golden - new VendorHueCategory( null, [ 0x046D, 0x046E, 0x046F, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478, 0x0479, 0x047A, 0x047B, 0x047C ], 40095 ), // Dark Brown - new VendorHueCategory( null, [ 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7, 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF, 0x04C0 ], 40096 ), // Red - new VendorHueCategory( null, [ 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC ], 40097 ), // Auburn - new VendorHueCategory( null, [ 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0657, 0x0658, 0x0659, 0x065A, 0x065B, 0x065C, 0x065D, 0x065E, 0x065F, 0x0660 ], 40098 ), // Brown - new VendorHueCategory( null, [ 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, 0x0961, 0x0962, 0x0963, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968 ], 40099 ), // Blonde + new VendorHueCategory( null, [ 0x044E, 0x044F, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454 ], 17111 ), // Black + new VendorHueCategory( null, [ 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C ], 17112 ), // Beige + new VendorHueCategory( null, [ 0x045D, 0x045E, 0x045F, 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468, 0x0469, 0x046A, 0x046B, 0x046C ], 17113 ), // Golden + new VendorHueCategory( null, [ 0x046D, 0x046E, 0x046F, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478, 0x0479, 0x047A, 0x047B, 0x047C ], 17114 ), // Dark Brown + new VendorHueCategory( null, [ 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7, 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF, 0x04C0 ], 17108 ), // Red + new VendorHueCategory( null, [ 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC ], 17105 ), // Auburn + new VendorHueCategory( null, [ 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0657, 0x0658, 0x0659, 0x065A, 0x065B, 0x065C, 0x065D, 0x065E, 0x065F, 0x0660 ], 17103 ), // Brown + new VendorHueCategory( null, [ 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, 0x0961, 0x0962, 0x0963, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968 ], 17110 ), // Blonde new VendorHueCategory( null, [ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ], 40100 ), // Special Purple new VendorHueCategory( null, [ 32, 33, 34, 35, 36, 37 ], 40101 ), // Special Red new VendorHueCategory( null, [ 38, 39, 40, 41, 42, 43, 44, 45, 46 ], 40102 ), // Special Orange @@ -95,47 +95,47 @@ function GetHairOrBeardName( entry, socket ) } var femaleElfHairStyles = [ - new HairOrBeard( 0x2FCC, null, 40060 ), // Flower - new HairOrBeard( 0x2FC0, null, 40061 ), // Long Feather - new HairOrBeard( 0x2FC1, null, 40048 ), // Short - new HairOrBeard( 0x2FC2, null, 40062 ), // Mullet - new HairOrBeard( 0x2FCE, null, 40063 ), // Topknot - new HairOrBeard( 0x2FCF, null, 40064 ), // Long Braid - new HairOrBeard( 0x2FD0, null, 40065 ), // Buns - new HairOrBeard( 0x2FD1, null, 40066 ) // Spiked + new HairOrBeard( 0x2FCC, null, 18035 ), // Flower + new HairOrBeard( 0x2FC0, null, 18028 ), // Long Feather + new HairOrBeard( 0x2FC1, null, 18029 ), // Short + new HairOrBeard( 0x2FC2, null, 18030 ), // Mullet + new HairOrBeard( 0x2FCE, null, 18032 ), // Topknot + new HairOrBeard( 0x2FCF, null, 18033 ), // Long Braid + new HairOrBeard( 0x2FD0, null, 18036 ), // Buns + new HairOrBeard( 0x2FD1, null, 18034 ) // Spiked ]; var maleElfHairStyles = [ - new HairOrBeard( 0x2FBF, null, 40067 ), // Mid Long - new HairOrBeard( 0x2FC0, null, 40061 ), // Long Feather - new HairOrBeard( 0x2FC1, null, 40048 ), // Short - new HairOrBeard( 0x2FC2, null, 40062 ), // Mullet - new HairOrBeard( 0x2FCE, null, 40063 ), // Topknot - new HairOrBeard( 0x2FCF, null, 40064 ), // Long Braid - new HairOrBeard( 0x2FCD, null, 40049 ), // Long - new HairOrBeard( 0x2FD1, null, 40066 ) // Spiked + new HairOrBeard( 0x2FBF, null, 18027 ), // Mid Long + new HairOrBeard( 0x2FC0, null, 18028 ), // Long Feather + new HairOrBeard( 0x2FC1, null, 18029 ), // Short + new HairOrBeard( 0x2FC2, null, 18030 ), // Mullet + new HairOrBeard( 0x2FCE, null, 18032 ), // Topknot + new HairOrBeard( 0x2FCF, null, 18033 ), // Long Braid + new HairOrBeard( 0x2FCD, null, 18031 ), // Long + new HairOrBeard( 0x2FD1, null, 18034 ) // Spiked ]; var humanHairStyles = [ - new HairOrBeard( 0x203B, null, 40048 ), // Short - new HairOrBeard( 0x203C, null, 40049 ), // Long - new HairOrBeard( 0x203D, null, 40050 ), // Ponytail - new HairOrBeard( 0x2044, null, 40051 ), // Mohawk - new HairOrBeard( 0x2045, null, 40052 ), // Pageboy - new HairOrBeard( 0x204A, null, 40063 ), // Topknot - new HairOrBeard( 0x2047, null, 40053 ), // Curly - new HairOrBeard( 0x2048, null, 40054 ), // Receding - new HairOrBeard( 0x2049, null, 40055 ) // 2-Tails + new HairOrBeard( 0x203B, null, 18029 ), // Short + new HairOrBeard( 0x203C, null, 18031 ), // Long + new HairOrBeard( 0x203D, null, 2086 ), // Ponytail + new HairOrBeard( 0x2044, null, 2087 ), // Mohawk + new HairOrBeard( 0x2045, null, 2080 ), // Pageboy + new HairOrBeard( 0x204A, null, 18032 ), // Topknot + new HairOrBeard( 0x2047, null, 2088 ), // Curly + new HairOrBeard( 0x2048, null, 2081 ), // Receding + new HairOrBeard( 0x2049, null, 2082 ) // 2-Tails ]; var humanBeardStyles = [ - new HairOrBeard( 0x2041, null, 40056 ), // Mustache - new HairOrBeard( 0x203F, null, 40057 ), // Short Beard + new HairOrBeard( 0x2041, null, 18001 ), // Mustache + new HairOrBeard( 0x203F, null, 18002 ), // Short Beard new HairOrBeard( 0x204B, null, 40058 ), // Short Beard and Mustache - new HairOrBeard( 0x203E, null, 40059 ), // Long Beard + new HairOrBeard( 0x203E, null, 18005 ), // Long Beard new HairOrBeard( 0x204C, null, 40068 ), // Long Beard and Mustache new HairOrBeard( 0x2040, null, 40069 ), // Goatee - new HairOrBeard( 0x204D, null, 40070 ) // Vandyke + new HairOrBeard( 0x204D, null, 18000 ) // Vandyke ]; /** @constructor @param {number} itemID @param {string} name */ @@ -560,24 +560,24 @@ function PlaceItemForOwnerOrDrop( itemObj, pUser, vendor ) if( !ValidateObject( itemObj ) || !ValidateObject( pUser ) || !ValidateObject( vendor )) return 0; - var bankBox; - var pPack; + var bankBox = GetBankBox( pUser ); + var pPack = pUser.pack; if( onlyReturnToBank ) { - bankBox = GetBankBox( pUser ); if( ValidateObject( bankBox ) && TryMoveItemToContainer( itemObj, bankBox )) return 2; + if( ValidateObject( pPack ) && TryMoveItemToContainer( itemObj, pPack )) + return 1; + DropItemAtVendorLocation( itemObj, vendor ); return 3; } - pPack = pUser.pack; if( ValidateObject( pPack ) && TryMoveItemToContainer( itemObj, pPack )) return 1; - bankBox = GetBankBox( pUser ); if( ValidateObject( bankBox ) && TryMoveItemToContainer( itemObj, bankBox )) return 2; From ffa1c24666fa68a5397415916a1ec05ca163b185 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:38:48 -0500 Subject: [PATCH 04/26] update missing options --- data/dictionaries/dictionary.CSY | 16 ++- data/dictionaries/dictionary.ENG | 13 +- data/dictionaries/dictionary.FRE | 15 ++- data/dictionaries/dictionary.GER | 13 +- data/dictionaries/dictionary.ITA | 15 ++- data/dictionaries/dictionary.POL | 13 +- data/dictionaries/dictionary.PTG | 15 ++- data/dictionaries/dictionary.SPA | 15 ++- data/dictionaries/dictionary.ZRO | 13 +- data/js/npc/ai/playervendor.js | 220 ++++++++++++++++++++++++++++--- 10 files changed, 318 insertions(+), 30 deletions(-) diff --git a/data/dictionaries/dictionary.CSY b/data/dictionaries/dictionary.CSY index d8bf7a6a6..7555fb95c 100644 --- a/data/dictionaries/dictionary.CSY +++ b/data/dictionaries/dictionary.CSY @@ -5726,7 +5726,7 @@ 40029=Zobrazit zboží 40030=Přizpůsobit 40031=Sbírat zlato -40032=Vložit 1000 +40032=Vložit zlato 40033=Vyprázdnit účet 40034=Zavřít 40035=Počet dnů, které mohu pracovat: @@ -5741,7 +5741,19 @@ 40044=Zakázáno 40045=HLAVNÍ 40046=PŘIZPŮSOBENÍ DODAVATELEM MENU -40047=VLASY40058=Krátké vousy a knír +40047=VLASY +40048=Přejmenovat prodejce +40049=Přejmenovat obchod +40050=Zadejte nový název prodejce. +40051=Zadejte nový název obchodu. +40052=Zadejte množství zlata, které chcete vložit. +40053=Toto není platný hráčský prodejce. +40054=Váš prodejce je nyní pojmenován: %s +40055=Název obchodu je příliš dlouhý. Maximálně 40 znaků. +40056=Název vašeho obchodu je nyní: %s +40057=Musíte zadat platné množství zlata. +40058=Krátké vousy a knír +40059=Z tohoto domu nemůžete nakupovat, protože vám byl do tohoto podniku zakázán vstup. 40068=Dlouhé vousy a Knír 40069=Kozí bradka 40071=Odstranit ochlupení diff --git a/data/dictionaries/dictionary.ENG b/data/dictionaries/dictionary.ENG index 4fa2b919a..58145daf6 100644 --- a/data/dictionaries/dictionary.ENG +++ b/data/dictionaries/dictionary.ENG @@ -5726,7 +5726,7 @@ 40029=See goods 40030=Customize 40031=Collect Gold -40032=Deposit 1000 +40032=Deposit Gold 40033=Flush Bank 40034=Dismiss 40035=Amount of days I can work: @@ -5742,7 +5742,18 @@ 40045=MAIN 40046=VENDOR CUSTOMIZATION MENU 40047=HAIR +40048=Rename Vendor +40049=Rename Shop +40050=Enter a new vendor name. +40051=Enter a new shop name. +40052=Enter the amount of gold you wish to deposit. +40053=That is not a valid player vendor. +40054=Your vendor is now named: %s +40055=That shop name is too long. Maximum 40 chars. +40056=Your shop title is now: %s +40057=You must enter a valid gold amount. 40058=Short Beard and Mustache +40059=You can't shop from this home as you have been banned from this establishment. 40068=Long Beard and Mustache 40069=Goatee 40071=Remove Hair diff --git a/data/dictionaries/dictionary.FRE b/data/dictionaries/dictionary.FRE index a0d68c7f4..5a97244e1 100644 --- a/data/dictionaries/dictionary.FRE +++ b/data/dictionaries/dictionary.FRE @@ -5887,7 +5887,7 @@ 40028=Je ne travaille pas pour vous ! 40029=Voir les articles 40030=Personnaliser 40031=Collecter de l'or -40032=Déposer 1000 +40032=Déposer de l'or 40033=Vider la banque 40034=Annuler 40035=Nombre de jours ouvrables : @@ -5903,7 +5903,18 @@ 40045=PRINCIPAL 40046=PERSONNALISATION DU VENDEUR MENU 40047=CHEVEUX -40058=Barbe et moustache courtes +40048=Renommer le vendeur +40049=Renommer la boutique +40050=Saisissez un nouveau nom de vendeur. +40051=Saisissez un nouveau nom de boutique. +40052=Saisissez le montant d'or que vous souhaitez déposer. +40053=Ce n'est pas un vendeur de joueur valide. +40054=Votre vendeur s'appelle désormais : %s +40055=Ce nom de boutique est trop long. Maximum 40 caractères. +40056=Le titre de votre boutique est désormais : %s +40057=Vous devez saisir un montant d'or valide. +40058=Barbe courte et moustache +40059=Vous ne pouvez pas faire d'achats dans cette demeure, car vous avez été banni de cet établissement. 40068=Barbe et Moustache 40069=Bouquet 40071=Enlever les cheveux diff --git a/data/dictionaries/dictionary.GER b/data/dictionaries/dictionary.GER index 68ffaa0ce..27d188e18 100644 --- a/data/dictionaries/dictionary.GER +++ b/data/dictionaries/dictionary.GER @@ -5726,7 +5726,7 @@ 40029=Waren ansehen 40030=Anpassen 40031=Gold sammeln -40032=1000 einzahlen +40032=Gold einzahlen 40033=Bank leeren 40034=Schließen 40035=Anzahl der Tage, an denen ich arbeiten kann: @@ -5742,7 +5742,18 @@ 40045=HAUPT 40046=HÄNDLERANPASSUNG MENÜ 40047=HAAR +40048=Händler umbenennen +40049=Laden umbenennen +40050=Geben Sie einen neuen Händlernamen ein. +40051=Geben Sie einen neuen Ladennamen ein. +40052=Geben Sie die Menge an Gold ein, die Sie einzahlen möchten. +40053=Dies ist kein gültiger Spielerhändler. +40054=Ihr Händler heißt nun: %s +40055=Dieser Ladenname ist zu lang. Maximal 40 Zeichen. +40056=Ihr Ladentitel lautet nun: %s +40057=Sie müssen einen gültigen Goldbetrag eingeben. 40058=Kurzer Bart und Schnurrbart +40059=Sie können in diesem Heim keine Einkäufe tätigen, da Sie von dieser Einrichtung ausgeschlossen wurden. 40068=Langer Bart und Schnurrbart Schnurrbart 40069=Ziegenbart 40071=Haare entfernen diff --git a/data/dictionaries/dictionary.ITA b/data/dictionaries/dictionary.ITA index 6ae8345f0..7a11ca9de 100644 --- a/data/dictionaries/dictionary.ITA +++ b/data/dictionaries/dictionary.ITA @@ -5726,7 +5726,7 @@ 40029=Vedi beni 40030=Personalizza 40031=Raccogli oro -40032=Deposita 1000 +40032=Deposita oro 40033=Svuota banca 40034=Ignora 40035=Numero di giorni in cui posso lavorare: @@ -5742,7 +5742,18 @@ 40045=PRINCIPALE 40046=PERSONALIZZAZIONE VENDITORE MENU 40047=CAPELLI -40058=Barba corta e baffi +40048=Rinomina venditore +40049=Rinomina negozio +40050=Inserisci un nuovo nome per il venditore. +40051=Inserisci un nuovo nome per il negozio. +40052=Inserisci la quantità d'oro che desideri depositare. +40053=Non è un venditore gestito da un giocatore valido. +40054=Il tuo venditore ora si chiama: %s +40055=Il nome del negozio è troppo lungo. Massimo 40 caratteri. +40056=Il titolo del tuo negozio ora è: %s +40057=Devi inserire una quantità d'oro valida. +40058=Barba e baffi corti +40059=Non puoi fare acquisti in questa abitazione, poiché sei stato bandito da questa struttura. 40068=Barba lunga e Baffi 40069=Pizzetto 40071=Rimuovi peli diff --git a/data/dictionaries/dictionary.POL b/data/dictionaries/dictionary.POL index b543e3dcf..fbba62e46 100644 --- a/data/dictionaries/dictionary.POL +++ b/data/dictionaries/dictionary.POL @@ -5726,7 +5726,7 @@ 40029=Zobacz towary 40030=Dostosuj 40031=Odbierz złoto -40032=Wpłać 1000 +40032=Wpłać złoto 40033=Opróżnij bank 40034=Odrzuć 40035=Liczba dni, w których mogę pracować: @@ -5742,7 +5742,18 @@ 40045=GŁÓWNY 40046=DOSTOSOWANIE PRZEZ SPRZEDAWCĘ MENU 40047=WŁOSY +40048=Zmień nazwę handlarza +40049=Zmień nazwę sklepu +40050=Wpisz nową nazwę handlarza. +40051=Wpisz nową nazwę sklepu. +40052=Wpisz ilość złota, którą chcesz wpłacić. +40053=To nie jest poprawny handlarz gracza. +40054=Twój handlarz nazywa się teraz: %s +40055=Ta nazwa sklepu jest zbyt długa. Maksymalnie 40 znaków. +40056=Tytuł twojego sklepu brzmi teraz: %s +40057=Musisz wpisać poprawną ilość złota. 40058=Krótka broda i wąsy +40059=Nie możesz robić zakupów w tym domu, ponieważ otrzymałeś zakaz wstępu do tego lokalu. 40068=Długa broda i Wąsy 40069=Kozia bródka 40071=Usuń włosy diff --git a/data/dictionaries/dictionary.PTG b/data/dictionaries/dictionary.PTG index 709b44c5b..e6fdf3e77 100644 --- a/data/dictionaries/dictionary.PTG +++ b/data/dictionaries/dictionary.PTG @@ -5726,7 +5726,7 @@ 40029=Ver mercadorias 40030=Personalizar 40031=Coletar Ouro -40032=Depositar 1000 +40032=Depositar Ouro 40033=Levantar dinheiro 40034=Dispensar 40035=Nº de dias que posso trabalhar: @@ -5742,7 +5742,18 @@ 40045=PRINCIPAL 40046=PERSONALIZAÇÃO DO FORNECEDOR MENU 40047=CABELO -40058=Barba e bigode curtos +40048=Renomear Vendedor +40049=Renomear Loja +40050=Introduza um novo nome para o vendedor. +40051=Introduza um novo nome para a loja. +40052=Introduza a quantidade de ouro que pretende depositar. +40053=Este não é um vendedor de jogadores válido. +40054=O seu vendedor chama-se agora: %s +40055=O nome da loja é demasiado longo. Máximo de 40 caracteres. +40056=O nome da sua loja é agora: %s +40057=Tem de introduzir uma quantidade de ouro válida. +40058=Barba e Bigode Curtos +40059=Não pode comprar nesta casa, pois foi banido deste estabelecimento. 40068=Barba comprida e Bigode 40069=Cavahaque 40071=Remover Cabelo diff --git a/data/dictionaries/dictionary.SPA b/data/dictionaries/dictionary.SPA index 774985a02..8825c8904 100644 --- a/data/dictionaries/dictionary.SPA +++ b/data/dictionaries/dictionary.SPA @@ -5724,7 +5724,7 @@ 40028=¡No trabajo para ti! 40029=Ver artículos 40030=Personalizar 40031=Recoger oro -40032=Depositar 1000 +40032=Depositar oro 40033=Fluir banco 40034=Descartar 40035=Días que puedo trabajar: @@ -5740,7 +5740,18 @@ 40045=PRINCIPAL 40046=PERSONALIZACIÓN DEL VENDEDOR MENÚ 40047=CABELLO -40058=Barba corta y bigote +40048=Cambiar nombre de vendedor +40049=Cambiar nombre de tienda +40050=Introduce un nuevo nombre de vendedor. +40051=Introduce un nuevo nombre de tienda. +40052=Introduce la cantidad de oro que deseas depositar. +40053=Ese vendedor no es válido para el jugador. +40054=Tu vendedor ahora se llama: %s +40055=El nombre de la tienda es demasiado largo. Máximo 40 caracteres. +40056=El nombre de tu tienda ahora es: %s +40057=Debes introducir una cantidad válida de oro. +40058=Barba y bigote cortos +40059=No puedes comprar en esta casa porque has sido expulsado del establecimiento. 40068=Barba larga y bigote Bigote 40069=Perilla 40071=Quitar pelo diff --git a/data/dictionaries/dictionary.ZRO b/data/dictionaries/dictionary.ZRO index 07b59052f..3e74a121c 100644 --- a/data/dictionaries/dictionary.ZRO +++ b/data/dictionaries/dictionary.ZRO @@ -5726,7 +5726,7 @@ 40029=See goods 40030=Customize 40031=Collect Gold -40032=Deposit 1000 +40032=Deposit Gold 40033=Flush Bank 40034=Dismiss 40035=Amount of days I can work: @@ -5742,7 +5742,18 @@ 40045=MAIN 40046=VENDOR CUSTOMIZATION MENU 40047=HAIR +40048=Rename Vendor +40049=Rename Shop +40050=Enter a new vendor name. +40051=Enter a new shop name. +40052=Enter the amount of gold you wish to deposit. +40053=That is not a valid player vendor. +40054=Your vendor is now named: %s +40055=That shop name is too long. Maximum 40 chars. +40056=Your shop title is now: %s +40057=You must enter a valid gold amount. 40058=Short Beard and Mustache +40059=You can't shop from this home as you have been banned from this establishment. 40068=Long Beard and Mustache 40069=Goatee 40071=Remove Hair diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 53d36b2f8..48ab0b736 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -952,8 +952,8 @@ function ShowPlayerVendorOwnerGump( socket, vendor ) var myGump = new Gump; myGump.AddPage( 0 ); - myGump.AddBackground( 25, 10, 555, 190, 5054 ); - myGump.AddCheckerTrans( 32, 20, 537, 170 ); + myGump.AddBackground( 25, 10, 555, 240, 5054 ); + myGump.AddCheckerTrans( 32, 20, 537, 220 ); myGump.NoResize(); myGump.AddButton( 390, 25, 4005, 4007, 1, 0, 1 ); @@ -962,20 +962,26 @@ function ShowPlayerVendorOwnerGump( socket, vendor ) myGump.AddButton( 390, 48, 4005, 4007, 1, 0, 2 ); myGump.AddHTMLGump( 425, 48, 120, 20, false, false, "" + GetDictionaryEntry( 40030, socket.language ) + "" ); // Customize - myGump.AddButton( 390, 71, 4005, 4007, 1, 0, 3 ); - myGump.AddHTMLGump( 425, 72, 120, 20, false, false, "" + GetDictionaryEntry( 40031, socket.language ) + "" ); // Collect Gold + myGump.AddButton( 390, 71, 4005, 4007, 1, 0, 7 ); + myGump.AddHTMLGump( 425, 72, 120, 20, false, false, "" + GetDictionaryEntry( 40048, socket.language ) + "" ); // Rename Vendor - myGump.AddButton( 390, 94, 4005, 4007, 1, 0, 4 ); - myGump.AddHTMLGump( 425, 95, 120, 20, false, false, "" + GetDictionaryEntry( 40032, socket.language ) + "" ); // Deposit 1000 + myGump.AddButton( 390, 94, 4005, 4007, 1, 0, 8 ); + myGump.AddHTMLGump( 425, 95, 120, 20, false, false, "" + GetDictionaryEntry( 40049, socket.language ) + "" ); // Rename Shop - myGump.AddButton( 390, 117, 4005, 4007, 1, 0, 5 ); - myGump.AddHTMLGump( 425, 118, 120, 20, false, false, "" + GetDictionaryEntry( 40033, socket.language ) + "" ); // Flush Bank + myGump.AddButton( 390, 117, 4005, 4007, 1, 0, 3 ); + myGump.AddHTMLGump( 425, 118, 120, 20, false, false, "" + GetDictionaryEntry( 40031, socket.language ) + "" ); // Collect Gold - myGump.AddButton( 390, 140, 4005, 4007, 1, 0, 6 ); - myGump.AddHTMLGump( 425, 141, 120, 20, false, false, "" + GetDictionaryEntry( 40034, socket.language ) + "" ); // Dismiss + myGump.AddButton( 390, 140, 4005, 4007, 1, 0, 4 ); + myGump.AddHTMLGump( 425, 141, 120, 20, false, false, "" + GetDictionaryEntry( 40032, socket.language ) + "" ); // Deposit 1000 - myGump.AddButton( 390, 163, 4005, 4007, 1, 0, 0 ); - myGump.AddHTMLGump( 425, 164, 120, 20, false, false, "" + GetDictionaryEntry( 18762, socket.language ) + "" ); // CANCEL + myGump.AddButton( 390, 163, 4005, 4007, 1, 0, 5 ); + myGump.AddHTMLGump( 425, 164, 120, 20, false, false, "" + GetDictionaryEntry( 40033, socket.language ) + "" ); // Flush Bank + + myGump.AddButton( 390, 186, 4005, 4007, 1, 0, 6 ); + myGump.AddHTMLGump( 425, 187, 120, 20, false, false, "" + GetDictionaryEntry( 40034, socket.language ) + "" ); // Dismiss + + myGump.AddButton( 390, 209, 4005, 4007, 1, 0, 0 ); + myGump.AddHTMLGump( 425, 210, 120, 20, false, false, "" + GetDictionaryEntry( 18762, socket.language ) + "" ); // CANCEL if( !vendorChargesEnabled ) { @@ -1421,6 +1427,13 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "view" || cmd == "browse" || cmd == "look" ) { + if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser )) + { + if( pUser.socket ) + pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); // You can't shop from this home as you have been banned from this establishment. + return 2; + } + if( !CheckVendorUpkeep( vendor, pUser )) return 2; @@ -1430,6 +1443,13 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "buy" || cmd == "purchase" ) { + if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser )) + { + if( pUser.socket ) + pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); // You can't shop from this home as you have been banned from this establishment. + return 2; + } + if( !CheckVendorUpkeep( vendor, pUser )) return 2; @@ -1511,6 +1531,13 @@ function onCharDoubleClick( pUser, targChar, nonMouseClickEvent ) return false; } + if( ValidateObject( targChar.multi ) && targChar.multi.IsOnBanList( pUser )) + { + if( pUser.socket ) + pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); // You can't shop from this home as you have been banned from this establishment. + return false; + } + OpenVendorBackpack( pUser, targChar ); return false; } @@ -1640,8 +1667,7 @@ function onGumpPress( pSock, pButton, gumpData ) ShowPlayerVendorOwnerGump( pSock, vendor ); break; case 4: - DepositToVendorBank( pUser, vendor, 1000 ); - ShowPlayerVendorOwnerGump( pSock, vendor ); + BeginDepositVendorGold( pUser, vendor ); break; case 5: FlushBankToHeld( pUser, vendor ); @@ -1651,7 +1677,10 @@ function onGumpPress( pSock, pButton, gumpData ) DismissVendor( pUser, vendor ); break; case 7: - ShowVendorClothingGump( pUser, vendor ); + BeginRenameVendor( pUser, vendor ); + break; + case 8: + BeginRenameVendorShop( pUser, vendor ); break; default: break; @@ -1752,7 +1781,7 @@ function ShowVendorCustomizeGump( pUser, vendor ) for( i = 0; i < humanBeardStyles.length; ++i ) { myGump.AddButton( 160, 70 + ( i * 20 ), 0xFA5, 0xFA7, 1, 1, 0x2000 + i ); - myGump.AddHTMLGump( 195, 72 + ( i * 20 ), 160, 18, false, false, "" + GetHairOrBeardName( hairStyles[i], socket ) + "" ); + myGump.AddHTMLGump( 195, 72 + ( i * 20 ), 160, 18, false, false, "" + GetHairOrBeardName( humanBeardStyles[i], socket ) + "" ); } myGump.AddButton( 160, 70 + ( humanBeardStyles.length * 20 ), 0xFB1, 0xFB3, 1, 1, 5004 ); @@ -2315,4 +2344,163 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) ShowVendorClothingDyeGump( pUser, vendor ); return; } +} + +/** @param {string} text @returns {string} */ +function TrimString( text ) +{ + if( text == null || text == undefined ) + return ""; + + return ( "" + text ).replace( /^\s+|\s+$/g, "" ); +} + +/** @param {Character} vendor @returns {string} */ +function GetVendorShopTitle( vendor ) +{ + if( !IsPlayerVendor( vendor )) + return ""; + + if( vendor.title == null || vendor.title == undefined ) + return ""; + + return "" + vendor.title; +} + +/** @param {Character} pUser @param {Character} vendor */ +function BeginRenameVendor( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + StoreVendorForGump( pUser, vendor ); + pUser.SpeechInput( 20, vendor ); + socket.SysMessage( GetDictionaryEntry( 40050, socket.language )); // Enter a new vendor name. +} + +/** @param {Character} pUser @param {Character} vendor */ +function BeginRenameVendorShop( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + StoreVendorForGump( pUser, vendor ); + pUser.SpeechInput( 21, vendor ); + socket.SysMessage( GetDictionaryEntry( 40051, socket.language )); // Enter a new shop name. +} + +/** @param {Character} pUser @param {Character} vendor */ +function BeginDepositVendorGold( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + StoreVendorForGump( pUser, vendor ); + pUser.SpeechInput( 22, vendor ); + socket.SysMessage( GetDictionaryEntry( 40052, socket.language )); // Enter the amount of gold you wish to deposit. +} + +/** @type { ( myChar: Character, targObj: BaseObject, mySpeech: string, mySpeechId: number ) => void } */ +function onSpeechInput( pUser, targObj, pSpeech, pSpeechID ) +{ + if( !ValidateObject( pUser )) + return; + + var socket = pUser.socket; + if( !socket ) + return; + + var vendor = GetStoredVendorForGump( pUser ); + if( !IsPlayerVendor( vendor )) + { + socket.SysMessage( GetDictionaryEntry( 40053, socket.language )); // That is not a valid player vendor. + return; + } + + if( !IsVendorOwner( vendor, pUser )) + { + socket.SysMessage( GetDictionaryEntry( 40028, socket.language )); // I don't work for you! + return; + } + + if( !CheckVendorUpkeep( vendor, pUser )) + return; + + var newText = TrimString( pSpeech ); + if( newText == "" ) + { + socket.SysMessage( GetDictionaryEntry( 9270, socket.language )); // That name is too short, or no name was entered. + return; + } + + switch( pSpeechID ) + { + case 20: // Rename vendor + if( newText.length > 50 ) + { + socket.SysMessage( GetDictionaryEntry( 9271, socket.language )); // That name is too long. Maximum 50 chars. + return; + } + + vendor.name = newText; + vendor.Refresh(); + + socket.SysMessage( GetDictionaryEntry( 40054, socket.language ), vendor.name ); // Your vendor is now named: %s + ShowPlayerVendorOwnerGump( socket, vendor ); + break; + + case 21: // Rename shop title + if( newText.length > 40 ) + { + socket.SysMessage( GetDictionaryEntry( 40055, socket.language )); // That shop name is too long. Maximum 40 chars. + return; + } + + vendor.title = "Shop Name: " + newText; + vendor.Refresh(); + socket.SysMessage( GetDictionaryEntry( 40056, socket.language ), vendor.title ); // Your shop title is now: %s + ShowPlayerVendorOwnerGump( socket, vendor ); + break; + case 22: // Deposit vendor gold + if( !/^\d+$/.test( newText )) + { + socket.SysMessage( GetDictionaryEntry( 40057, socket.language )); // You must enter a valid gold amount. + return; + } + + var depositAmount = parseInt( newText, 10 ); + if( isNaN( depositAmount ) || depositAmount <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 40018, socket.language )); // Invalid deposit amount. + return; + } + + DepositToVendorBank( pUser, vendor, depositAmount ); + ShowPlayerVendorOwnerGump( socket, vendor ); + break; + + default: + break; + } } \ No newline at end of file From 483474f5226e4081eca0cadc5af585b27d1d3bef Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Fri, 13 Mar 2026 11:49:38 -0500 Subject: [PATCH 05/26] cycle vendor --- data/js/npc/ai/playervendor.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 48ab0b736..0108c5300 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -1357,6 +1357,18 @@ function DismissVendor( pUser, vendor ) FinalizeVendorRemoval( vendor ); } +/** @param {Character} pUser @param {Character} vendor */ +function CycleVendorDirection( pUser, vendor ) +{ + if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + return; + + if( !IsVendorOwner( vendor, pUser )) + return; + + vendor.direction = ( vendor.direction + 1 ) % 8; +} + /** @param {string} speech @returns {string} */ function NormalizeSpeech( speech ) { @@ -1412,6 +1424,9 @@ function MatchVendorCommand( pUser, vendor, speech ) if( cmd == "dismiss" || cmd == "replace" ) return true; + if( cmd == "vendor cycle" || cmd == "cycle" ) + return true; + return false; } @@ -1503,6 +1518,18 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) return 2; } + if( cmd == "vendor cycle" || cmd == "cycle" ) + { + if( !IsVendorOwner( vendor, pUser )) + { + vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + return 2; + } + + CycleVendorDirection( pUser, vendor ); + return 2; + } + return 0; } From 3dcf096369d705aa6306ddd8ecaa829314d4a889 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Wed, 18 Mar 2026 15:55:44 -0500 Subject: [PATCH 06/26] huge cleanup condensed the code down not so many helper functions --- data/js/npc/ai/playervendor.js | 2021 ++++++++++++-------------------- 1 file changed, 777 insertions(+), 1244 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 0108c5300..4fdf29d61 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -20,28 +20,28 @@ var vendorUseItemFees = true; // Add item-based fee from listed item prices var vendorItemFeeDivisor = 500; // 3 gold per 500 worth of one item var vendorItemFeeAmount = 3; // Fee added per divisor step -var layerOneHand = 0x01; -var layerTwoHand = 0x02; -var layerShoes = 0x03; -var layerPants = 0x04; -var layerShirt = 0x05; -var layerHelm = 0x06; -var layerGloves = 0x07; -var layerRing = 0x08; -var layerNeck = 0x0A; -var layerHair = 0x0B; -var layerWaist = 0x0C; -var layerInnerTorso = 0x0D; -var layerBracelet = 0x0E; -var layerBeard = 0x10; -var layerMiddleTorso = 0x11; -var layerEarrings = 0x12; -var layerArms = 0x13; -var layerCloak = 0x14; -var layerOuterTorso = 0x16; -var layerOuterLegs = 0x17; - -/** @constructor @param {string|null} name @param {number[] } hues @param {number|null} dictID */ +var layerOneHand = 0x01; +var layerTwoHand = 0x02; +var layerShoes = 0x03; +var layerPants = 0x04; +var layerShirt = 0x05; +var layerHelm = 0x06; +var layerGloves = 0x07; +var layerRing = 0x08; +var layerNeck = 0x0A; +var layerHair = 0x0B; +var layerWaist = 0x0C; +var layerInnerTorso = 0x0D; +var layerBracelet = 0x0E; +var layerBeard = 0x10; +var layerMiddleTorso = 0x11; +var layerEarrings = 0x12; +var layerArms = 0x13; +var layerCloak = 0x14; +var layerOuterTorso = 0x16; +var layerOuterLegs = 0x17; + +/** @constructor @param {string|null} name @param {number[]} hues @param {number|null} dictID */ function VendorHueCategory( name, hues, dictID ) { this.name = name; @@ -49,6 +49,31 @@ function VendorHueCategory( name, hues, dictID ) this.dictID = dictID; } +/** @constructor @param {number} itemID @param {string|null} name @param {number=} dictID */ +function HairOrBeard( itemID, name, dictID ) +{ + this.itemID = itemID; + this.name = name; + this.dictID = dictID; +} + +/** @constructor @param {number} itemID @param {string} name */ +function VendorClothingEntry( itemID, name ) +{ + this.itemID = itemID; + this.name = name; +} + +/** @constructor @param {number} layer @param {string} name @param {boolean} canDye @param {VendorClothingEntry[]} entries @param {boolean=} compactLayout */ +function VendorClothingCategory( layer, name, canDye, entries, compactLayout ) +{ + this.layer = layer; + this.name = name; + this.canDye = canDye; + this.entries = entries; + this.compactLayout = compactLayout ? true : false; +} + /** @param {VendorHueCategory} entry @param {Socket|null} socket @returns {string} */ function GetVendorHueCategoryName( entry, socket ) { @@ -58,6 +83,15 @@ function GetVendorHueCategoryName( entry, socket ) return entry.name || ""; } +/** @param {HairOrBeard} entry @param {Socket} socket @returns {string} */ +function GetHairOrBeardName( entry, socket ) +{ + if( entry.dictID ) + return GetDictionaryEntry( entry.dictID, socket.language ); + + return entry.name || ""; +} + var vendorHairHueCategories = [ new VendorHueCategory( null, [ 0x044E, 0x044F, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454 ], 17111 ), // Black new VendorHueCategory( null, [ 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C ], 17112 ), // Beige @@ -77,23 +111,6 @@ var vendorHairHueCategories = [ new VendorHueCategory( null, [ 1153, 1154, 1155 ], 40107 ) // Special Ice White ]; -/** @constructor @param {number} itemID @param {string} name */ -function HairOrBeard( itemID, name, dictID ) -{ - this.itemID = itemID; - this.name = name; - this.dictID = dictID; -} - -/** @param {HairOrBeard} entry @param {Socket} socket @returns {string} */ -function GetHairOrBeardName( entry, socket ) -{ - if( entry.dictID ) - return GetDictionaryEntry( entry.dictID, socket.language ); - - return entry.name || ""; -} - var femaleElfHairStyles = [ new HairOrBeard( 0x2FCC, null, 18035 ), // Flower new HairOrBeard( 0x2FC0, null, 18028 ), // Long Feather @@ -138,23 +155,6 @@ var humanBeardStyles = [ new HairOrBeard( 0x204D, null, 18000 ) // Vandyke ]; -/** @constructor @param {number} itemID @param {string} name */ -function VendorClothingEntry( itemID, name ) -{ - this.itemID = itemID; - this.name = name; -} - -/** @constructor @param {number} layer @param {string} name @param {boolean} canDye @param {VendorClothingEntry[]} entries @param {boolean=} compactLayout*/ -function VendorClothingCategory( layer, name, canDye, entries, compactLayout ) -{ - this.layer = layer; - this.name = name; - this.canDye = canDye; - this.entries = entries; - this.compactLayout = compactLayout ? true : false; -} - var vendorClothingCategories = [ new VendorClothingCategory( layerInnerTorso, "Upper Torso", true, [ new VendorClothingEntry( 0x1517, "Shirt" ), @@ -225,145 +225,27 @@ var vendorClothingCategories = [ ], true) ]; -/** @param {Character} vendor @returns {boolean} */ -function IsPlayerVendor( vendor ) -{ - return ValidateObject( vendor ) && vendor.aitype == 17; -} - -/** @param {Character} vendor @param {Character} pUser @returns {boolean} */ -function IsVendorOwner( vendor, pUser ) -{ - if( !IsPlayerVendor( vendor ) || !ValidateObject( pUser )) - return false; - - if( !ValidateObject( vendor.owner )) - return false; - - return vendor.owner.serial == pUser.serial; -} - -/** @param {Character} vendor @returns {number} */ -function GetVendorHeldGold( vendor ) -{ - if( !IsPlayerVendor( vendor )) - return 0; - - return vendor.vendorGoldHeld || 0; -} - -/** @param {Character} vendor @param {number} amount */ -function SetVendorHeldGold( vendor, amount ) -{ - if( !IsPlayerVendor( vendor )) - return; - - if( amount < 0 ) - amount = 0; - - vendor.vendorGoldHeld = amount; -} - -/** @param {Character} vendor @returns {number} */ -function GetVendorBankAccount( vendor ) -{ - if( !IsPlayerVendor( vendor )) - return 0; - - var bankAccount = vendor.GetTag( "VendorBankAccount" ); - if( bankAccount < 0 ) - return 0; - - return bankAccount; -} - -/** @param {Character} vendor @param {number} amount */ -function SetVendorBankAccount( vendor, amount ) -{ - if( !IsPlayerVendor( vendor )) - return; - - if( amount < 0 ) - amount = 0; - - vendor.SetTag( "VendorBankAccount", amount ); -} - -/** @returns {number} */ -function GetCurrentTimestamp() -{ - return Math.floor( GetCurrentClock() / 1000 ); -} - -/** @param {Character} vendor @returns {number} */ -function GetVendorTotalFunds( vendor ) -{ - return GetVendorHeldGold( vendor ) + GetVendorBankAccount( vendor ); -} - -/** @param {Character} vendor @returns {number} */ -function GetVendorLastChargeTime( vendor ) -{ - if( !IsPlayerVendor( vendor )) - return 0; - - return vendor.GetTag( "VendorLastChargeTime" ); -} - -/** @param {Character} vendor @param {number} timestamp */ -function SetVendorLastChargeTime( vendor, timestamp ) -{ - if( !IsPlayerVendor( vendor )) - return; - - vendor.SetTag( "VendorLastChargeTime", timestamp ); -} - -/** @param {Item} itemObj @returns {number} */ -function GetVendorItemPrice( itemObj ) -{ - if( !ValidateObject( itemObj )) - return 0; - - // Adjust this if your vendor sale price is stored elsewhere - if( itemObj.buyValue > 0 ) - return itemObj.buyValue; - - return 0; -} - /** @param {Item} itemObj @returns {number} */ function GetVendorItemPeriodFee( itemObj ) { - if( !ValidateObject( itemObj )) - return 0; - - var itemPrice = GetVendorItemPrice( itemObj ); - if( itemPrice <= 0 ) + if( !ValidateObject( itemObj ) || itemObj.buyValue <= 0 || !vendorUseItemFees || vendorItemFeeDivisor <= 0 || vendorItemFeeAmount <= 0 ) return 0; - return Math.floor( itemPrice / vendorItemFeeDivisor ) * vendorItemFeeAmount; + return Math.floor( itemObj.buyValue / vendorItemFeeDivisor ) * vendorItemFeeAmount; } /** @param {Character} vendor @returns {number} */ function GetVendorItemFeeTotal( vendor ) { - if( !IsPlayerVendor( vendor )) - return 0; - - var vendorPack = vendor.pack; - if( !ValidateObject( vendorPack )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || !ValidateObject( vendor.pack ) ) return 0; var totalFee = 0; - var packItem = vendorPack.FirstItem(); - - for( ; !vendorPack.FinishedItems(); packItem = vendorPack.NextItem() ) + var packItem = vendor.pack.FirstItem(); + for( ; !vendor.pack.FinishedItems(); packItem = vendor.pack.NextItem() ) { - if( !ValidateObject( packItem )) - continue; - - totalFee += GetVendorItemPeriodFee( packItem ); + if( ValidateObject( packItem ) ) + totalFee += GetVendorItemPeriodFee( packItem ); } return totalFee; @@ -372,106 +254,94 @@ function GetVendorItemFeeTotal( vendor ) /** @param {Character} vendor @returns {number} */ function GetVendorChargePerPeriod( vendor ) { - if( !IsPlayerVendor( vendor )) - return 0; - - if( !vendorChargesEnabled ) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || !vendorChargesEnabled ) return 0; var overrideValue = vendor.GetTag( "VendorChargePerPeriod" ); if( overrideValue > 0 ) return overrideValue; - var totalCharge = vendorBaseCharge; - - if( vendorUseItemFees ) - totalCharge += GetVendorItemFeeTotal( vendor ); - - return totalCharge; + return vendorBaseCharge + ( vendorUseItemFees ? GetVendorItemFeeTotal( vendor ) : 0 ); } /** @param {Character} vendor @param {number} amount @returns {number} */ function DepositVendorBankGold( vendor, amount ) { - if( !IsPlayerVendor( vendor ) || amount <= 0 ) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || amount <= 0 ) return 0; - var bankAccount = GetVendorBankAccount( vendor ); - var roomLeft = vendorMaxFunds - bankAccount; + var bankGold = vendor.GetTag( "VendorBankAccount" ); + if( bankGold < 0 ) + bankGold = 0; + var roomLeft = vendorMaxFunds - bankGold; if( roomLeft <= 0 ) return 0; if( amount > roomLeft ) amount = roomLeft; - SetVendorBankAccount( vendor, bankAccount + amount ); + vendor.SetTag( "VendorBankAccount", bankGold + amount ); return amount; } /** @param {Character} vendor @param {number} amount @returns {number} */ function WithdrawVendorBankGold( vendor, amount ) { - if( !IsPlayerVendor( vendor ) || amount <= 0 ) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || amount <= 0 ) return 0; - var bankAccount = GetVendorBankAccount( vendor ); - if( amount > bankAccount ) - amount = bankAccount; + var bankGold = vendor.GetTag( "VendorBankAccount" ); + if( bankGold < 0 ) + bankGold = 0; - SetVendorBankAccount( vendor, bankAccount - amount ); + if( amount > bankGold ) + amount = bankGold; + + vendor.SetTag( "VendorBankAccount", bankGold - amount ); return amount; } /** @param {Character} vendor @param {number} charge @returns {boolean} */ function PayVendorCharge( vendor, charge ) { - if( !IsPlayerVendor( vendor ) || charge <= 0 ) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || charge <= 0 ) return false; - var bankAccount = GetVendorBankAccount( vendor ); - var heldGold = GetVendorHeldGold( vendor ); + var bankGold = vendor.GetTag( "VendorBankAccount" ); + var heldGold = vendor.vendorGoldHeld || 0; + + if( bankGold < 0 ) + bankGold = 0; - if(( bankAccount + heldGold ) < charge ) + if(( bankGold + heldGold ) < charge ) return false; - if( bankAccount >= charge ) + if( bankGold >= charge ) { - SetVendorBankAccount( vendor, bankAccount - charge ); + vendor.SetTag( "VendorBankAccount", bankGold - charge ); return true; } - charge -= bankAccount; - SetVendorBankAccount( vendor, 0 ); - SetVendorHeldGold( vendor, heldGold - charge ); + charge -= bankGold; + vendor.SetTag( "VendorBankAccount", 0 ); + vendor.vendorGoldHeld = heldGold - charge; return true; } -/** @param {Character} vendor @param {number} amount @returns {number} */ -function MoveBankToHeldGold( vendor, amount ) -{ - if( !IsPlayerVendor( vendor ) || amount <= 0 ) - return 0; - - var bankAccount = GetVendorBankAccount( vendor ); - if( amount > bankAccount ) - amount = bankAccount; - - SetVendorBankAccount( vendor, bankAccount - amount ); - SetVendorHeldGold( vendor, GetVendorHeldGold( vendor ) + amount ); - return amount; -} - /** @param {Character} vendor @returns {number} */ function FlushVendorBankToHeldGold( vendor ) { - var bankAccount = GetVendorBankAccount( vendor ); - if( bankAccount <= 0 ) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return 0; - SetVendorBankAccount( vendor, 0 ); - SetVendorHeldGold( vendor, GetVendorHeldGold( vendor ) + bankAccount ); - return bankAccount; + var bankGold = vendor.GetTag( "VendorBankAccount" ); + if( bankGold <= 0 ) + return 0; + + vendor.SetTag( "VendorBankAccount", 0 ); + vendor.vendorGoldHeld = ( vendor.vendorGoldHeld || 0 ) + bankGold; + return bankGold; } /** @param {Character} vendor @returns {number} */ @@ -481,7 +351,19 @@ function GetVendorPeriodsAffordable( vendor ) if( perPeriod <= 0 ) return 0; - return Math.floor( GetVendorTotalFunds( vendor ) / perPeriod ); + var bankGold = 0; + var heldGold = 0; + + if( ValidateObject( vendor ) && vendor.aitype == 17 ) + { + bankGold = vendor.GetTag( "VendorBankAccount" ); + heldGold = vendor.vendorGoldHeld || 0; + + if( bankGold < 0 ) + bankGold = 0; + } + + return Math.floor(( bankGold + heldGold ) / perPeriod ); } /** @param {Character} vendor @returns {number} */ @@ -493,14 +375,13 @@ function GetVendorHoursAffordable( vendor ) /** @param {Character} vendor @returns {number} */ function GetVendorDaysAffordable( vendor ) { - var hoursAffordable = GetVendorHoursAffordable( vendor ); - return Math.floor( hoursAffordable / 24 ); + return Math.floor( GetVendorHoursAffordable( vendor ) / 24 ); } /** @param {Item} itemObj @param {Character} vendor */ function DropItemAtVendorLocation( itemObj, vendor ) { - if( !ValidateObject( itemObj ) || !ValidateObject( vendor )) + if( !ValidateObject( itemObj ) || !ValidateObject( vendor ) ) return; itemObj.container = null; @@ -511,75 +392,47 @@ function DropItemAtVendorLocation( itemObj, vendor ) itemObj.instanceID = vendor.instanceID; } -/** @param {Character} pUser @returns {Item|null} */ -function GetBankBox( pUser ) -{ - if( !ValidateObject( pUser )) - return null; - - var bankBox = pUser.FindItemLayer( 29 ); - if( !ValidateObject( bankBox )) - return null; - - return bankBox; -} - -/** @param {Item} container @param {Item} itemObj @returns {boolean} */ -function CanContainerReceiveItem( container, itemObj ) +/** @param {Item} itemObj @param {Item} container @returns {boolean} */ +function TryMoveItemToContainer( itemObj, container ) { - if( !ValidateObject( container ) || !ValidateObject( itemObj )) + if( !ValidateObject( itemObj ) || !ValidateObject( container ) ) return false; if( container.totalItemCount >= container.maxItems ) return false; - var itemWeight = itemObj.weight * itemObj.amount; - if(( container.weight + itemWeight ) > container.weightMax ) - return false; - - return true; -} - -/** @param {Item} itemObj @param {Item} container @returns {boolean} */ -function TryMoveItemToContainer( itemObj, container ) -{ - if( !ValidateObject( itemObj ) || !ValidateObject( container )) - return false; - - if( !CanContainerReceiveItem( container, itemObj )) + if(( container.weight + ( itemObj.weight * itemObj.amount ) ) > container.weightMax ) return false; itemObj.container = container; - return ValidateObject( itemObj.container ) && itemObj.container.serial == container.serial; } /** @param {Item} itemObj @param {Character} pUser @param {Character} vendor @returns {number} */ function PlaceItemForOwnerOrDrop( itemObj, pUser, vendor ) { - if( !ValidateObject( itemObj ) || !ValidateObject( pUser ) || !ValidateObject( vendor )) + if( !ValidateObject( itemObj ) || !ValidateObject( pUser ) || !ValidateObject( vendor ) ) return 0; - var bankBox = GetBankBox( pUser ); - var pPack = pUser.pack; + var pack = pUser.pack; + var bankBox = pUser.FindItemLayer( 29 ); if( onlyReturnToBank ) { - if( ValidateObject( bankBox ) && TryMoveItemToContainer( itemObj, bankBox )) + if( TryMoveItemToContainer( itemObj, bankBox ) ) return 2; - if( ValidateObject( pPack ) && TryMoveItemToContainer( itemObj, pPack )) + if( TryMoveItemToContainer( itemObj, pack ) ) return 1; - - DropItemAtVendorLocation( itemObj, vendor ); - return 3; } + else + { + if( TryMoveItemToContainer( itemObj, pack ) ) + return 1; - if( ValidateObject( pPack ) && TryMoveItemToContainer( itemObj, pPack )) - return 1; - - if( ValidateObject( bankBox ) && TryMoveItemToContainer( itemObj, bankBox )) - return 2; + if( TryMoveItemToContainer( itemObj, bankBox ) ) + return 2; + } DropItemAtVendorLocation( itemObj, vendor ); return 3; @@ -590,29 +443,20 @@ function ReturnVendorItemsToOwner( vendor, pUser ) { var results = { pack:0, bank:0, ground:0 }; - if( !IsPlayerVendor( vendor ) || !ValidateObject( pUser )) - return results; - - var vendorPack = vendor.pack; - if( !ValidateObject( vendorPack )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || !ValidateObject( pUser ) || !ValidateObject( vendor.pack ) ) return results; var itemList = []; - var packItem = vendorPack.FirstItem(); - - for( ; !vendorPack.FinishedItems(); packItem = vendorPack.NextItem() ) + var packItem = vendor.pack.FirstItem(); + for( ; !vendor.pack.FinishedItems(); packItem = vendor.pack.NextItem() ) { - if( ValidateObject( packItem )) + if( ValidateObject( packItem ) ) itemList.push( packItem ); } for( var i = 0; i < itemList.length; ++i ) { - var moveItem = itemList[i]; - if( !ValidateObject( moveItem )) - continue; - - var placeResult = PlaceItemForOwnerOrDrop( moveItem, pUser, vendor ); + var placeResult = PlaceItemForOwnerOrDrop( itemList[i], pUser, vendor ); if( placeResult == 1 ) results.pack++; else if( placeResult == 2 ) @@ -627,27 +471,19 @@ function ReturnVendorItemsToOwner( vendor, pUser ) /** @param {Character} vendor @returns {number} */ function DropVendorItemsAtLocation( vendor ) { - if( !IsPlayerVendor( vendor )) - return 0; - - var vendorPack = vendor.pack; - if( !ValidateObject( vendorPack )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 || !ValidateObject( vendor.pack ) ) return 0; var itemList = []; - var packItem = vendorPack.FirstItem(); - - for( ; !vendorPack.FinishedItems(); packItem = vendorPack.NextItem() ) + var packItem = vendor.pack.FirstItem(); + for( ; !vendor.pack.FinishedItems(); packItem = vendor.pack.NextItem() ) { - if( ValidateObject( packItem )) + if( ValidateObject( packItem ) ) itemList.push( packItem ); } for( var i = 0; i < itemList.length; ++i ) - { - if( ValidateObject( itemList[i] )) - DropItemAtVendorLocation( itemList[i], vendor ); - } + DropItemAtVendorLocation( itemList[i], vendor ); return itemList.length; } @@ -655,72 +491,64 @@ function DropVendorItemsAtLocation( vendor ) /** @param {Character} vendor @returns {Item|null} */ function CreateVendorDismissDeedAtLocation( vendor ) { - if( !IsPlayerVendor( vendor )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return null; - var tempName = "A vendor deed for " + vendor.name + "."; - var pvDeed = CreateBlankItem( null, vendor, 1, tempName, 0x14F0, 0x0, "ITEM", false ); - if( !ValidateObject( pvDeed )) + var deed = CreateBlankItem( null, vendor, 1, "A vendor deed for " + vendor.name + ".", 0x14F0, 0x0, "ITEM", false ); + if( !ValidateObject( deed ) ) return null; - pvDeed.type = 217; - pvDeed.buyValue = 2000; - pvDeed.SetTag( "vendorName", vendor.name ); - - DropItemAtVendorLocation( pvDeed, vendor ); - return pvDeed; + deed.type = 217; + deed.buyValue = 2000; + deed.SetTag( "vendorName", vendor.name ); + DropItemAtVendorLocation( deed, vendor ); + return deed; } /** @param {Character} pUser @param {Character} vendor @returns {Item|null} */ function CreateVendorDismissDeedForOwner( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) return null; - var socket = pUser.socket; - var tempName; - - if( socket ) + var deedName = "A vendor deed for " + vendor.name + "."; + if( pUser.socket ) { - tempName = GetDictionaryEntry( 580, socket.language ); - tempName = tempName.replace( /%s/gi, vendor.name ); - } - else - { - tempName = "A vendor deed for " + vendor.name + "."; + deedName = GetDictionaryEntry( 580, pUser.socket.language ); + deedName = deedName.replace( /%s/gi, vendor.name ); } - var pvDeed = CreateBlankItem( null, pUser, 1, tempName, 0x14F0, 0x0, "ITEM", false ); - if( !ValidateObject( pvDeed )) + var deed = CreateBlankItem( null, pUser, 1, deedName, 0x14F0, 0x0, "ITEM", false ); + if( !ValidateObject( deed ) ) return null; - pvDeed.type = 217; - pvDeed.buyValue = 2000; - pvDeed.SetTag( "vendorName", vendor.name ); - - return pvDeed; + deed.type = 217; + deed.buyValue = 2000; + deed.SetTag( "vendorName", vendor.name ); + return deed; } /** @param {Character} vendor @returns {number} */ function DropVendorGoldAtLocation( vendor ) { - if( !IsPlayerVendor( vendor )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return 0; - var holdGold = GetVendorHeldGold( vendor ); - var bankGold = GetVendorBankAccount( vendor ); - var totalGold = holdGold + bankGold; + var heldGold = vendor.vendorGoldHeld || 0; + var bankGold = vendor.GetTag( "VendorBankAccount" ); + if( bankGold < 0 ) + bankGold = 0; + var totalGold = heldGold + bankGold; if( totalGold <= 0 ) return 0; var goldItem = CreateDFNItem( null, vendor, "0x0EED", totalGold, "ITEM", false ); - if( !ValidateObject( goldItem )) + if( !ValidateObject( goldItem ) ) return 0; - SetVendorHeldGold( vendor, 0 ); - SetVendorBankAccount( vendor, 0 ); - + vendor.vendorGoldHeld = 0; + vendor.SetTag( "VendorBankAccount", 0 ); DropItemAtVendorLocation( goldItem, vendor ); return totalGold; } @@ -730,26 +558,28 @@ function ReturnVendorGoldToOwner( pUser, vendor ) { var result = { amount:0, location:0 }; - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) return result; - var holdGold = GetVendorHeldGold( vendor ); - var bankGold = GetVendorBankAccount( vendor ); - var totalGold = holdGold + bankGold; + var heldGold = vendor.vendorGoldHeld || 0; + var bankGold = vendor.GetTag( "VendorBankAccount" ); + if( bankGold < 0 ) + bankGold = 0; + var totalGold = heldGold + bankGold; if( totalGold <= 0 ) return result; var goldItem = CreateDFNItem( null, pUser, "0x0EED", totalGold, "ITEM", false ); - if( !ValidateObject( goldItem )) + if( !ValidateObject( goldItem ) ) return result; var placeResult = PlaceItemForOwnerOrDrop( goldItem, pUser, vendor ); if( placeResult == 0 ) return result; - SetVendorHeldGold( vendor, 0 ); - SetVendorBankAccount( vendor, 0 ); + vendor.vendorGoldHeld = 0; + vendor.SetTag( "VendorBankAccount", 0 ); result.amount = totalGold; result.location = placeResult; @@ -759,15 +589,11 @@ function ReturnVendorGoldToOwner( pUser, vendor ) /** @param {Character} vendor */ function FinalizeVendorRemoval( vendor ) { - if( !IsPlayerVendor( vendor )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return; - var iMulti = null; - if( ValidateObject( vendor.multi )) - iMulti = vendor.multi; - - if( ValidateObject( iMulti )) - iMulti.RemoveVendor( vendor ); + if( ValidateObject( vendor.multi ) ) + vendor.multi.RemoveVendor( vendor ); vendor.Delete(); } @@ -775,57 +601,50 @@ function FinalizeVendorRemoval( vendor ) /** @param {Character} vendor @param {Character|null} notifyChar */ function RemoveVendorForNoFunds( vendor, notifyChar ) { - if( !IsPlayerVendor( vendor )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return; - var ownerChar = null; - if( ValidateObject( vendor.owner )) - ownerChar = vendor.owner; - + var ownerChar = ValidateObject( vendor.owner ) ? vendor.owner : null; if( ValidateObject( ownerChar ) && ownerChar.socket ) { - var socket = ownerChar.socket; - socket.SysMessage( GetDictionaryEntry( 40000, socket.language ), vendor.name ); // %s can no longer afford upkeep and has been dismissed. + var ownerSocket = ownerChar.socket; + ownerSocket.SysMessage( GetDictionaryEntry( 40000, ownerSocket.language ), vendor.name ); - var pvDeed = CreateVendorDismissDeedForOwner( ownerChar, vendor ); - if( !ValidateObject( pvDeed )) + var deed = CreateVendorDismissDeedForOwner( ownerChar, vendor ); + if( !ValidateObject( deed ) ) { - socket.SysMessage( GetDictionaryEntry( 40001, socket.language )); // Unable to create vendor deed. Vendor dismissal aborted. + ownerSocket.SysMessage( GetDictionaryEntry( 40001, ownerSocket.language ) ); return; } var itemResults = ReturnVendorItemsToOwner( vendor, ownerChar ); var goldResult = ReturnVendorGoldToOwner( ownerChar, vendor ); - var deedLocation = PlaceItemForOwnerOrDrop( pvDeed, ownerChar, vendor ); + var deedLocation = PlaceItemForOwnerOrDrop( deed, ownerChar, vendor ); if(( itemResults.pack + itemResults.bank + itemResults.ground ) > 0 ) { if( onlyReturnToBank ) - { - socket.SysMessage( GetDictionaryEntry( 40002, socket.language ), itemResults.bank, itemResults.ground ); // Vendor items returned - bank: %i, ground: %i. - } + ownerSocket.SysMessage( GetDictionaryEntry( 40002, ownerSocket.language ), itemResults.bank, itemResults.ground ); else - { - socket.SysMessage( GetDictionaryEntry( 40003, socket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); // Vendor items returned - pack: %i, bank: %i, ground: %i. - } + ownerSocket.SysMessage( GetDictionaryEntry( 40003, ownerSocket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); } if( goldResult.amount > 0 ) { if( goldResult.location == 1 ) - socket.SysMessage( GetDictionaryEntry( 40004, socket.language ), goldResult.amount ); // Returned %i gold to your pack. + ownerSocket.SysMessage( GetDictionaryEntry( 40004, ownerSocket.language ), goldResult.amount ); else if( goldResult.location == 2 ) - socket.SysMessage( GetDictionaryEntry( 40005, socket.language ), goldResult.amount ); // Returned %i gold to your bank box. + ownerSocket.SysMessage( GetDictionaryEntry( 40005, ownerSocket.language ), goldResult.amount ); else if( goldResult.location == 3 ) - socket.SysMessage( GetDictionaryEntry( 40006, socket.language ), goldResult.amount ); // Dropped %i gold at vendor location. + ownerSocket.SysMessage( GetDictionaryEntry( 40006, ownerSocket.language ), goldResult.amount ); } if( deedLocation == 1 ) - socket.SysMessage( GetDictionaryEntry( 40007, socket.language )); // Placed vendor deed in your pack. + ownerSocket.SysMessage( GetDictionaryEntry( 40007, ownerSocket.language ) ); else if( deedLocation == 2 ) - socket.SysMessage( GetDictionaryEntry( 40008, socket.language )); // Placed vendor deed in your bank box. + ownerSocket.SysMessage( GetDictionaryEntry( 40008, ownerSocket.language ) ); else if( deedLocation == 3 ) - socket.SysMessage( GetDictionaryEntry( 40009, socket.language )); // Dropped vendor deed at vendor location. + ownerSocket.SysMessage( GetDictionaryEntry( 40009, ownerSocket.language ) ); FinalizeVendorRemoval( vendor ); return; @@ -833,20 +652,21 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) var itemCount = DropVendorItemsAtLocation( vendor ); var totalGold = DropVendorGoldAtLocation( vendor ); - var pvDeedOffline = CreateVendorDismissDeedAtLocation( vendor ); + var offlineDeed = CreateVendorDismissDeedAtLocation( vendor ); if( ValidateObject( notifyChar ) && notifyChar.socket ) { - notifyChar.socket.SysMessage( GetDictionaryEntry( 40010, notifyChar.socket.language ), vendor.name ); // %s could not afford upkeep and was dismissed. + var notifySocket = notifyChar.socket; + notifySocket.SysMessage( GetDictionaryEntry( 40010, notifySocket.language ), vendor.name ); if( itemCount > 0 ) - notifyChar.socket.SysMessage( GetDictionaryEntry( 40011, notifyChar.socket.language ), itemCount ); // Dropped %i vendor item(s) at vendor location. + notifySocket.SysMessage( GetDictionaryEntry( 40011, notifySocket.language ), itemCount ); if( totalGold > 0 ) - notifyChar.socket.SysMessage( GetDictionaryEntry( 40006, notifyChar.socket.language ), totalGold ); // Dropped %i gold at vendor location. + notifySocket.SysMessage( GetDictionaryEntry( 40006, notifySocket.language ), totalGold ); - if( ValidateObject( pvDeedOffline )) - notifyChar.socket.SysMessage( GetDictionaryEntry( 40009, notifyChar.socket.language )); // Dropped vendor deed at vendor location. + if( ValidateObject( offlineDeed ) ) + notifySocket.SysMessage( GetDictionaryEntry( 40009, notifySocket.language ) ); } FinalizeVendorRemoval( vendor ); @@ -855,68 +675,64 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) /** @param {Character} vendor @param {Character|null} notifyChar @returns {boolean} */ function CheckVendorUpkeep( vendor, notifyChar ) { - if( !IsPlayerVendor( vendor )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return false; if( !vendorChargesEnabled ) return true; - var currentTime = GetCurrentTimestamp(); - var lastChargeTime = GetVendorLastChargeTime( vendor ); var chargeInterval = vendorChargeHours * 60 * 60; - if( chargeInterval <= 0 ) return true; + var currentTime = Math.floor( GetCurrentClock() / 1000 ); + var lastChargeTime = vendor.GetTag( "VendorLastChargeTime" ); + if( lastChargeTime <= 0 ) { - SetVendorLastChargeTime( vendor, currentTime ); + vendor.SetTag( "VendorLastChargeTime", currentTime ); return true; } if( currentTime <= lastChargeTime ) return true; - var elapsed = currentTime - lastChargeTime; - var periodsOwed = Math.floor( elapsed / chargeInterval ); - + var periodsOwed = Math.floor(( currentTime - lastChargeTime ) / chargeInterval ); if( periodsOwed <= 0 ) return true; for( var i = 0; i < periodsOwed; ++i ) { - if( !PayVendorCharge( vendor, GetVendorChargePerPeriod( vendor ))) + if( !PayVendorCharge( vendor, GetVendorChargePerPeriod( vendor ) ) ) { RemoveVendorForNoFunds( vendor, notifyChar ); return false; } } - SetVendorLastChargeTime( vendor, lastChargeTime + ( periodsOwed * chargeInterval )); + vendor.SetTag( "VendorLastChargeTime", lastChargeTime + ( periodsOwed * chargeInterval ) ); return true; } /** @param {Character} pUser @param {Character} vendor */ function StoreVendorForGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) - return; - - pUser.SetTempTag( "PlayerVendorGumpSerial", vendor.serial ); + if( ValidateObject( pUser ) && ValidateObject( vendor ) && vendor.aitype == 17 ) + pUser.SetTempTag( "PlayerVendorGumpSerial", vendor.serial ); } /** @param {Character} pUser @returns {Character|null} */ function GetStoredVendorForGump( pUser ) { - if( !ValidateObject( pUser )) + if( !ValidateObject( pUser ) ) return null; - var vendorSerial = pUser.GetTempTag( "PlayerVendorGumpSerial" ); - if( !vendorSerial ) + var serial = pUser.GetTempTag( "PlayerVendorGumpSerial" ); + if( !serial ) return null; - var vendor = CalcCharFromSer( vendorSerial ); - if( !IsPlayerVendor( vendor )) + var vendor = CalcCharFromSer( serial ); + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) return null; return vendor; @@ -925,171 +741,56 @@ function GetStoredVendorForGump( pUser ) /** @param {Character} pUser @param {Character} vendor */ function OpenVendorBackpack( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket || !ValidateObject( vendor.pack ) ) return; - var socket = pUser.socket; - if( !socket ) - return; - - var pPack = vendor.pack; - if( ValidateObject( pPack )) - socket.OpenContainer( pPack ); + pUser.socket.OpenContainer( vendor.pack ); } -/** @param {Socket} socket @param {Character} vendor */ -function ShowPlayerVendorOwnerGump( socket, vendor ) +/** @param {Character} pUser @returns {number} */ +function GetPackGoldAmount( pUser ) { - if( !socket || !IsPlayerVendor( vendor )) - return; - - var holdGold = GetVendorHeldGold( vendor ); - var bankAccount = GetVendorBankAccount( vendor ); - var perPeriod = GetVendorChargePerPeriod( vendor ); - var days = GetVendorDaysAffordable( vendor ); - var hours = GetVendorHoursAffordable( vendor ); - var itemFeeTotal = GetVendorItemFeeTotal( vendor ); - - var myGump = new Gump; - myGump.AddPage( 0 ); - myGump.AddBackground( 25, 10, 555, 240, 5054 ); - myGump.AddCheckerTrans( 32, 20, 537, 220 ); - myGump.NoResize(); - - myGump.AddButton( 390, 25, 4005, 4007, 1, 0, 1 ); - myGump.AddHTMLGump( 425, 25, 120, 20, false, false, "" + GetDictionaryEntry( 40029, socket.language ) + "" ); // See goods + if( !ValidateObject( pUser ) || !ValidateObject( pUser.pack ) ) + return 0; - myGump.AddButton( 390, 48, 4005, 4007, 1, 0, 2 ); - myGump.AddHTMLGump( 425, 48, 120, 20, false, false, "" + GetDictionaryEntry( 40030, socket.language ) + "" ); // Customize + var totalGold = 0; + var itemObj = pUser.pack.FirstItem(); + for( ; !pUser.pack.FinishedItems(); itemObj = pUser.pack.NextItem() ) + { + if( ValidateObject( itemObj ) && itemObj.id == 0x0EED ) + totalGold += itemObj.amount; + } - myGump.AddButton( 390, 71, 4005, 4007, 1, 0, 7 ); - myGump.AddHTMLGump( 425, 72, 120, 20, false, false, "" + GetDictionaryEntry( 40048, socket.language ) + "" ); // Rename Vendor + return totalGold; +} - myGump.AddButton( 390, 94, 4005, 4007, 1, 0, 8 ); - myGump.AddHTMLGump( 425, 95, 120, 20, false, false, "" + GetDictionaryEntry( 40049, socket.language ) + "" ); // Rename Shop +/** @param {Character} pUser @param {number} amount @returns {boolean} */ +function RemoveGoldFromPack( pUser, amount ) +{ + if( !ValidateObject( pUser ) || amount <= 0 || !ValidateObject( pUser.pack ) ) + return false; - myGump.AddButton( 390, 117, 4005, 4007, 1, 0, 3 ); - myGump.AddHTMLGump( 425, 118, 120, 20, false, false, "" + GetDictionaryEntry( 40031, socket.language ) + "" ); // Collect Gold + if( GetPackGoldAmount( pUser ) < amount ) + return false; - myGump.AddButton( 390, 140, 4005, 4007, 1, 0, 4 ); - myGump.AddHTMLGump( 425, 141, 120, 20, false, false, "" + GetDictionaryEntry( 40032, socket.language ) + "" ); // Deposit 1000 - - myGump.AddButton( 390, 163, 4005, 4007, 1, 0, 5 ); - myGump.AddHTMLGump( 425, 164, 120, 20, false, false, "" + GetDictionaryEntry( 40033, socket.language ) + "" ); // Flush Bank - - myGump.AddButton( 390, 186, 4005, 4007, 1, 0, 6 ); - myGump.AddHTMLGump( 425, 187, 120, 20, false, false, "" + GetDictionaryEntry( 40034, socket.language ) + "" ); // Dismiss - - myGump.AddButton( 390, 209, 4005, 4007, 1, 0, 0 ); - myGump.AddHTMLGump( 425, 210, 120, 20, false, false, "" + GetDictionaryEntry( 18762, socket.language ) + "" ); // CANCEL - - if( !vendorChargesEnabled ) - { - myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); // Amount of days I can work: - myGump.AddText( 300, 25, 2603, GetDictionaryEntry( 40043, socket.language ) ); // Unlimited - - myGump.AddHTMLGump( 40, 48, 260, 20, false, false, "" + GetDictionaryEntry( 40036, socket.language ) + "" ); // Hours I can work: - myGump.AddText( 300, 48, 2603, GetDictionaryEntry( 40043, socket.language ) ); // Unlimited - - myGump.AddHTMLGump( 40, 72, 260, 20, false, false, "" + GetDictionaryEntry( 40037, socket.language ) + "" ); // Gold held for you: - myGump.AddText( 300, 72, 1153, "" + holdGold ); - - myGump.AddHTMLGump( 40, 96, 260, 20, false, false, "" + GetDictionaryEntry( 40038, socket.language ) + "" ); // Gold held in my account: - myGump.AddText( 300, 96, 1153, "" + bankAccount ); - - myGump.AddHTMLGump( 40, 120, 260, 20, false, false, "" + GetDictionaryEntry( 40039, socket.language ) + "" ); // Vendor upkeep: - myGump.AddText( 300, 120, 2603, GetDictionaryEntry( 40044, socket.language ) ); // Disabled - } - else - { - myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); // Amount of days I can work: - myGump.AddText( 300, 25, 1153, "" + days ); - - myGump.AddHTMLGump( 40, 48, 260, 20, false, false, "" + GetDictionaryEntry( 40036, socket.language ) + "" ); // Hours I can work: - myGump.AddText( 300, 48, 1153, "" + hours ); - - myGump.AddHTMLGump( 40, 72, 260, 20, false, false, "" + GetDictionaryEntry( 40037, socket.language ) + "" ); // Gold held for you: - myGump.AddText( 300, 72, 1153, "" + holdGold ); - - myGump.AddHTMLGump( 40, 96, 260, 20, false, false, "" + GetDictionaryEntry( 40038, socket.language ) + "" ); // Gold held in my account: - myGump.AddText( 300, 96, 1153, "" + bankAccount ); - - myGump.AddHTMLGump( 40, 120, 260, 20, false, false, "" + GetDictionaryEntry( 40040, socket.language ) + "" ); // My charge per period is: - myGump.AddText( 300, 120, 1153, "" + perPeriod ); - - myGump.AddHTMLGump( 40, 144, 260, 20, false, false, "" + GetDictionaryEntry( 40041, socket.language ) + "" ); // Charge period hours: - myGump.AddText( 300, 144, 1153, "" + vendorChargeHours ); - - myGump.AddHTMLGump( 40, 168, 260, 20, false, false, "" + GetDictionaryEntry( 40042, socket.language ) + "" ); // Item fee total: - myGump.AddText( 300, 168, 1153, "" + itemFeeTotal ); - } - - myGump.Send( socket ); - myGump.Free(); -} - -/** @param {Character} pUser @returns {number} */ -function GetPackGoldAmount( pUser ) -{ - if( !ValidateObject( pUser )) - return 0; - - var pPack = pUser.pack; - if( !ValidateObject( pPack )) - return 0; - - var totalGold = 0; - var goldItem = pPack.FirstItem(); - - for( ; !pPack.FinishedItems(); goldItem = pPack.NextItem() ) - { - if( !ValidateObject( goldItem )) - continue; - - if( goldItem.id == 0x0EED ) - totalGold += goldItem.amount; - } - - return totalGold; -} - -/** @param {Character} pUser @param {number} amount @returns {boolean} */ -function RemoveGoldFromPack( pUser, amount ) -{ - if( !ValidateObject( pUser ) || amount <= 0 ) - return false; - - var pPack = pUser.pack; - if( !ValidateObject( pPack )) - return false; - - var totalGold = GetPackGoldAmount( pUser ); - if( totalGold < amount ) - return false; - - var goldStacks = []; - var goldItem = pPack.FirstItem(); - - for( ; !pPack.FinishedItems(); goldItem = pPack.NextItem() ) - { - if( ValidateObject( goldItem ) && goldItem.id == 0x0EED ) - goldStacks.push( goldItem ); - } + var goldStacks = []; + var itemObj = pUser.pack.FirstItem(); + for( ; !pUser.pack.FinishedItems(); itemObj = pUser.pack.NextItem() ) + { + if( ValidateObject( itemObj ) && itemObj.id == 0x0EED ) + goldStacks.push( itemObj ); + } for( var i = 0; i < goldStacks.length && amount > 0; ++i ) { - var stack = goldStacks[i]; - if( !ValidateObject( stack )) - continue; - - if( stack.amount <= amount ) + if( goldStacks[i].amount <= amount ) { - amount -= stack.amount; - stack.Delete(); + amount -= goldStacks[i].amount; + goldStacks[i].Delete(); } else { - stack.amount = stack.amount - amount; + goldStacks[i].amount -= amount; amount = 0; } } @@ -1097,14 +798,21 @@ function RemoveGoldFromPack( pUser, amount ) return amount <= 0; } +/** @param {Character} pUser @returns {Item|null} */ +function GetBankBox( pUser ) +{ + if( !ValidateObject( pUser ) ) + return null; + + var bankBox = pUser.FindItemLayer( 29 ); + return ValidateObject( bankBox ) ? bankBox : null; +} + /** @param {Character} pUser @returns {boolean} */ function CanBankReceiveVendorPayout( pUser ) { - if( !ValidateObject( pUser )) - return false; - var bankBox = GetBankBox( pUser ); - if( !ValidateObject( bankBox )) + if( !ValidateObject( bankBox ) ) return false; if( bankBox.totalItemCount >= bankBox.maxItems ) @@ -1122,30 +830,49 @@ function CreateVendorBankCheck( pUser, checkSize ) if( !ValidateObject( pUser ) || checkSize <= 0 ) return null; - var socket = pUser.socket; var bankBox = GetBankBox( pUser ); - if( !ValidateObject( bankBox )) + if( !ValidateObject( bankBox ) ) return null; - var newCheck = CreateDFNItem( socket, pUser, "bankcheck", 1, "ITEM", false ); - if( !ValidateObject( newCheck )) + var newCheck = CreateDFNItem( pUser.socket, pUser, "bankcheck", 1, "ITEM", false ); + if( !ValidateObject( newCheck ) ) return null; newCheck.SetTag( "CheckSize", checkSize ); newCheck.AddScriptTrigger( 5015 ); newCheck.container = bankBox; - return newCheck; } +/** @param {Character} pTalking @param {Item} bankBox @param {number} depositAmt */ +function DivideDepositedGold( pTalking, bankBox, depositAmt ) +{ + var remainingGold = depositAmt; + var newGoldPile; + + while( remainingGold > 0 ) + { + if( remainingGold >= 65535 ) + { + newGoldPile = CreateDFNItem( pTalking.socket, pTalking, "0x0EED", 65535, "ITEM", false ); + remainingGold -= 65535; + } + else + { + newGoldPile = CreateDFNItem( pTalking.socket, pTalking, "0x0EED", remainingGold, "ITEM", false ); + remainingGold = 0; + } + + if( ValidateObject( newGoldPile ) ) + newGoldPile.container = bankBox; + } +} + /** @param {Character} pUser @param {number} goldAmount @returns {boolean} */ function DepositVendorGoldToBankBox( pUser, goldAmount ) { - if( !ValidateObject( pUser ) || goldAmount <= 0 ) - return false; - var bankBox = GetBankBox( pUser ); - if( !ValidateObject( bankBox )) + if( !ValidateObject( pUser ) || !ValidateObject( bankBox ) || goldAmount <= 0 ) return false; if( bankBox.totalItemCount >= bankBox.maxItems ) @@ -1158,201 +885,159 @@ function DepositVendorGoldToBankBox( pUser, goldAmount ) return true; } -/** @param {Character} pTalking @param {Item} bankBox @param {number} depositAmt @returns {void} */ -function DivideDepositedGold( pTalking, bankBox, depositAmt ) -{ - var numOfGoldPiles = ( depositAmt / 65535 ); - var i = 0; - var newGoldPile; - var remainingGold = depositAmt; - for( i = 1; i < numOfGoldPiles + 1; i++ ) - { - if( remainingGold >= 65535 ) - { - newGoldPile = CreateDFNItem( pTalking.socket, pTalking, "0x0EED", 65535, "ITEM", false ); - remainingGold = remainingGold - 65535; - newGoldPile.container = bankBox; - } - else - { - newGoldPile = CreateDFNItem( pTalking.socket, pTalking, "0x0EED", remainingGold, "ITEM", false ); - newGoldPile.container = bankBox; - continue; - } - } -} - /** @param {Character} pUser @param {Character} vendor */ function CollectVendorGold( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; var socket = pUser.socket; - if( !socket ) - return; + var heldGold = vendor.vendorGoldHeld || 0; - var holdGold = GetVendorHeldGold( vendor ); - if( holdGold <= 0 ) + if( heldGold <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40012, socket.language )); // This vendor has no held gold to collect. + socket.SysMessage( GetDictionaryEntry( 40012, socket.language ) ); return; } - if( !CanBankReceiveVendorPayout( pUser )) + if( !CanBankReceiveVendorPayout( pUser ) ) { - socket.SysMessage( GetDictionaryEntry( 40013, socket.language )); // Your bank box cannot receive vendor payouts right now. + socket.SysMessage( GetDictionaryEntry( 40013, socket.language ) ); return; } - if( holdGold > 2000 ) + if( heldGold > 2000 ) { - var vendorCheck = CreateVendorBankCheck( pUser, holdGold ); - if( !ValidateObject( vendorCheck )) + var vendorCheck = CreateVendorBankCheck( pUser, heldGold ); + if( !ValidateObject( vendorCheck ) ) { - socket.SysMessage( GetDictionaryEntry( 40014, socket.language )); // Unable to create a bank check for vendor gold. + socket.SysMessage( GetDictionaryEntry( 40014, socket.language ) ); return; } - SetVendorHeldGold( vendor, 0 ); - socket.SysMessage( GetDictionaryEntry( 40015, socket.language ), holdGold ); // Collected %i gold as a bank check in your bank box. + vendor.vendorGoldHeld = 0; + socket.SysMessage( GetDictionaryEntry( 40015, socket.language ), heldGold ); return; } - if( !DepositVendorGoldToBankBox( pUser, holdGold )) + if( !DepositVendorGoldToBankBox( pUser, heldGold ) ) { - socket.SysMessage( GetDictionaryEntry( 40016, socket.language )); // Unable to deposit vendor gold into your bank box. + socket.SysMessage( GetDictionaryEntry( 40016, socket.language ) ); return; } - SetVendorHeldGold( vendor, 0 ); - socket.SysMessage( GetDictionaryEntry( 40017, socket.language ), holdGold ); // Collected %i gold to your bank box. + vendor.vendorGoldHeld = 0; + socket.SysMessage( GetDictionaryEntry( 40017, socket.language ), heldGold ); } /** @param {Character} pUser @param {Character} vendor @param {number} amount */ function DepositToVendorBank( pUser, vendor, amount ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; var socket = pUser.socket; - if( !socket ) - return; - if( amount <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40018, socket.language )); // Invalid deposit amount. + socket.SysMessage( GetDictionaryEntry( 40018, socket.language ) ); return; } - var pPack = pUser.pack; - if( !ValidateObject( pPack )) + if( !ValidateObject( pUser.pack ) ) { - socket.SysMessage( GetDictionaryEntry( 40019, socket.language )); // You have no backpack. + socket.SysMessage( GetDictionaryEntry( 40019, socket.language ) ); return; } - var totalPackGold = GetPackGoldAmount( pUser ); - if( totalPackGold < amount ) + if( GetPackGoldAmount( pUser ) < amount ) { - socket.SysMessage( GetDictionaryEntry( 40020, socket.language )); // You do not have enough gold in your pack. + socket.SysMessage( GetDictionaryEntry( 40020, socket.language ) ); return; } var deposited = DepositVendorBankGold( vendor, amount ); if( deposited <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40021, socket.language )); // Vendor bank account is full. + socket.SysMessage( GetDictionaryEntry( 40021, socket.language ) ); return; } - if( !RemoveGoldFromPack( pUser, deposited )) + if( !RemoveGoldFromPack( pUser, deposited ) ) { WithdrawVendorBankGold( vendor, deposited ); - socket.SysMessage( GetDictionaryEntry( 40022, socket.language )); // Unable to remove gold from your pack. Deposit cancelled. + socket.SysMessage( GetDictionaryEntry( 40022, socket.language ) ); return; } - socket.SysMessage( GetDictionaryEntry( 40023, socket.language ), deposited ); // Deposited %i gold into vendor bank account. + socket.SysMessage( GetDictionaryEntry( 40023, socket.language ), deposited ); if( deposited < amount ) - socket.SysMessage( GetDictionaryEntry( 40024, socket.language )); // Vendor bank reached its maximum balance. + socket.SysMessage( GetDictionaryEntry( 40024, socket.language ) ); } /** @param {Character} pUser @param {Character} vendor */ function FlushBankToHeld( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) - return; - - var socket = pUser.socket; - if( !socket ) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; var moved = FlushVendorBankToHeldGold( vendor ); if( moved <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40025, socket.language )); // Vendor bank account is empty. + pUser.socket.SysMessage( GetDictionaryEntry( 40025, pUser.socket.language ) ); return; } - socket.SysMessage( GetDictionaryEntry( 40026, socket.language ), moved ); // Moved %i gold from vendor bank account to held gold. + pUser.socket.SysMessage( GetDictionaryEntry( 40026, pUser.socket.language ), moved ); } /** @param {Character} pUser @param {Character} vendor */ function DismissVendor( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; var socket = pUser.socket; - if( !socket ) - return; - - var pvDeed = CreateVendorDismissDeedForOwner( pUser, vendor ); - if( !ValidateObject( pvDeed )) + var deed = CreateVendorDismissDeedForOwner( pUser, vendor ); + if( !ValidateObject( deed ) ) { - socket.SysMessage( GetDictionaryEntry( 40027, socket.language )); // Unable to create vendor deed. Dismiss cancelled. + socket.SysMessage( GetDictionaryEntry( 40027, socket.language ) ); return; } var itemResults = ReturnVendorItemsToOwner( vendor, pUser ); var goldResult = ReturnVendorGoldToOwner( pUser, vendor ); - var deedLocation = PlaceItemForOwnerOrDrop( pvDeed, pUser, vendor ); + var deedLocation = PlaceItemForOwnerOrDrop( deed, pUser, vendor ); - socket.SysMessage( GetDictionaryEntry( 581, socket.language ), pvDeed.name ); // Thy deed for %s has been placed in thy pack. + socket.SysMessage( GetDictionaryEntry( 581, socket.language ), deed.name ); if(( itemResults.pack + itemResults.bank + itemResults.ground ) > 0 ) { if( onlyReturnToBank ) - { - socket.SysMessage( GetDictionaryEntry( 40002, socket.language ), itemResults.bank, itemResults.ground ); // Vendor items returned - bank: %i, ground: %i. - } + socket.SysMessage( GetDictionaryEntry( 40002, socket.language ), itemResults.bank, itemResults.ground ); else - { - socket.SysMessage( GetDictionaryEntry( 40003, socket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); // Vendor items returned - pack: %i, bank: %i, ground: %i. - } + socket.SysMessage( GetDictionaryEntry( 40003, socket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); } if( goldResult.amount > 0 ) { if( goldResult.location == 1 ) - socket.SysMessage( GetDictionaryEntry( 40004, socket.language ), goldResult.amount ); // Returned %i gold to your pack. + socket.SysMessage( GetDictionaryEntry( 40004, socket.language ), goldResult.amount ); else if( goldResult.location == 2 ) - socket.SysMessage( GetDictionaryEntry( 40005, socket.language ), goldResult.amount ); // Returned %i gold to your bank box. + socket.SysMessage( GetDictionaryEntry( 40005, socket.language ), goldResult.amount ); else if( goldResult.location == 3 ) - socket.SysMessage( GetDictionaryEntry( 40006, socket.language ), goldResult.amount ); // Dropped %i gold at vendor location. + socket.SysMessage( GetDictionaryEntry( 40006, socket.language ), goldResult.amount ); } if( deedLocation == 1 ) - socket.SysMessage( GetDictionaryEntry( 40007, socket.language )); // Placed vendor deed in your pack. + socket.SysMessage( GetDictionaryEntry( 40007, socket.language ) ); else if( deedLocation == 2 ) - socket.SysMessage( GetDictionaryEntry( 40008, socket.language )); // Placed vendor deed in your bank box. + socket.SysMessage( GetDictionaryEntry( 40008, socket.language ) ); else if( deedLocation == 3 ) - socket.SysMessage( GetDictionaryEntry( 40009, socket.language )); // Dropped vendor deed at vendor location. + socket.SysMessage( GetDictionaryEntry( 40009, socket.language ) ); FinalizeVendorRemoval( vendor ); } @@ -1360,71 +1045,46 @@ function DismissVendor( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function CycleVendorDirection( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; vendor.direction = ( vendor.direction + 1 ) % 8; } -/** @param {string} speech @returns {string} */ -function NormalizeSpeech( speech ) +/** @param {Character} vendor @param {string} speech @returns {string} */ +function NormalizeVendorSpeech( vendor, speech ) { if( !speech ) return ""; - return ( "" + speech ).toLowerCase().replace( /^\s+|\s+$/g, "" ); -} - -/** @param {Character} vendor @param {string} speech @returns {string} */ -function StripVendorNamePrefix( vendor, speech ) -{ - if( !IsPlayerVendor( vendor )) - return speech; - - var vendorName = ""; - if( vendor.name ) - vendorName = ( "" + vendor.name ).toLowerCase(); - - if( vendorName == "" ) - return speech; + var cleanedSpeech = ( "" + speech ).toLowerCase().replace( /^\s+|\s+$/g, "" ); + if( !ValidateObject( vendor ) || vendor.aitype != 17 || !vendor.name ) + return cleanedSpeech; - if( speech.indexOf( vendorName + " " ) == 0 ) - return speech.substring( vendorName.length + 1 ); + var vendorName = ( "" + vendor.name ).toLowerCase(); + if( cleanedSpeech.indexOf( vendorName + " " ) == 0 ) + return cleanedSpeech.substring( vendorName.length + 1 ); - if( speech.indexOf( vendorName + "," ) == 0 ) - return speech.substring( vendorName.length + 1 ).replace( /^\s+|\s+$/g, "" ); + if( cleanedSpeech.indexOf( vendorName + "," ) == 0 ) + return cleanedSpeech.substring( vendorName.length + 1 ).replace( /^\s+|\s+$/g, "" ); - return speech; + return cleanedSpeech; } -/** @param {Character} pUser @param {Character} vendor @param {string} speech @returns {boolean} */ -function MatchVendorCommand( pUser, vendor, speech ) +/** @param {Character} pUser @param {Character} vendor @returns {boolean} */ +function VendorAccessBlocked( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) - return false; - - var cmd = NormalizeSpeech( speech ); - cmd = StripVendorNamePrefix( vendor, cmd ); - - if( cmd == "view" || cmd == "browse" || cmd == "look" ) - return true; - - if( cmd == "buy" || cmd == "purchase" ) - return true; - - if( cmd == "gold" || cmd == "collect" || cmd == "get" ) - return true; - - if( cmd == "status" || cmd == "info" ) - return true; - - if( cmd == "dismiss" || cmd == "replace" ) + if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser ) ) + { + if( pUser.socket ) + pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language ) ); return true; + } - if( cmd == "vendor cycle" || cmd == "cycle" ) + if( !CheckVendorUpkeep( vendor, pUser ) ) return true; return false; @@ -1433,23 +1093,14 @@ function MatchVendorCommand( pUser, vendor, speech ) /** @param {Character} pUser @param {Character} vendor @param {string} speech @returns {number} */ function HandleVendorSpeechCommand( pUser, vendor, speech ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) return 0; - var socket = pUser.socket; - var cmd = NormalizeSpeech( speech ); - cmd = StripVendorNamePrefix( vendor, cmd ); + var cmd = NormalizeVendorSpeech( vendor, speech ); if( cmd == "view" || cmd == "browse" || cmd == "look" ) { - if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser )) - { - if( pUser.socket ) - pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); // You can't shop from this home as you have been banned from this establishment. - return 2; - } - - if( !CheckVendorUpkeep( vendor, pUser )) + if( VendorAccessBlocked( pUser, vendor ) ) return 2; OpenVendorBackpack( pUser, vendor ); @@ -1458,14 +1109,7 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "buy" || cmd == "purchase" ) { - if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser )) - { - if( pUser.socket ) - pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); // You can't shop from this home as you have been banned from this establishment. - return 2; - } - - if( !CheckVendorUpkeep( vendor, pUser )) + if( VendorAccessBlocked( pUser, vendor ) ) return 2; pUser.BuyFrom( vendor ); @@ -1474,13 +1118,13 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "gold" || cmd == "collect" || cmd == "get" ) { - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + vendor.TextMessage( GetDictionaryEntry( 40028 ) ); return 2; } - if( !CheckVendorUpkeep( vendor, pUser )) + if( !CheckVendorUpkeep( vendor, pUser ) ) return 2; CollectVendorGold( pUser, vendor ); @@ -1489,28 +1133,28 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "status" || cmd == "info" ) { - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + vendor.TextMessage( GetDictionaryEntry( 40028 ) ); return 2; } - if( !CheckVendorUpkeep( vendor, pUser )) + if( !CheckVendorUpkeep( vendor, pUser ) ) return 2; - if( socket ) + if( pUser.socket ) { StoreVendorForGump( pUser, vendor ); - ShowPlayerVendorOwnerGump( socket, vendor ); + ShowPlayerVendorOwnerGump( pUser.socket, vendor ); } return 2; } if( cmd == "dismiss" || cmd == "replace" ) { - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + vendor.TextMessage( GetDictionaryEntry( 40028 ) ); return 2; } @@ -1520,9 +1164,9 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "vendor cycle" || cmd == "cycle" ) { - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 )); // I don't work for you! + vendor.TextMessage( GetDictionaryEntry( 40028 ) ); return 2; } @@ -1533,277 +1177,275 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) return 0; } -/** @type { ( pUser: Character, targChar: Character, nonMouseClickEvent: boolean ) => boolean } */ -function onCharDoubleClick( pUser, targChar, nonMouseClickEvent ) +/** @param {Character} vendor @param {number} layer */ +function RemoveVendorLayerItem( vendor, layer ) { - if( !ValidateObject( pUser ) || !ValidateObject( targChar )) - return false; + if( !ValidateObject( vendor ) ) + return; - if( nonMouseClickEvent ) - return true; + var layerItem = vendor.FindItemLayer( layer ); + if( ValidateObject( layerItem ) ) + layerItem.Delete(); +} - if( !IsPlayerVendor( targChar )) - return true; +/** @param {Character} vendor @param {number} layer @param {number} itemID @param {number} hue @param {string} itemName */ +function SetVendorLayerItem( vendor, layer, itemID, hue, itemName ) +{ + if( !ValidateObject( vendor ) ) + return; - if( !CheckVendorUpkeep( targChar, pUser )) - return false; + var oldItem = vendor.FindItemLayer( layer ); + if( ValidateObject( oldItem ) ) + oldItem.Delete(); - if( IsVendorOwner( targChar, pUser )) - { - if( pUser.socket ) - { - StoreVendorForGump( pUser, targChar ); - ShowPlayerVendorOwnerGump( pUser.socket, targChar ); - } - return false; - } + if( itemID == 0 ) + return; - if( ValidateObject( targChar.multi ) && targChar.multi.IsOnBanList( pUser )) - { - if( pUser.socket ) - pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); // You can't shop from this home as you have been banned from this establishment. - return false; - } + var newItem = CreateBlankItem( vendor.socket ? vendor.socket : null, vendor, 1, itemName, itemID, hue, "ITEM", false ); + if( !ValidateObject( newItem ) ) + return; - OpenVendorBackpack( pUser, targChar ); - return false; + newItem.container = vendor; + newItem.layer = layer; } -/** @param {string} speech @param {Character} personTalking @param {BaseObject} talkingTo @returns {number} */ -function onSpeech( speech, personTalking, talkingTo ) +/** @param {Character} vendor @param {number} layer @param {number} hue */ +function SetVendorLayerHue( vendor, layer, hue ) { - if( !ValidateObject( personTalking ) || !ValidateObject( talkingTo )) - return 0; - - if( !IsPlayerVendor( talkingTo )) - return 0; - - if( !MatchVendorCommand( personTalking, talkingTo, speech )) - return 0; + if( !ValidateObject( vendor ) ) + return; - return HandleVendorSpeechCommand( personTalking, talkingTo, speech ); + var layerItem = vendor.FindItemLayer( layer ); + if( ValidateObject( layerItem ) ) + layerItem.colour = hue; } -/** @param {Character} socket @param {Gump} myGump @param {number} menuPage @param {number} categoryPageStart @param {string} title */ -function AddHairHueCategoryMenu( socket, myGump, menuPage, categoryPageStart, title ) +/** @param {Character} vendor @param {boolean} isElf @param {boolean} isFemale */ +function SetVendorRaceGenderBody( vendor, isElf, isFemale ) { - myGump.AddPage( menuPage ); - myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + title + "
" ); + if( isElf ) + vendor.id = isFemale ? 0x025E : 0x025D; + else + vendor.id = isFemale ? 0x0191 : 0x0190; - var columns = 2; - var startX = 20; - var startY = 70; - var colWidth = 160; - var rowHeight = 20; + if( isFemale ) + RemoveVendorLayerItem( vendor, layerBeard ); - for( var i = 0; i < vendorHairHueCategories.length; ++i ) - { - var row = Math.floor( i / columns ); - var col = i % columns; - var x = startX + ( col * colWidth ); - var y = startY + ( row * rowHeight ); + vendor.Teleport(); +} - myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 0, categoryPageStart + i, 0 ); - myGump.AddHTMLGump( x + 30, y, 125, 18, false, false, "" + GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) + "" ); - } +/** @param {Character} pUser @param {number} categoryIndex */ +function StoreClothingDyeCategory( pUser, categoryIndex ) +{ + if( ValidateObject( pUser ) ) + pUser.SetTempTag( "PlayerVendorClothingDyeCategory", categoryIndex ); +} - myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 1, 5007 ); - myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK +/** @param {Character} pUser @returns {number} */ +function GetStoredClothingDyeCategory( pUser ) +{ + if( !ValidateObject( pUser ) ) + return -1; + + var categoryIndex = pUser.GetTempTag( "PlayerVendorClothingDyeCategory" ); + return ( categoryIndex === null || categoryIndex === undefined || categoryIndex === "" ) ? -1 : categoryIndex; } -/** @param {Character} socket @param {Gump} myGump @param {number} pageNumber @param {string} title @param {number[]} hueList @param {number} buttonBase @param {number} backPage */ -function AddHairHueCategoryPage( socket, myGump, pageNumber, title, hueList, buttonBase, backPage ) +/** @param {Socket} socket @param {Character} vendor */ +function ShowPlayerVendorOwnerGump( socket, vendor ) { - myGump.AddPage( pageNumber ); - myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + title + "
" ); + if( !socket || !ValidateObject( vendor ) || vendor.aitype != 17 ) + return; - var hueColumns = 3; - var startX = 20; - var startY = 70; - var colWidth = 112; - var rowHeight = 18; + var heldGold = vendor.vendorGoldHeld || 0; + var bankGold = vendor.GetTag( "VendorBankAccount" ); + if( bankGold < 0 ) + bankGold = 0; - for( var i = 0; i < hueList.length; ++i ) - { - var row = Math.floor( i / hueColumns ); - var col = i % hueColumns; - var x = startX + ( col * colWidth ); - var y = startY + ( row * rowHeight ); - var hueHex = hueList[i].toString( 16 ).toUpperCase(); + var perPeriod = GetVendorChargePerPeriod( vendor ); + var days = GetVendorDaysAffordable( vendor ); + var hours = GetVendorHoursAffordable( vendor ); + var itemFeeTotal = GetVendorItemFeeTotal( vendor ); - myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 1, pageNumber, buttonBase + hueList[i] ); - myGump.AddText( x + 25, y, hueList[i], "0x" + hueHex ); - } + var myGump = new Gump; + myGump.AddPage( 0 ); + myGump.AddBackground( 25, 10, 555, 240, 5054 ); + myGump.AddCheckerTrans( 32, 20, 537, 220 ); + myGump.NoResize(); - myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 0, backPage, 0 ); - myGump.AddHTMLGump( 45, 342, 80, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK + myGump.AddButton( 390, 25, 4005, 4007, 1, 0, 1 ); + myGump.AddHTMLGump( 425, 25, 120, 20, false, false, "" + GetDictionaryEntry( 40029, socket.language ) + "" ); - myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 1, 5007 ); - myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 40045, socket.language ) + "" ); // MAIN -} + myGump.AddButton( 390, 48, 4005, 4007, 1, 0, 2 ); + myGump.AddHTMLGump( 425, 48, 120, 20, false, false, "" + GetDictionaryEntry( 40030, socket.language ) + "" ); -/** @param {Socket} pSock @param {number} pButton @param {GumpData} gumpData */ -function onGumpPress( pSock, pButton, gumpData ) -{ - var pUser = pSock.currentChar; - if( !ValidateObject( pUser )) - return; + myGump.AddButton( 390, 71, 4005, 4007, 1, 0, 7 ); + myGump.AddHTMLGump( 425, 72, 120, 20, false, false, "" + GetDictionaryEntry( 40048, socket.language ) + "" ); - var vendor = GetStoredVendorForGump( pUser ); - if( !IsPlayerVendor( vendor )) - return; + myGump.AddButton( 390, 94, 4005, 4007, 1, 0, 8 ); + myGump.AddHTMLGump( 425, 95, 120, 20, false, false, "" + GetDictionaryEntry( 40049, socket.language ) + "" ); - if( !IsVendorOwner( vendor, pUser )) - return; + myGump.AddButton( 390, 117, 4005, 4007, 1, 0, 3 ); + myGump.AddHTMLGump( 425, 118, 120, 20, false, false, "" + GetDictionaryEntry( 40031, socket.language ) + "" ); - if( !CheckVendorUpkeep( vendor, pUser )) - return; + myGump.AddButton( 390, 140, 4005, 4007, 1, 0, 4 ); + myGump.AddHTMLGump( 425, 141, 120, 20, false, false, "" + GetDictionaryEntry( 40032, socket.language ) + "" ); - if( pButton == 5000 || pButton == 5001 || pButton == 5002 || pButton == 5004 || pButton == 5006 || pButton == 5007 || - ( pButton >= 0x1000 && pButton < ( 0x1000 + 256 )) || - ( pButton >= 0x2000 && pButton < ( 0x2000 + 256 )) || - ( pButton >= 0x3000 && pButton < 0x4000 ) || - ( pButton >= 0x4000 && pButton < 0x5000 )) - { - HandleVendorCustomizeButton( pUser, vendor, pButton ); - return; - } + myGump.AddButton( 390, 163, 4005, 4007, 1, 0, 5 ); + myGump.AddHTMLGump( 425, 164, 120, 20, false, false, "" + GetDictionaryEntry( 40033, socket.language ) + "" ); - if( pButton == 0x8FFF || pButton == 0x8FFE || - ( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 )) || - ( pButton >= 0x7000 && pButton < ( 0x7000 + 100 )) || - ( pButton >= 0x8000 && pButton < ( 0x8000 + vendorClothingCategories.length )) || - ( pButton >= 0x9000 && pButton < ( 0x9000 + 0x1000 ))) + myGump.AddButton( 390, 186, 4005, 4007, 1, 0, 6 ); + myGump.AddHTMLGump( 425, 187, 120, 20, false, false, "" + GetDictionaryEntry( 40034, socket.language ) + "" ); + + myGump.AddButton( 390, 209, 4005, 4007, 1, 0, 0 ); + myGump.AddHTMLGump( 425, 210, 120, 20, false, false, "" + GetDictionaryEntry( 18762, socket.language ) + "" ); + + if( !vendorChargesEnabled ) { - HandleVendorClothingButton( pUser, vendor, pButton ); - return; - } + myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); + myGump.AddText( 300, 25, 2603, GetDictionaryEntry( 40043, socket.language ) ); - switch( pButton ) + myGump.AddHTMLGump( 40, 48, 260, 20, false, false, "" + GetDictionaryEntry( 40036, socket.language ) + "" ); + myGump.AddText( 300, 48, 2603, GetDictionaryEntry( 40043, socket.language ) ); + + myGump.AddHTMLGump( 40, 72, 260, 20, false, false, "" + GetDictionaryEntry( 40037, socket.language ) + "" ); + myGump.AddText( 300, 72, 1153, "" + heldGold ); + + myGump.AddHTMLGump( 40, 96, 260, 20, false, false, "" + GetDictionaryEntry( 40038, socket.language ) + "" ); + myGump.AddText( 300, 96, 1153, "" + bankGold ); + + myGump.AddHTMLGump( 40, 120, 260, 20, false, false, "" + GetDictionaryEntry( 40039, socket.language ) + "" ); + myGump.AddText( 300, 120, 2603, GetDictionaryEntry( 40044, socket.language ) ); + } + else { - case 0: - break; - case 1: - OpenVendorBackpack( pUser, vendor ); - break; - case 2: - ShowVendorCustomizeGump( pUser, vendor ); - break; - case 3: - CollectVendorGold( pUser, vendor ); - ShowPlayerVendorOwnerGump( pSock, vendor ); - break; - case 4: - BeginDepositVendorGold( pUser, vendor ); - break; - case 5: - FlushBankToHeld( pUser, vendor ); - ShowPlayerVendorOwnerGump( pSock, vendor ); - break; - case 6: - DismissVendor( pUser, vendor ); - break; - case 7: - BeginRenameVendor( pUser, vendor ); - break; - case 8: - BeginRenameVendorShop( pUser, vendor ); - break; - default: - break; + myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); + myGump.AddText( 300, 25, 1153, "" + days ); + + myGump.AddHTMLGump( 40, 48, 260, 20, false, false, "" + GetDictionaryEntry( 40036, socket.language ) + "" ); + myGump.AddText( 300, 48, 1153, "" + hours ); + + myGump.AddHTMLGump( 40, 72, 260, 20, false, false, "" + GetDictionaryEntry( 40037, socket.language ) + "" ); + myGump.AddText( 300, 72, 1153, "" + heldGold ); + + myGump.AddHTMLGump( 40, 96, 260, 20, false, false, "" + GetDictionaryEntry( 40038, socket.language ) + "" ); + myGump.AddText( 300, 96, 1153, "" + bankGold ); + + myGump.AddHTMLGump( 40, 120, 260, 20, false, false, "" + GetDictionaryEntry( 40040, socket.language ) + "" ); + myGump.AddText( 300, 120, 1153, "" + perPeriod ); + + myGump.AddHTMLGump( 40, 144, 260, 20, false, false, "" + GetDictionaryEntry( 40041, socket.language ) + "" ); + myGump.AddText( 300, 144, 1153, "" + vendorChargeHours ); + + myGump.AddHTMLGump( 40, 168, 260, 20, false, false, "" + GetDictionaryEntry( 40042, socket.language ) + "" ); + myGump.AddText( 300, 168, 1153, "" + itemFeeTotal ); } -} -/** @param {Character} vendor @returns {boolean} */ -function IsFemaleVendor( vendor ) -{ - return vendor.id == 0x0191 || vendor.id == 0x025E; + myGump.Send( socket ); + myGump.Free(); } -/** @param {Character} vendor @returns {boolean} */ -function IsElfVendor( vendor ) +/** @param {Socket} socket @param {Gump} myGump @param {number} menuPage @param {number} categoryPageStart @param {string} title */ +function AddHairHueCategoryMenu( socket, myGump, menuPage, categoryPageStart, title ) { - return vendor.id == 0x025D || vendor.id == 0x025E; -} + myGump.AddPage( menuPage ); + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + title + "
" ); -/** @param {Character} vendor @param {boolean} isElf @param {boolean} isFemale */ -function SetVendorRaceGenderBody( vendor, isElf, isFemale ) -{ - if( isElf ) - vendor.id = ( isFemale ? 0x025E : 0x025D ); - else - vendor.id = ( isFemale ? 0x0191 : 0x0190 ); + var columns = 2; + var startX = 20; + var startY = 70; + var colWidth = 160; + var rowHeight = 20; - if( isFemale ) - RemoveVendorLayerItem( vendor, layerBeard ); + for( var i = 0; i < vendorHairHueCategories.length; ++i ) + { + var row = Math.floor( i / columns ); + var col = i % columns; + var x = startX + ( col * colWidth ); + var y = startY + ( row * rowHeight ); - vendor.Teleport(); + myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 0, categoryPageStart + i, 0 ); + myGump.AddHTMLGump( x + 30, y, 125, 18, false, false, "" + GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) + "" ); + } + + myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 1, 5007 ); + myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); } -/** @param {Character} vendor @returns {HairOrBeard[]} */ -function GetVendorHairStyles( vendor ) +/** @param {Socket} socket @param {Gump} myGump @param {number} pageNumber @param {string} title @param {number[]} hueList @param {number} buttonBase @param {number} backPage */ +function AddHairHueCategoryPage( socket, myGump, pageNumber, title, hueList, buttonBase, backPage ) { - if( IsElfVendor( vendor )) + myGump.AddPage( pageNumber ); + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + title + "
" ); + + var columns = 3; + var startX = 20; + var startY = 70; + var colWidth = 112; + var rowHeight = 18; + + for( var i = 0; i < hueList.length; ++i ) { - if( IsFemaleVendor( vendor )) - return femaleElfHairStyles; + var row = Math.floor( i / columns ); + var col = i % columns; + var x = startX + ( col * colWidth ); + var y = startY + ( row * rowHeight ); + var hueHex = hueList[i].toString( 16 ).toUpperCase(); - return maleElfHairStyles; + myGump.AddButton( x, y, 0x0A9A, 0x0A9A, 1, pageNumber, buttonBase + hueList[i] ); + myGump.AddText( x + 25, y, hueList[i], "0x" + hueHex ); } - return humanHairStyles; -} + myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 0, backPage, 0 ); + myGump.AddHTMLGump( 45, 342, 80, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); -/** @param {Character} vendor @returns {boolean} */ -function VendorCanHaveBeard( vendor ) -{ - return !IsElfVendor( vendor ) && !IsFemaleVendor( vendor ); + myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 1, 5007 ); + myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 40045, socket.language ) + "" ); } /** @param {Character} pUser @param {Character} vendor */ function ShowVendorCustomizeGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; var socket = pUser.socket; - if( !socket ) - return; + var isElf = ( vendor.id == 0x025D || vendor.id == 0x025E ); + var isFemale = ( vendor.id == 0x0191 || vendor.id == 0x025E ); + var hairStyles = humanHairStyles; - StoreVendorForGump( pUser, vendor ); + if( isElf ) + hairStyles = isFemale ? femaleElfHairStyles : maleElfHairStyles; - var isElf = IsElfVendor( vendor ); - var isFemale = IsFemaleVendor( vendor ); - var hairStyles = GetVendorHairStyles( vendor ); + StoreVendorForGump( pUser, vendor ); var myGump = new Gump; myGump.AddPage( 0 ); myGump.AddBackground( 0, 0, 370, 370, 0x13BE ); myGump.AddCheckerTrans( 10, 10, 350, 350 ); - myGump.AddHTMLGump( 10, 12, 350, 18, false, false, "
" + GetDictionaryEntry( 40046, socket.language ) + "
" ); // VENDOR CUSTOMIZATION MENU + myGump.AddHTMLGump( 10, 12, 350, 18, false, false, "
" + GetDictionaryEntry( 40046, socket.language ) + "
" ); myGump.AddPage( 1 ); - myGump.AddHTMLGump( 10, 42, 150, 18, false, false, "
" + GetDictionaryEntry( 40047, socket.language ) + "
" ); // HAIR + myGump.AddHTMLGump( 10, 42, 150, 18, false, false, "
" + GetDictionaryEntry( 40047, socket.language ) + "
" ); - var i; - for( i = 0; i < hairStyles.length; ++i ) + for( var i = 0; i < hairStyles.length; ++i ) { myGump.AddButton( 10, 70 + ( i * 20 ), 0xFA5, 0xFA7, 1, 1, 0x1000 + i ); myGump.AddHTMLGump( 45, 72 + ( i * 20 ), 110, 18, false, false, "" + GetHairOrBeardName( hairStyles[i], socket ) + "" ); } myGump.AddButton( 10, 70 + ( hairStyles.length * 20 ), 0xFB1, 0xFB3, 1, 1, 5002 ); - myGump.AddHTMLGump( 45, 72 + ( hairStyles.length * 20 ), 110, 18, false, false, "" + GetDictionaryEntry( 40071, socket.language ) + "" ); // Remove Hair + myGump.AddHTMLGump( 45, 72 + ( hairStyles.length * 20 ), 110, 18, false, false, "" + GetDictionaryEntry( 40071, socket.language ) + "" ); myGump.AddButton( 10, 70 + (( hairStyles.length + 1 ) * 20 ), 0xFA5, 0xFA7, 0, 2, 0 ); - myGump.AddHTMLGump( 45, 72 + (( hairStyles.length + 1 ) * 20 ), 110, 18, false, false, "" + GetDictionaryEntry( 40072, socket.language ) + "" ); // Color Hair + myGump.AddHTMLGump( 45, 72 + (( hairStyles.length + 1 ) * 20 ), 110, 18, false, false, "" + GetDictionaryEntry( 40072, socket.language ) + "" ); - if( VendorCanHaveBeard( vendor )) + if( !isElf && !isFemale ) { - myGump.AddHTMLGump( 160, 42, 190, 18, false, false, "
" + GetDictionaryEntry( 40073, socket.language ) + "
" ); // BEARD + myGump.AddHTMLGump( 160, 42, 190, 18, false, false, "
" + GetDictionaryEntry( 40073, socket.language ) + "
" ); for( i = 0; i < humanBeardStyles.length; ++i ) { @@ -1812,34 +1454,31 @@ function ShowVendorCustomizeGump( pUser, vendor ) } myGump.AddButton( 160, 70 + ( humanBeardStyles.length * 20 ), 0xFB1, 0xFB3, 1, 1, 5004 ); - myGump.AddHTMLGump( 195, 72 + ( humanBeardStyles.length * 20 ), 160, 18, false, false, "" + GetDictionaryEntry( 40074, socket.language ) + "" ); // Remove Beard + myGump.AddHTMLGump( 195, 72 + ( humanBeardStyles.length * 20 ), 160, 18, false, false, "" + GetDictionaryEntry( 40074, socket.language ) + "" ); myGump.AddButton( 160, 70 + (( humanBeardStyles.length + 1 ) * 20 ), 0xFA5, 0xFA7, 0, 100, 0 ); - myGump.AddHTMLGump( 195, 72 + (( humanBeardStyles.length + 1 ) * 20 ), 160, 18, false, false, "" + GetDictionaryEntry( 40075, socket.language ) + "" ); // Color Beard + myGump.AddHTMLGump( 195, 72 + (( humanBeardStyles.length + 1 ) * 20 ), 160, 18, false, false, "" + GetDictionaryEntry( 40075, socket.language ) + "" ); } myGump.AddButton( 160, 290, 0xFA5, 0xFA7, 1, 1, 5001 ); - myGump.AddHTMLGump( 195, 292, 160, 18, false, false, isFemale ? "" + GetDictionaryEntry( 40076, socket.language ) + "" : "" + GetDictionaryEntry( 40077, socket.language ) + "" ); // Change to Male Change to Female + myGump.AddHTMLGump( 195, 292, 160, 18, false, false, isFemale ? "" + GetDictionaryEntry( 40076, socket.language ) + "" : "" + GetDictionaryEntry( 40077, socket.language ) + "" ); myGump.AddButton( 160, 310, 0xFA5, 0xFA7, 1, 1, 5006 ); - myGump.AddHTMLGump( 195, 312, 160, 18, false, false, isElf ? "" + GetDictionaryEntry( 40078, socket.language ) + "" : "" + GetDictionaryEntry( 40079, socket.language ) + "" ); // Change to Human Change to Elf + myGump.AddHTMLGump( 195, 312, 160, 18, false, false, isElf ? "" + GetDictionaryEntry( 40078, socket.language ) + "" : "" + GetDictionaryEntry( 40079, socket.language ) + "" ); - myGump.AddButton( 160, 330, 0xFA5, 0xFA7, 1, 0, 7 ); - myGump.AddHTMLGump( 195, 332, 160, 18, false, false, "" + GetDictionaryEntry( 40080, socket.language ) + "" ); // Change Clothing + myGump.AddButton( 160, 330, 0xFA5, 0xFA7, 1, 0, 9 ); + myGump.AddHTMLGump( 195, 332, 160, 18, false, false, "" + GetDictionaryEntry( 40080, socket.language ) + "" ); myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 1, 1, 5000 ); - myGump.AddHTMLGump( 45, 342, 305, 18, false, false, "" + GetDictionaryEntry( 40081, socket.language ) + "" ); // CLOSE + myGump.AddHTMLGump( 45, 342, 305, 18, false, false, "" + GetDictionaryEntry( 40081, socket.language ) + "" ); - AddHairHueCategoryMenu( socket, myGump, 2, 10, GetDictionaryEntry( 40082, socket.language )); // HAIR COLOR - AddHairHueCategoryMenu( socket, myGump, 100, 110, GetDictionaryEntry( 40083, socket.language )); // BEARD COLOR + AddHairHueCategoryMenu( socket, myGump, 2, 10, GetDictionaryEntry( 40082, socket.language ) ); + AddHairHueCategoryMenu( socket, myGump, 100, 110, GetDictionaryEntry( 40083, socket.language ) ); for( i = 0; i < vendorHairHueCategories.length; ++i ) { - var hairTitle = GetDictionaryEntry( 40084, socket.language ); // Hair - %s - hairTitle = hairTitle.replace( /%s/gi, GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) ); - - var beardTitle = GetDictionaryEntry( 40085, socket.language ); // Beard - %s - beardTitle = beardTitle.replace( /%s/gi, GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) ); + var hairTitle = GetDictionaryEntry( 40084, socket.language ).replace( /%s/gi, GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) ); + var beardTitle = GetDictionaryEntry( 40085, socket.language ).replace( /%s/gi, GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) ); AddHairHueCategoryPage( socket, myGump, 10 + i, hairTitle, vendorHairHueCategories[i].hues, 0x3000, 2 ); AddHairHueCategoryPage( socket, myGump, 110 + i, beardTitle, vendorHairHueCategories[i].hues, 0x4000, 100 ); @@ -1852,23 +1491,22 @@ function ShowVendorCustomizeGump( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor @param {number} pButton */ function HandleVendorCustomizeButton( pUser, vendor, pButton ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; - var socket = pUser.socket; - if( !socket ) - return; + var isElf = ( vendor.id == 0x025D || vendor.id == 0x025E ); + var isFemale = ( vendor.id == 0x0191 || vendor.id == 0x025E ); + var hairStyles = humanHairStyles; - var isElf = IsElfVendor( vendor ); - var isFemale = IsFemaleVendor( vendor ); - var hairStyles = GetVendorHairStyles( vendor ); + if( isElf ) + hairStyles = isFemale ? femaleElfHairStyles : maleElfHairStyles; if( pButton == 5000 ) { - ShowPlayerVendorOwnerGump( socket, vendor ); + ShowPlayerVendorOwnerGump( pUser.socket, vendor ); return; } @@ -1890,12 +1528,17 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) { RemoveVendorLayerItem( vendor, layerHair ); RemoveVendorLayerItem( vendor, layerBeard ); - SetVendorRaceGenderBody( vendor, !isElf, isFemale ); - var newHairStyles = GetVendorHairStyles( vendor ); + var newHairStyles = humanHairStyles; + var newIsElf = ( vendor.id == 0x025D || vendor.id == 0x025E ); + var newIsFemale = ( vendor.id == 0x0191 || vendor.id == 0x025E ); + + if( newIsElf ) + newHairStyles = newIsFemale ? femaleElfHairStyles : maleElfHairStyles; + if( newHairStyles.length > 0 ) - SetVendorHairStyleByLayer( vendor, newHairStyles[0].itemID ); + SetVendorLayerItem( vendor, layerHair, newHairStyles[0].itemID, 0, "vendor hair" ); ShowVendorCustomizeGump( pUser, vendor ); return; @@ -1919,7 +1562,11 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) { var hairIndex = pButton - 0x1000; if( hairIndex >= 0 && hairIndex < hairStyles.length ) - SetVendorHairStyleByLayer( vendor, hairStyles[hairIndex].itemID ); + { + var oldHairItem = vendor.FindItemLayer( layerHair ); + var oldHairHue = ValidateObject( oldHairItem ) ? oldHairItem.colour : 0; + SetVendorLayerItem( vendor, layerHair, hairStyles[hairIndex].itemID, oldHairHue, "vendor hair" ); + } ShowVendorCustomizeGump( pUser, vendor ); return; @@ -1928,8 +1575,12 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton >= 0x2000 && pButton < ( 0x2000 + 256 ) ) { var beardIndex = pButton - 0x2000; - if( VendorCanHaveBeard( vendor ) && beardIndex >= 0 && beardIndex < humanBeardStyles.length ) - SetVendorBeardStyleByLayer( vendor, humanBeardStyles[beardIndex].itemID ); + if( !isElf && !isFemale && beardIndex >= 0 && beardIndex < humanBeardStyles.length ) + { + var oldBeardItem = vendor.FindItemLayer( layerBeard ); + var oldBeardHue = ValidateObject( oldBeardItem ) ? oldBeardItem.colour : 0; + SetVendorLayerItem( vendor, layerBeard, humanBeardStyles[beardIndex].itemID, oldBeardHue, "vendor beard" ); + } ShowVendorCustomizeGump( pUser, vendor ); return; @@ -1937,216 +1588,46 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton >= 0x3000 && pButton < 0x4000 ) { - SetVendorHairHueByLayer( vendor, pButton - 0x3000 ); + SetVendorLayerHue( vendor, layerHair, pButton - 0x3000 ); ShowVendorCustomizeGump( pUser, vendor ); return; } if( pButton >= 0x4000 && pButton < 0x5000 ) { - if( VendorCanHaveBeard( vendor ) ) - SetVendorBeardHueByLayer( vendor, pButton - 0x4000 ); + if( !isElf && !isFemale ) + SetVendorLayerHue( vendor, layerBeard, pButton - 0x4000 ); ShowVendorCustomizeGump( pUser, vendor ); - return; } } -/** @param {Character} vendor @param {number} layer */ -function RemoveVendorLayerItem( vendor, layer ) -{ - if( !ValidateObject( vendor )) - return; - - var layerItem = vendor.FindItemLayer( layer ); - if( ValidateObject( layerItem )) - layerItem.Delete(); -} - -/** @param {Character} vendor @param {number} itemID @param {number} layer @param {number} hue @returns {boolean} */ -function EquipVendorLayerItem( vendor, itemID, layer, hue ) -{ - if( !ValidateObject( vendor )) - return false; - - var socket = null; - if( vendor.socket ) - socket = vendor.socket; - - var itemName = "vendor style item"; - var newItem = CreateBlankItem( socket, vendor, 1, itemName, itemID, hue, "ITEM", false ); - if( !ValidateObject( newItem )) - return false; - - newItem.container = vendor; - newItem.layer = layer; - return true; -} - -/** @param {Character} vendor @param {number} hairItemID */ -function SetVendorHairStyleByLayer( vendor, hairItemID ) -{ - if( !ValidateObject( vendor )) - return; - - var oldHair = vendor.FindItemLayer( layerHair ); - var oldHue = 0; - if( ValidateObject( oldHair )) - oldHue = oldHair.colour; - - RemoveVendorLayerItem( vendor, layerHair ); - - if( hairItemID != 0 ) - EquipVendorLayerItem( vendor, hairItemID, layerHair, oldHue ); -} - -/** @param {Character} vendor @param {number} beardItemID */ -function SetVendorBeardStyleByLayer( vendor, beardItemID ) -{ - if( !ValidateObject( vendor )) - return; - - var oldBeard = vendor.FindItemLayer( layerBeard ); - var oldHue = 0; - if( ValidateObject( oldBeard )) - oldHue = oldBeard.colour; - - RemoveVendorLayerItem( vendor, layerBeard ); - - if( beardItemID != 0 ) - EquipVendorLayerItem( vendor, beardItemID, layerBeard, oldHue ); -} - -/** @param {Character} vendor @param {number} hue */ -function SetVendorHairHueByLayer( vendor, hue ) -{ - if( !ValidateObject( vendor )) - return; - - var hairItem = vendor.FindItemLayer( layerHair ); - if( ValidateObject( hairItem )) - hairItem.colour = hue; -} - -/** @param {Character} vendor @param {number} hue */ -function SetVendorBeardHueByLayer( vendor, hue ) -{ - if( !ValidateObject( vendor )) - return; - - var beardItem = vendor.FindItemLayer( layerBeard ); - if( ValidateObject( beardItem )) - beardItem.colour = hue; -} - -/** @param {Character} vendor @param {number} layer */ -function RemoveVendorEquippedLayer( vendor, layer ) -{ - if( !ValidateObject( vendor )) - return; - - var oldItem = vendor.FindItemLayer( layer ); - if( ValidateObject( oldItem )) - oldItem.Delete(); -} - -/** @param {Character} vendor @param {number} itemID @param {number} layer @param {number} hue @returns {boolean} */ -function EquipVendorItemOnLayer( vendor, itemID, layer, hue ) -{ - if( !ValidateObject( vendor )) - return false; - - var socket = vendor.socket ? vendor.socket : null; - var newItem = CreateBlankItem( socket, vendor, 1, "vendor clothing", itemID, hue, "ITEM", false ); - if( !ValidateObject( newItem )) - return false; - - newItem.container = vendor; - newItem.layer = layer; - return true; -} - -/** @param {Character} vendor @param {number} layer @param {number} itemID */ -function SetVendorClothingByLayer( vendor, layer, itemID ) -{ - if( !ValidateObject( vendor )) - return; - - var oldItem = vendor.FindItemLayer( layer ); - var oldHue = 0; - - if( ValidateObject( oldItem )) - oldHue = oldItem.colour; - - RemoveVendorEquippedLayer( vendor, layer ); - - if( itemID != 0 ) - EquipVendorItemOnLayer( vendor, itemID, layer, oldHue ); -} - -/** @param {Character} vendor @param {number} layer @param {number} hue */ -function SetVendorClothingHueByLayer( vendor, layer, hue ) -{ - if( !ValidateObject( vendor )) - return; - - var layerItem = vendor.FindItemLayer( layer ); - if( ValidateObject( layerItem )) - layerItem.colour = hue; -} - -/** @param {Character} pUser @param {number} categoryIndex */ -function StoreClothingDyeCategory( pUser, categoryIndex ) -{ - if( !ValidateObject( pUser )) - return; - - pUser.SetTempTag( "PlayerVendorClothingDyeCategory", categoryIndex ); -} - -/** @param {Character} pUser @returns {number} */ -function GetStoredClothingDyeCategory( pUser ) -{ - if( !ValidateObject( pUser )) - return -1; - - var categoryIndex = pUser.GetTempTag( "PlayerVendorClothingDyeCategory" ); - if( categoryIndex === null || categoryIndex === undefined || categoryIndex === "" ) - return -1; - - return categoryIndex; -} - /** @param {Character} pUser @param {Character} vendor */ function ShowVendorClothingGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; var socket = pUser.socket; - if( !socket ) - return; - StoreVendorForGump( pUser, vendor ); var myGump = new Gump; myGump.AddPage( 0 ); myGump.AddBackground( 0, 0, 585, 393, 5054 ); myGump.AddBackground( 195, 36, 387, 275, 3000 ); - myGump.AddHTMLGump( 10, 10, 565, 18, false, false, "
" + GetDictionaryEntry( 40086, socket.language ) + "
" ); // VENDOR CLOTHING MENU + myGump.AddHTMLGump( 10, 10, 565, 18, false, false, "
" + GetDictionaryEntry( 40086, socket.language ) + "
" ); - myGump.AddHTMLGump( 60, 355, 150, 18, false, false, GetDictionaryEntry( 18718, socket.language ) ); // OKAY + myGump.AddHTMLGump( 60, 355, 150, 18, false, false, GetDictionaryEntry( 18718, socket.language ) ); myGump.AddButton( 25, 355, 4005, 4007, 1, 0, 5000 ); - myGump.AddHTMLGump( 320, 355, 150, 18, false, false, GetDictionaryEntry( 10267, socket.language )); // BACK + myGump.AddHTMLGump( 320, 355, 150, 18, false, false, GetDictionaryEntry( 10267, socket.language ) ); myGump.AddButton( 285, 355, 4005, 4007, 1, 0, 0x8FFF ); var i; var y = 35; - for( i = 0; i < vendorClothingCategories.length; ++i ) { myGump.AddHTMLGump( 5, y, 150, 25, false, false, vendorClothingCategories[i].name ); @@ -2159,32 +1640,18 @@ function ShowVendorClothingGump( pUser, vendor ) var cat = vendorClothingCategories[i]; myGump.AddPage( 20 + i ); - var entryIndex; - for( entryIndex = 0; entryIndex < cat.entries.length; ++entryIndex ) + for( var entryIndex = 0; entryIndex < cat.entries.length; ++entryIndex ) { var entry = cat.entries[entryIndex]; - var cols = 3; - var startX = 198; - var startY = 38; - var colWidth = 129; - var rowHeight = 67; - var textWidth = 100; - var itemOffsetX = 20; - var itemOffsetY = 25; - var buttonOffsetY = 45; - - if( cat.name == "Held Items" ) - { - cols = 4; - startX = 205; - startY = 42; - colWidth = 92; - rowHeight = 52; - textWidth = 80; - itemOffsetX = 18; - itemOffsetY = 16; - buttonOffsetY = 30; - } + var cols = cat.name == "Held Items" ? 4 : 3; + var startX = cat.name == "Held Items" ? 205 : 198; + var startY = cat.name == "Held Items" ? 42 : 38; + var colWidth = cat.name == "Held Items" ? 92 : 129; + var rowHeight = cat.name == "Held Items" ? 52 : 67; + var textWidth = cat.name == "Held Items" ? 80 : 100; + var itemOffsetX = cat.name == "Held Items" ? 18 : 20; + var itemOffsetY = cat.name == "Held Items" ? 16 : 25; + var buttonOffsetY = cat.name == "Held Items" ? 30 : 45; var x = startX + ( entryIndex % cols ) * colWidth; var ey = startY + Math.floor( entryIndex / cols ) * rowHeight; @@ -2197,11 +1664,11 @@ function ShowVendorClothingGump( pUser, vendor ) if( cat.canDye ) { myGump.AddButton( 300, 315, 4005, 4007, 1, 0, 0x8000 + i ); - myGump.AddHTMLGump( 335, 317, 100, 18, false, false, GetDictionaryEntry( 40087, socket.language )); // Color + myGump.AddHTMLGump( 335, 317, 100, 18, false, false, GetDictionaryEntry( 40087, socket.language ) ); } myGump.AddButton( 430, 315, 4005, 4007, 1, 20 + i, 0x7000 + i ); - myGump.AddHTMLGump( 465, 317, 100, 18, false, false, GetDictionaryEntry( 40088, socket.language )); // Remove + myGump.AddHTMLGump( 465, 317, 100, 18, false, false, GetDictionaryEntry( 40088, socket.language ) ); } myGump.Send( socket ); @@ -2211,24 +1678,21 @@ function ShowVendorClothingGump( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function ShowVendorClothingDyeGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; var socket = pUser.socket; - if( !socket ) - return; - - StoreVendorForGump( pUser, vendor ); - var categoryIndex = GetStoredClothingDyeCategory( pUser ); var title = GetDictionaryEntry( 40091, socket.language ); if( categoryIndex >= 0 && categoryIndex < vendorClothingCategories.length ) title = vendorClothingCategories[categoryIndex].name + " COLOR"; + StoreVendorForGump( pUser, vendor ); + var myGump = new Gump; myGump.AddPage( 0 ); myGump.AddBackground( 0, 0, 370, 370, 0x13BE ); @@ -2236,7 +1700,7 @@ function ShowVendorClothingDyeGump( pUser, vendor ) myGump.AddHTMLGump( 10, 12, 350, 18, false, false, "
" + title + "
" ); myGump.AddPage( 1 ); - myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + GetDictionaryEntry( 40089, socket.language ) + "
" ); // COLOR CATEGORY + myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + GetDictionaryEntry( 40089, socket.language ) + "
" ); var columns = 2; var startX = 20; @@ -2244,8 +1708,7 @@ function ShowVendorClothingDyeGump( pUser, vendor ) var colWidth = 160; var rowHeight = 20; - var i; - for( i = 0; i < vendorHairHueCategories.length; ++i ) + for( var i = 0; i < vendorHairHueCategories.length; ++i ) { var row = Math.floor( i / columns ); var col = i % columns; @@ -2257,7 +1720,7 @@ function ShowVendorClothingDyeGump( pUser, vendor ) } myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 1, 0, 0x8FFE ); - myGump.AddHTMLGump( 45, 342, 120, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK + myGump.AddHTMLGump( 45, 342, 120, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); for( i = 0; i < vendorHairHueCategories.length; ++i ) { @@ -2265,19 +1728,12 @@ function ShowVendorClothingDyeGump( pUser, vendor ) myGump.AddHTMLGump( 10, 42, 350, 18, false, false, "
" + GetVendorHueCategoryName( vendorHairHueCategories[i], socket ) + "
" ); var hues = vendorHairHueCategories[i].hues; - var hueColumns = 3; - var hueStartX = 20; - var hueStartY = 70; - var hueColWidth = 112; - var hueRowHeight = 18; - - var j; - for( j = 0; j < hues.length; ++j ) + for( var j = 0; j < hues.length; ++j ) { - var hueRow = Math.floor( j / hueColumns ); - var hueCol = j % hueColumns; - var hx = hueStartX + ( hueCol * hueColWidth ); - var hy = hueStartY + ( hueRow * hueRowHeight ); + var hueRow = Math.floor( j / 3 ); + var hueCol = j % 3; + var hx = 20 + ( hueCol * 112 ); + var hy = 70 + ( hueRow * 18 ); var hueHex = hues[j].toString( 16 ).toUpperCase(); myGump.AddButton( hx, hy, 0x0A9A, 0x0A9A, 1, 10 + i, 0x9000 + hues[j] ); @@ -2285,10 +1741,10 @@ function ShowVendorClothingDyeGump( pUser, vendor ) } myGump.AddButton( 10, 340, 0xFA5, 0xFA7, 0, 1, 0 ); - myGump.AddHTMLGump( 45, 342, 80, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); // BACK + myGump.AddHTMLGump( 45, 342, 80, 18, false, false, "" + GetDictionaryEntry( 10267, socket.language ) + "" ); myGump.AddButton( 270, 340, 0xFA5, 0xFA7, 1, 0, 0x8FFE ); - myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 40090, socket.language ) + "" ); // DONE + myGump.AddHTMLGump( 305, 342, 60, 18, false, false, "" + GetDictionaryEntry( 40090, socket.language ) + "" ); } myGump.Send( socket ); @@ -2298,10 +1754,10 @@ function ShowVendorClothingDyeGump( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor @param {number} pButton */ function HandleVendorClothingButton( pUser, vendor, pButton ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) return; - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; if( pButton == 0x8FFF ) @@ -2321,7 +1777,7 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) var removeCatIndex = pButton - 0x7000; if( removeCatIndex >= 0 && removeCatIndex < vendorClothingCategories.length ) { - RemoveVendorEquippedLayer( vendor, vendorClothingCategories[removeCatIndex].layer ); + RemoveVendorLayerItem( vendor, vendorClothingCategories[removeCatIndex].layer ); ShowVendorClothingGump( pUser, vendor ); } return; @@ -2329,16 +1785,18 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) if( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 ) ) { - var entryVal = pButton - 0x5000; - var catIndex = Math.floor( entryVal / 100 ); - var entryIndex = entryVal % 100; + var entryValue = pButton - 0x5000; + var catIndex = Math.floor( entryValue / 100 ); + var entryIndex = entryValue % 100; if( catIndex >= 0 && catIndex < vendorClothingCategories.length ) { var cat = vendorClothingCategories[catIndex]; if( entryIndex >= 0 && entryIndex < cat.entries.length ) { - SetVendorClothingByLayer( vendor, cat.layer, cat.entries[entryIndex].itemID ); + var oldClothingItem = vendor.FindItemLayer( cat.layer ); + var oldClothingHue = ValidateObject( oldClothingItem ) ? oldClothingItem.colour : 0; + SetVendorLayerItem( vendor, cat.layer, cat.entries[entryIndex].itemID, oldClothingHue, "vendor clothing" ); ShowVendorClothingGump( pUser, vendor ); } } @@ -2365,169 +1823,244 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) { var dyeCat = vendorClothingCategories[storedCatIndex]; if( dyeCat.canDye ) - SetVendorClothingHueByLayer( vendor, dyeCat.layer, hueValue ); + SetVendorLayerHue( vendor, dyeCat.layer, hueValue ); } ShowVendorClothingDyeGump( pUser, vendor ); - return; } } /** @param {string} text @returns {string} */ function TrimString( text ) { - if( text == null || text == undefined ) + if( text === null || text === undefined ) return ""; return ( "" + text ).replace( /^\s+|\s+$/g, "" ); } -/** @param {Character} vendor @returns {string} */ -function GetVendorShopTitle( vendor ) -{ - if( !IsPlayerVendor( vendor )) - return ""; - - if( vendor.title == null || vendor.title == undefined ) - return ""; - - return "" + vendor.title; -} - /** @param {Character} pUser @param {Character} vendor */ function BeginRenameVendor( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) - return; - - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - var socket = pUser.socket; - if( !socket ) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; StoreVendorForGump( pUser, vendor ); pUser.SpeechInput( 20, vendor ); - socket.SysMessage( GetDictionaryEntry( 40050, socket.language )); // Enter a new vendor name. + pUser.socket.SysMessage( GetDictionaryEntry( 40050, pUser.socket.language ) ); } /** @param {Character} pUser @param {Character} vendor */ function BeginRenameVendorShop( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) - return; - - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - var socket = pUser.socket; - if( !socket ) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; StoreVendorForGump( pUser, vendor ); pUser.SpeechInput( 21, vendor ); - socket.SysMessage( GetDictionaryEntry( 40051, socket.language )); // Enter a new shop name. + pUser.socket.SysMessage( GetDictionaryEntry( 40051, pUser.socket.language ) ); } /** @param {Character} pUser @param {Character} vendor */ function BeginDepositVendorGold( pUser, vendor ) { - if( !ValidateObject( pUser ) || !IsPlayerVendor( vendor )) + if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) return; - if( !IsVendorOwner( vendor, pUser )) - return; - - var socket = pUser.socket; - if( !socket ) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; StoreVendorForGump( pUser, vendor ); pUser.SpeechInput( 22, vendor ); - socket.SysMessage( GetDictionaryEntry( 40052, socket.language )); // Enter the amount of gold you wish to deposit. + pUser.socket.SysMessage( GetDictionaryEntry( 40052, pUser.socket.language ) ); } -/** @type { ( myChar: Character, targObj: BaseObject, mySpeech: string, mySpeechId: number ) => void } */ -function onSpeechInput( pUser, targObj, pSpeech, pSpeechID ) +/** @type { ( pUser: Character, targChar: Character, nonMouseClickEvent: boolean ) => boolean } */ +function onCharDoubleClick( pUser, targChar, nonMouseClickEvent ) +{ + if( !ValidateObject( pUser ) || !ValidateObject( targChar ) ) + return false; + + if( nonMouseClickEvent ) + return true; + + if( targChar.aitype != 17 ) + return true; + + if( !CheckVendorUpkeep( targChar, pUser ) ) + return false; + + if( ValidateObject( targChar.owner ) && targChar.owner.serial == pUser.serial ) + { + if( pUser.socket ) + { + StoreVendorForGump( pUser, targChar ); + ShowPlayerVendorOwnerGump( pUser.socket, targChar ); + } + return false; + } + + if( ValidateObject( targChar.multi ) && targChar.multi.IsOnBanList( pUser ) ) + { + if( pUser.socket ) + pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language ) ); + return false; + } + + OpenVendorBackpack( pUser, targChar ); + return false; +} + +/** @param {string} speech @param {Character} personTalking @param {BaseObject} talkingTo @returns {number} */ +function onSpeech( speech, personTalking, talkingTo ) +{ + if( !ValidateObject( personTalking ) || !ValidateObject( talkingTo ) ) + return 0; + + if( talkingTo.aitype != 17 ) + return 0; + + return HandleVendorSpeechCommand( personTalking, talkingTo, speech ); +} + +/** @param {Socket} pSock @param {number} pButton @param {GumpData} gumpData */ +function onGumpPress( pSock, pButton, gumpData ) { - if( !ValidateObject( pUser )) + var pUser = pSock.currentChar; + if( !ValidateObject( pUser ) ) return; - var socket = pUser.socket; - if( !socket ) + var vendor = GetStoredVendorForGump( pUser ); + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + return; + + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) + return; + + if( !CheckVendorUpkeep( vendor, pUser ) ) + return; + + if( pButton == 5000 || pButton == 5001 || pButton == 5002 || pButton == 5004 || pButton == 5006 || pButton == 5007 || + ( pButton >= 0x1000 && pButton < ( 0x1000 + 256 ) ) || + ( pButton >= 0x2000 && pButton < ( 0x2000 + 256 ) ) || + ( pButton >= 0x3000 && pButton < 0x4000 ) || + ( pButton >= 0x4000 && pButton < 0x5000 ) ) + { + HandleVendorCustomizeButton( pUser, vendor, pButton ); + return; + } + + if( pButton == 0x8FFF || pButton == 0x8FFE || + ( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 ) ) || + ( pButton >= 0x7000 && pButton < ( 0x7000 + 100 ) ) || + ( pButton >= 0x8000 && pButton < ( 0x8000 + vendorClothingCategories.length ) ) || + ( pButton >= 0x9000 && pButton < ( 0x9000 + 0x1000 ) ) ) + { + HandleVendorClothingButton( pUser, vendor, pButton ); + return; + } + + switch( pButton ) + { + case 0: break; + case 1: OpenVendorBackpack( pUser, vendor ); break; + case 2: ShowVendorCustomizeGump( pUser, vendor ); break; + case 3: + CollectVendorGold( pUser, vendor ); + ShowPlayerVendorOwnerGump( pSock, vendor ); + break; + case 4: BeginDepositVendorGold( pUser, vendor ); break; + case 5: + FlushBankToHeld( pUser, vendor ); + ShowPlayerVendorOwnerGump( pSock, vendor ); + break; + case 6: DismissVendor( pUser, vendor ); break; + case 7: BeginRenameVendor( pUser, vendor ); break; + case 8: BeginRenameVendorShop( pUser, vendor ); break; + case 9: ShowVendorClothingGump( pUser, vendor ); break; + } +} + +/** @type { ( pUser: Character, targObj: BaseObject, pSpeech: string, pSpeechID: number ) => void } */ +function onSpeechInput( pUser, targObj, pSpeech, pSpeechID ) +{ + if( !ValidateObject( pUser ) || !pUser.socket ) return; + var socket = pUser.socket; var vendor = GetStoredVendorForGump( pUser ); - if( !IsPlayerVendor( vendor )) + if( !ValidateObject( vendor ) || vendor.aitype != 17 ) { - socket.SysMessage( GetDictionaryEntry( 40053, socket.language )); // That is not a valid player vendor. + socket.SysMessage( GetDictionaryEntry( 40053, socket.language ) ); return; } - if( !IsVendorOwner( vendor, pUser )) + if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - socket.SysMessage( GetDictionaryEntry( 40028, socket.language )); // I don't work for you! + socket.SysMessage( GetDictionaryEntry( 40028, socket.language ) ); return; } - if( !CheckVendorUpkeep( vendor, pUser )) + if( !CheckVendorUpkeep( vendor, pUser ) ) return; var newText = TrimString( pSpeech ); if( newText == "" ) { - socket.SysMessage( GetDictionaryEntry( 9270, socket.language )); // That name is too short, or no name was entered. + socket.SysMessage( GetDictionaryEntry( 9270, socket.language ) ); return; } switch( pSpeechID ) { - case 20: // Rename vendor + case 20: if( newText.length > 50 ) { - socket.SysMessage( GetDictionaryEntry( 9271, socket.language )); // That name is too long. Maximum 50 chars. + socket.SysMessage( GetDictionaryEntry( 9271, socket.language ) ); return; } vendor.name = newText; vendor.Refresh(); - - socket.SysMessage( GetDictionaryEntry( 40054, socket.language ), vendor.name ); // Your vendor is now named: %s + socket.SysMessage( GetDictionaryEntry( 40054, socket.language ), vendor.name ); ShowPlayerVendorOwnerGump( socket, vendor ); break; - case 21: // Rename shop title + case 21: if( newText.length > 40 ) { - socket.SysMessage( GetDictionaryEntry( 40055, socket.language )); // That shop name is too long. Maximum 40 chars. + socket.SysMessage( GetDictionaryEntry( 40055, socket.language ) ); return; } vendor.title = "Shop Name: " + newText; vendor.Refresh(); - socket.SysMessage( GetDictionaryEntry( 40056, socket.language ), vendor.title ); // Your shop title is now: %s + socket.SysMessage( GetDictionaryEntry( 40056, socket.language ), vendor.title ); ShowPlayerVendorOwnerGump( socket, vendor ); break; - case 22: // Deposit vendor gold - if( !/^\d+$/.test( newText )) + + case 22: + if( !/^\d+$/.test( newText ) ) { - socket.SysMessage( GetDictionaryEntry( 40057, socket.language )); // You must enter a valid gold amount. + socket.SysMessage( GetDictionaryEntry( 40057, socket.language ) ); return; } var depositAmount = parseInt( newText, 10 ); if( isNaN( depositAmount ) || depositAmount <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40018, socket.language )); // Invalid deposit amount. + socket.SysMessage( GetDictionaryEntry( 40018, socket.language ) ); return; } DepositToVendorBank( pUser, vendor, depositAmount ); ShowPlayerVendorOwnerGump( socket, vendor ); break; - - default: - break; } } \ No newline at end of file From 093a1e2c022207c07126f364b139b9bb72aa375d Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Tue, 5 May 2026 20:59:21 -0500 Subject: [PATCH 07/26] Update cServerData.cpp --- source/cServerData.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 3889bd36b..22aed960f 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -416,7 +416,13 @@ const std::map CServerData::uox3IniCaseValue {"SPEEDHACKMAXCREDIT", 403}, {"SPEEDHACKGRACETHRESHOLD", 404}, {"SPEEDHACKTHROTTLEPENALTY", 405}, - {"EVENTMANAGERSYSTEM", 406} + {"EVENTMANAGERSYSTEM", 406}, + {"VENDORCHARGESENABLED", 407}, + {"VENDORBASECHARGE", 408}, + {"VENDORCHARGEHOURS", 409}, + {"VENDORUSEITEMFEES", 410}, + {"VENDORITEMFEEDIVISOR", 411}, + {"VENDORITEMFEEAMOUNT", 412}, }; constexpr auto MAX_TRACKINGTARGETS = 128; constexpr auto SKILLTOTALCAP = 7000; @@ -538,6 +544,12 @@ constexpr auto BIT_HOUSEITEMSDELETEONDECAY = UI32( 112 ); constexpr auto BIT_HOUSEGRANDFATHERED = UI32( 113 ); constexpr auto BIT_SPEEDHACKDETECTION = UI32( 119 ); constexpr auto BIT_EVENTMANAGERSYSTEM = UI32( 120 ); +constexpr auto BIT_VENDORCHARGESENABLED = UI32( 121 ); +constexpr auto BIT_VENDORBASECHARGE = UI32( 122 ); +constexpr auto BIT_VENDORCHARGEHOURS = UI32( 123 ); +constexpr auto BIT_VENDORUSEITEMFEES = UI32( 124 ); +constexpr auto BIT_VENDORITEMFEEDIVISOR = UI32( 125 ); +constexpr auto BIT_VENDORITEMFEEAMOUNT = UI32( 126 ); // New uox3.ini format lookup From fd4697fdd8bb5196685813d5cc8b87b28d09a765 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Tue, 5 May 2026 21:25:01 -0500 Subject: [PATCH 08/26] update --- source/SEFunctions.cpp | 18 ++++++ source/cServerData.cpp | 134 ++++++++++++++++++++++++++++++++++++++--- source/cServerData.h | 27 ++++++++- 3 files changed, 169 insertions(+), 10 deletions(-) diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp index 84a67872a..5b3674c22 100644 --- a/source/SEFunctions.cpp +++ b/source/SEFunctions.cpp @@ -5777,6 +5777,24 @@ JSBool SE_GetServerSetting( JSContext *cx, uintN argc, jsval *vp ) case 407: // LOGINQUESTENABLED JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->LoginQuestEnabled() ) ); break; + case 408: // VENDORCHARGESENABLED + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorChargesEnabled() ) ); + break; + case 409: // VENDORBASECHARGE + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorBaseCharge() ) ) ); + break; + case 410: // VENDORCHARGEHOURS + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorChargeHours() ) ) ); + break; + case 411: // VENDORUSEITEMFEES + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorUseItemFees() ) ); + break; + case 412: // VENDORITEMFEEDIVISOR + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeDivisor() ) ) ); + break; + case 413: // VENDORITEMFEEAMOUNT + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeAmount() ) ) ); + break; default: ScriptError( cx, "GetServerSetting: Invalid server setting name provided" ); return false; diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 012214450..2eade127e 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -418,7 +418,7 @@ const std::map CServerData::uox3IniCaseValue {"SPEEDHACKGRACETHRESHOLD", 404}, {"SPEEDHACKTHROTTLEPENALTY", 405}, {"EVENTMANAGERSYSTEM", 406}, - {"LOGINQUESTENABLED"s, 407}, + {"LOGINQUESTENABLED"s, 407}, {"VENDORCHARGESENABLED", 408}, {"VENDORBASECHARGE", 409}, {"VENDORCHARGEHOURS", 410}, @@ -546,14 +546,10 @@ constexpr auto BIT_HOUSEITEMSDELETEONDECAY = UI32( 112 ); constexpr auto BIT_HOUSEGRANDFATHERED = UI32( 113 ); constexpr auto BIT_SPEEDHACKDETECTION = UI32( 119 ); constexpr auto BIT_EVENTMANAGERSYSTEM = UI32( 120 ); -constexpr auto BIT_QUESTSYSTEMENABLED = UI32( 121 ); -constexpr auto BIT_LOGINQUESTENABLED = UI32( 122 ); -constexpr auto BIT_VENDORCHARGESENABLED = UI32( 122 ); -constexpr auto BIT_VENDORBASECHARGE = UI32( 123 ); -constexpr auto BIT_VENDORCHARGEHOURS = UI32( 124 ); -constexpr auto BIT_VENDORUSEITEMFEES = UI32( 125 ); -constexpr auto BIT_VENDORITEMFEEDIVISOR = UI32( 126 ); -constexpr auto BIT_VENDORITEMFEEAMOUNT = UI32( 127 ); +constexpr auto BIT_QUESTSYSTEMENABLED = UI32( 121 ); +constexpr auto BIT_LOGINQUESTENABLED = UI32( 122 ); +constexpr auto BIT_VENDORCHARGESENABLED = UI32( 123 ); +constexpr auto BIT_VENDORUSEITEMFEES = UI32( 124 ); // New uox3.ini format lookup @@ -965,6 +961,14 @@ auto CServerData::ResetDefaults() -> void AmbientFootsteps( false ); ServerCommandPrefix( '\'' ); + // Player vendor upkeep settings + VendorChargesEnabled( true ); + VendorBaseCharge( 60 ); + VendorChargeHours( 24 ); + VendorUseItemFees( true ); + VendorItemFeeDivisor( 500 ); + VendorItemFeeAmount( 3 ); + // SPEEDUP CheckSpawnRegionSpeed( 30 ); CheckItemsSpeed( 1.5 ); @@ -5487,6 +5491,90 @@ auto CServerData::KickOnAssistantSilence( bool nVal ) -> void boolVals.set( BIT_KICKONASSISTANTSILENCE, nVal ); } +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorChargesEnabled() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets whether player vendors charge upkeep fees +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorChargesEnabled() const -> bool +{ + return boolVals.test( BIT_VENDORCHARGESENABLED ); +} +auto CServerData::VendorChargesEnabled( bool newVal ) -> void +{ + boolVals.set( BIT_VENDORCHARGESENABLED, newVal ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorBaseCharge() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the flat gold fee charged to player vendors each upkeep period +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorBaseCharge() const -> SI16 +{ + return vendorBaseCharge; +} +auto CServerData::VendorBaseCharge( SI16 value ) -> void +{ + vendorBaseCharge = value; +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorChargeHours() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets how often player vendors are charged upkeep fees, in real hours +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorChargeHours() const -> SI16 +{ + return vendorChargeHours; +} +auto CServerData::VendorChargeHours( SI16 value ) -> void +{ + vendorChargeHours = value; +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorUseItemFees() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets whether listed item values add extra player vendor upkeep fees +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorUseItemFees() const -> bool +{ + return boolVals.test( BIT_VENDORUSEITEMFEES ); +} +auto CServerData::VendorUseItemFees( bool newVal ) -> void +{ + boolVals.set( BIT_VENDORUSEITEMFEES, newVal ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorItemFeeDivisor() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the listed item value divisor used for player vendor item fees +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorItemFeeDivisor() const -> SI16 +{ + return vendorItemFeeDivisor; +} +auto CServerData::VendorItemFeeDivisor( SI16 value ) -> void +{ + vendorItemFeeDivisor = value; +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorItemFeeAmount() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the gold fee added per player vendor item fee divisor step +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorItemFeeAmount() const -> SI16 +{ + return vendorItemFeeAmount; +} +auto CServerData::VendorItemFeeAmount( SI16 value ) -> void +{ + vendorItemFeeAmount = value; +} + //o------------------------------------------------------------------------------------------------o //| Function - CServerData::SaveIni() //| Date - 02/21/2002 @@ -5854,6 +5942,15 @@ auto CServerData::SaveIni( const std::string &filename ) -> bool ofsOutput << "PETBONDINGENABLED=" << ( PetBondingEnabled() ? 1 : 0 ) << '\n'; ofsOutput << "}" << '\n'; + ofsOutput << '\n' << "[playervendor]" << '\n' << "{" << '\n'; + ofsOutput << "VENDORCHARGESENABLED=" << ( VendorChargesEnabled() ? 1 : 0 ) << '\n'; + ofsOutput << "VENDORBASECHARGE=" << VendorBaseCharge() << '\n'; + ofsOutput << "VENDORCHARGEHOURS=" << VendorChargeHours() << '\n'; + ofsOutput << "VENDORUSEITEMFEES=" << ( VendorUseItemFees() ? 1 : 0 ) << '\n'; + ofsOutput << "VENDORITEMFEEDIVISOR=" << VendorItemFeeDivisor() << '\n'; + ofsOutput << "VENDORITEMFEEAMOUNT=" << VendorItemFeeAmount() << '\n'; + ofsOutput << "}" << '\n'; + ofsOutput << '\n' << "[speedup]" << '\n' << "{" << '\n'; ofsOutput << "CHECKITEMS=" << CheckItemsSpeed() << '\n'; ofsOutput << "CHECKBOATS=" << CheckBoatSpeed() << '\n'; @@ -7599,6 +7696,25 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) break; case 407: // LOGINQUESTENABLED LoginQuestEnabled( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); + break; + case 408: // VENDORCHARGESENABLED + VendorChargesEnabled( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); + break; + case 409: // VENDORBASECHARGE + VendorBaseCharge( static_cast( std::stoi( value ))); + break; + case 410: // VENDORCHARGEHOURS + VendorChargeHours( static_cast( std::stoi( value ))); + break; + case 411: // VENDORUSEITEMFEES + VendorUseItemFees( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); + break; + case 412: // VENDORITEMFEEDIVISOR + VendorItemFeeDivisor( static_cast( std::stoi( value ))); + break; + case 413: // VENDORITEMFEEAMOUNT + VendorItemFeeAmount( static_cast( std::stoi( value ))); + break; default: rValue = false; break; diff --git a/source/cServerData.h b/source/cServerData.h index 9bed4047b..1484d0866 100644 --- a/source/cServerData.h +++ b/source/cServerData.h @@ -212,7 +212,7 @@ class CServerData // Once over 62, bitsets are costly. std::vector has a special exception in the c++ specificaiton, to minimize wasted space for bools // These should be updated - std::bitset<123> boolVals; // Many values stored this way, rather than using bools. + std::bitset<125> boolVals; // Many values stored this way, rather than using bools. std::bitset<64> spawnRegionsFacets; // Used to determine which facets to enable spawn regions for, set in UOX>INI std::bitset<64> moongateFacets; // Used to determine which facets to enable moongates for, set in UOX>INI @@ -337,6 +337,13 @@ class CServerData UI16 petLoyaltyGainOnSuccess; // The default amount of pet loyalty gained on successful use of a pet command UI16 petLoyaltyLossOnFailure; // The default amount of pet loyalty lost on a failed attempt to use a pet command + bool vendorChargesEnabled; // Master toggle for player vendor upkeep charges + SI16 vendorBaseCharge; // Flat fee per vendor upkeep charge period + SI16 vendorChargeHours; // Number of real hours between vendor upkeep charges + bool vendorUseItemFees; // Add item-based upkeep fees from listed item prices + SI16 vendorItemFeeDivisor; // Listed item value divisor used for vendor item fees + SI16 vendorItemFeeAmount; // Fee added per divisor step + // SpeedUp R64 npcWalkingSpeed; // Speed at which walking NPCs move R64 npcRunningSpeed; // Speed at which running NPCs move @@ -1387,6 +1394,24 @@ class CServerData auto APSDelayMaxCap() const -> UI16; auto APSDelayMaxCap( UI16 newVal ) -> void; + auto VendorChargesEnabled( bool value ) -> void; + auto VendorChargesEnabled() const -> bool; + + auto VendorBaseCharge( SI16 value ) -> void; + SI16 VendorBaseCharge() const; + + auto VendorChargeHours( SI16 value ) -> void; + SI16 VendorChargeHours() const; + + auto VendorUseItemFees( bool value ) -> void; + auto VendorUseItemFees() const -> bool; + + auto VendorItemFeeDivisor( SI16 value ) -> void; + SI16 VendorItemFeeDivisor() const; + + auto VendorItemFeeAmount( SI16 value ) -> void; + SI16 VendorItemFeeAmount() const; + SI16 ServerTimeDay() const; UI08 ServerTimeHours() const; UI08 ServerTimeMinutes() const; From de4784cbf8fe452f469e4c0ec443df1813dfb5db Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Tue, 5 May 2026 21:30:33 -0500 Subject: [PATCH 09/26] Update uox.ini --- data/uox.ini | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data/uox.ini b/data/uox.ini index ec78aaded..f4b3d05fa 100644 --- a/data/uox.ini +++ b/data/uox.ini @@ -243,6 +243,16 @@ PETLOYALTYRATE=900 PETBONDINGENABLED=0 } +[playervendor] +{ +VENDORCHARGESENABLED=1 +VENDORBASECHARGE=60 +VENDORCHARGEHOURS=24 +VENDORUSEITEMFEES=1 +VENDORITEMFEEDIVISOR=500 +VENDORITEMFEEAMOUNT=3 +} + [speedup] { CHECKITEMS=1.5 From 1857c99afbc72ea9eead2d8fa0ef2f3aed388782 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 10 May 2026 22:31:13 -0500 Subject: [PATCH 10/26] Missed couple settings --- data/js/npc/ai/playervendor.js | 16 ++++++------- source/SEFunctions.cpp | 22 ++++++++++------- source/cServerData.cpp | 43 +++++++++++++++++++++++++++++++++- source/cServerData.h | 10 +++++++- 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 4fdf29d61..aba8508de 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -5,20 +5,20 @@ // Max amount of money the vendor can hold in the bank. // Held gold is not included in this limit, but will // be used first to pay upkeep before bank funds are used. -var vendorMaxFunds = 1000000; +var vendorMaxFunds = GetServerSetting( "VendorMaxFunds" ); // If true, returned vendor belongings skip player backpack entirely. // Items, gold and vendor deed will try bank box first, then drop at vendor location. // If false, belongings try backpack first, then bank box, then ground. -var onlyReturnToBank = true; +const onlyReturnToBank = GetServerSetting( "onlyReturnToBank" ); // Vendor upkeep settings -var vendorChargesEnabled = true; // Master toggle for vendor upkeep charges -var vendorBaseCharge = 60; // Flat fee per charge period -var vendorChargeHours = 24; // Charge every X real hours -var vendorUseItemFees = true; // Add item-based fee from listed item prices -var vendorItemFeeDivisor = 500; // 3 gold per 500 worth of one item -var vendorItemFeeAmount = 3; // Fee added per divisor step +var vendorChargesEnabled = GetServerSetting( "VendorChargesEnabled" );; // Master toggle for vendor upkeep charges +var vendorBaseCharge = GetServerSetting( "VendorBaseCharge" ); // Flat fee per charge period +var vendorChargeHours = GetServerSetting( "VendorChargeHours" ); // Charge every X real hours +var vendorUseItemFees = GetServerSetting( "VendorUseItemFees" ); // Add item-based fee from listed item prices +var vendorItemFeeDivisor = GetServerSetting( "VendorItemFeeDivisor" ); // 3 gold per 500 worth of one item +var vendorItemFeeAmount = GetServerSetting( "VendorItemFeeAmount" ); // Fee added per divisor step var layerOneHand = 0x01; var layerTwoHand = 0x02; diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp index 5b3674c22..87a1a2667 100644 --- a/source/SEFunctions.cpp +++ b/source/SEFunctions.cpp @@ -5775,25 +5775,31 @@ JSBool SE_GetServerSetting( JSContext *cx, uintN argc, jsval *vp ) JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->EventManagerSystem() )); break; case 407: // LOGINQUESTENABLED - JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->LoginQuestEnabled() ) ); + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->LoginQuestEnabled() )); break; case 408: // VENDORCHARGESENABLED - JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorChargesEnabled() ) ); + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorChargesEnabled() )); break; case 409: // VENDORBASECHARGE - JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorBaseCharge() ) ) ); + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorBaseCharge() ))); break; case 410: // VENDORCHARGEHOURS - JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorChargeHours() ) ) ); + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorChargeHours() ))); break; - case 411: // VENDORUSEITEMFEES - JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorUseItemFees() ) ); + case 411: // VENDORUSEITEMFEES` + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorUseItemFees() )); break; case 412: // VENDORITEMFEEDIVISOR - JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeDivisor() ) ) ); + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeDivisor() ))); break; case 413: // VENDORITEMFEEAMOUNT - JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeAmount() ) ) ); + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeAmount() ))); + break; + case 414: // ONLYRETURNTOBANK` + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->OnlyReturnToBank() )); + break; + case 415: // VENDORMAXFUNDS + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorMaxFunds() ))); break; default: ScriptError( cx, "GetServerSetting: Invalid server setting name provided" ); diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 2eade127e..92a602348 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -424,7 +424,9 @@ const std::map CServerData::uox3IniCaseValue {"VENDORCHARGEHOURS", 410}, {"VENDORUSEITEMFEES", 411}, {"VENDORITEMFEEDIVISOR", 412}, - {"VENDORITEMFEEAMOUNT", 413} + {"VENDORITEMFEEAMOUNT", 413}, + {"ONLYRETURNTOBANK", 414}, + {"VENDORMAXFUNDS", 415}, }; constexpr auto MAX_TRACKINGTARGETS = 128; constexpr auto SKILLTOTALCAP = 7000; @@ -550,6 +552,7 @@ constexpr auto BIT_QUESTSYSTEMENABLED = UI32( 121 ); constexpr auto BIT_LOGINQUESTENABLED = UI32( 122 ); constexpr auto BIT_VENDORCHARGESENABLED = UI32( 123 ); constexpr auto BIT_VENDORUSEITEMFEES = UI32( 124 ); +constexpr auto BIT_ONLYRETURNTOBANK = UI32( 125 ); // New uox3.ini format lookup @@ -968,6 +971,8 @@ auto CServerData::ResetDefaults() -> void VendorUseItemFees( true ); VendorItemFeeDivisor( 500 ); VendorItemFeeAmount( 3 ); + OnlyReturnToBank( true ); + VendorMaxFunds( 1000000 ); // SPEEDUP CheckSpawnRegionSpeed( 30 ); @@ -5575,6 +5580,34 @@ auto CServerData::VendorItemFeeAmount( SI16 value ) -> void vendorItemFeeAmount = value; } +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::OnlyReturnToBank() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets returned vendor belongings skip player backpack entirely +//o------------------------------------------------------------------------------------------------o +auto CServerData::OnlyReturnToBank() const -> bool +{ + return boolVals.test( BIT_ONLYRETURNTOBANK ); +} +auto CServerData::OnlyReturnToBank( bool newVal ) -> void +{ + boolVals.set( BIT_ONLYRETURNTOBANK, newVal ); +} + +//o------------------------------------------------------------------------------------------------o +//| Function - CServerData::VendorMaxFunds() +//o------------------------------------------------------------------------------------------------o +//| Purpose - Gets/Sets the Max amount of money the vendor can hold in the bank. +//o------------------------------------------------------------------------------------------------o +auto CServerData::VendorMaxFunds() const -> SI16 +{ + return vendorMaxFunds; +} +auto CServerData::VendorMaxFunds( SI16 value ) -> void +{ + vendorMaxFunds = value; +} + //o------------------------------------------------------------------------------------------------o //| Function - CServerData::SaveIni() //| Date - 02/21/2002 @@ -5949,6 +5982,8 @@ auto CServerData::SaveIni( const std::string &filename ) -> bool ofsOutput << "VENDORUSEITEMFEES=" << ( VendorUseItemFees() ? 1 : 0 ) << '\n'; ofsOutput << "VENDORITEMFEEDIVISOR=" << VendorItemFeeDivisor() << '\n'; ofsOutput << "VENDORITEMFEEAMOUNT=" << VendorItemFeeAmount() << '\n'; + ofsOutput << "ONLYRETURNTOBANK=" << ( OnlyReturnToBank() ? 1 : 0 ) << '\n'; + ofsOutput << "VENDORMAXFUNDS=" << VendorMaxFunds() << '\n'; ofsOutput << "}" << '\n'; ofsOutput << '\n' << "[speedup]" << '\n' << "{" << '\n'; @@ -7715,6 +7750,12 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) case 413: // VENDORITEMFEEAMOUNT VendorItemFeeAmount( static_cast( std::stoi( value ))); break; + case 414: // ONLYRETURNTOBANK + OnlyReturnToBank( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); + break; + case 415: // VENDORMAXFUNDS + VendorMaxFunds( static_cast( std::stoi( value ))); + break; default: rValue = false; break; diff --git a/source/cServerData.h b/source/cServerData.h index 1484d0866..3f2629492 100644 --- a/source/cServerData.h +++ b/source/cServerData.h @@ -212,7 +212,7 @@ class CServerData // Once over 62, bitsets are costly. std::vector has a special exception in the c++ specificaiton, to minimize wasted space for bools // These should be updated - std::bitset<125> boolVals; // Many values stored this way, rather than using bools. + std::bitset<126> boolVals; // Many values stored this way, rather than using bools. std::bitset<64> spawnRegionsFacets; // Used to determine which facets to enable spawn regions for, set in UOX>INI std::bitset<64> moongateFacets; // Used to determine which facets to enable moongates for, set in UOX>INI @@ -343,6 +343,8 @@ class CServerData bool vendorUseItemFees; // Add item-based upkeep fees from listed item prices SI16 vendorItemFeeDivisor; // Listed item value divisor used for vendor item fees SI16 vendorItemFeeAmount; // Fee added per divisor step + bool onlyReturnToBank; // returned vendor belongings skip player backpack entirely + SI16 vendorMaxFunds; // Max amount of money the vendor can hold in the bank. // SpeedUp R64 npcWalkingSpeed; // Speed at which walking NPCs move @@ -1412,6 +1414,12 @@ class CServerData auto VendorItemFeeAmount( SI16 value ) -> void; SI16 VendorItemFeeAmount() const; + auto OnlyReturnToBank( bool value ) -> void; + auto OnlyReturnToBank() const -> bool; + + auto VendorMaxFunds( SI16 value ) -> void; + SI16 VendorMaxFunds() const; + SI16 ServerTimeDay() const; UI08 ServerTimeHours() const; UI08 ServerTimeMinutes() const; From 2f502a7bfcf270b8452c6f60f4c80edfec061ad6 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Fri, 5 Jun 2026 20:56:46 -0500 Subject: [PATCH 11/26] Update --- data/js/npc/ai/playervendor.js | 90 +++++++++++++++++----------------- data/uox.ini | 2 +- source/SEFunctions.cpp | 6 +-- source/cServerData.cpp | 22 ++++----- source/cServerData.h | 6 +-- 5 files changed, 64 insertions(+), 62 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index aba8508de..a93992a4a 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -10,36 +10,38 @@ var vendorMaxFunds = GetServerSetting( "VendorMaxFunds" ); // If true, returned vendor belongings skip player backpack entirely. // Items, gold and vendor deed will try bank box first, then drop at vendor location. // If false, belongings try backpack first, then bank box, then ground. -const onlyReturnToBank = GetServerSetting( "onlyReturnToBank" ); +var onlyReturnToBank = GetServerSetting( "onlyReturnToBank" ); // Vendor upkeep settings var vendorChargesEnabled = GetServerSetting( "VendorChargesEnabled" );; // Master toggle for vendor upkeep charges var vendorBaseCharge = GetServerSetting( "VendorBaseCharge" ); // Flat fee per charge period var vendorChargeHours = GetServerSetting( "VendorChargeHours" ); // Charge every X real hours -var vendorUseItemFees = GetServerSetting( "VendorUseItemFees" ); // Add item-based fee from listed item prices +var vendorItemFeesEnabled = GetServerSetting( "VendorUseItemFeesEnabled" ); // Add item-based fee from listed item prices var vendorItemFeeDivisor = GetServerSetting( "VendorItemFeeDivisor" ); // 3 gold per 500 worth of one item var vendorItemFeeAmount = GetServerSetting( "VendorItemFeeAmount" ); // Fee added per divisor step -var layerOneHand = 0x01; -var layerTwoHand = 0x02; -var layerShoes = 0x03; -var layerPants = 0x04; -var layerShirt = 0x05; -var layerHelm = 0x06; -var layerGloves = 0x07; -var layerRing = 0x08; -var layerNeck = 0x0A; -var layerHair = 0x0B; -var layerWaist = 0x0C; -var layerInnerTorso = 0x0D; -var layerBracelet = 0x0E; -var layerBeard = 0x10; -var layerMiddleTorso = 0x11; -var layerEarrings = 0x12; -var layerArms = 0x13; -var layerCloak = 0x14; -var layerOuterTorso = 0x16; -var layerOuterLegs = 0x17; +const VendorEquipmentLayer = { + OneHand: 0x01, + TwoHand: 0x02, + Shoes: 0x03, + Pants: 0x04, + Shirt: 0x05, + Helm: 0x06, + Gloves: 0x07, + Ring: 0x08, + Neck: 0x0A, + Hair: 0x0B, + Waist: 0x0C, + InnerTorso: 0x0D, + Bracelet: 0x0E, + Beard: 0x10, + MiddleTorso: 0x11, + Earrings: 0x12, + Arms: 0x13, + Cloak: 0x14, + OuterTorso: 0x16, + OuterLegs: 0x17 +}; /** @constructor @param {string|null} name @param {number[]} hues @param {number|null} dictID */ function VendorHueCategory( name, hues, dictID ) @@ -156,7 +158,7 @@ var humanBeardStyles = [ ]; var vendorClothingCategories = [ - new VendorClothingCategory( layerInnerTorso, "Upper Torso", true, [ + new VendorClothingCategory( VendorEquipmentLayer.InnerTorso, "Upper Torso", true, [ new VendorClothingEntry( 0x1517, "Shirt" ), new VendorClothingEntry( 0x1EFD, "Fancy Shirt" ), new VendorClothingEntry( 0x1F01, "Plain Dress" ), @@ -164,7 +166,7 @@ var vendorClothingCategories = [ new VendorClothingEntry( 0x1F03, "Robe" ) ]), - new VendorClothingCategory( layerMiddleTorso, "Over Chest", true, [ + new VendorClothingCategory( VendorEquipmentLayer.MiddleTorso, "Over Chest", true, [ new VendorClothingEntry( 0x1F7B, "Doublet" ), new VendorClothingEntry( 0x1FA1, "Tunic" ), new VendorClothingEntry( 0x1F9F, "Jester Suit" ), @@ -174,14 +176,14 @@ var vendorClothingCategories = [ new VendorClothingEntry( 0x153D, "Full Apron" ) ]), - new VendorClothingCategory( layerShoes, "Footwear", true, [ + new VendorClothingCategory( VendorEquipmentLayer.Shoes, "Footwear", true, [ new VendorClothingEntry( 0x170D, "Sandals" ), new VendorClothingEntry( 0x1710, "Shoes" ), new VendorClothingEntry( 0x170B, "Boots" ), new VendorClothingEntry( 0x1711, "Thigh Boots" ) ]), - new VendorClothingCategory( layerHelm, "Hats", true, [ + new VendorClothingCategory( VendorEquipmentLayer.Helm, "Hats", true, [ new VendorClothingEntry( 0x1544, "Skull Cap" ), new VendorClothingEntry( 0x1540, "Bandana" ), new VendorClothingEntry( 0x1713, "Floppy Hat" ), @@ -196,17 +198,17 @@ var vendorClothingCategories = [ new VendorClothingEntry( 0x171C, "Jester Hat" ) ]), - new VendorClothingCategory( layerPants, "Lower Torso", true, [ + new VendorClothingCategory( VendorEquipmentLayer.Pants, "Lower Torso", true, [ new VendorClothingEntry( 0x1539, "Long Pants" ), new VendorClothingEntry( 0x1537, "Kilt" ), new VendorClothingEntry( 0x1516, "Skirt" ) ]), - new VendorClothingCategory( layerCloak, "Back", true, [ + new VendorClothingCategory( VendorEquipmentLayer.Cloak, "Back", true, [ new VendorClothingEntry( 0x1515, "Cloak" ) ]), - new VendorClothingCategory( layerOneHand, "Held Items", false, [ + new VendorClothingCategory( VendorEquipmentLayer.OneHand, "Held Items", false, [ new VendorClothingEntry( 0x0DBF, "Fishing Pole" ), new VendorClothingEntry( 0x0E86, "Pickaxe" ), new VendorClothingEntry( 0x0E87, "Pitchfork" ), @@ -228,7 +230,7 @@ var vendorClothingCategories = [ /** @param {Item} itemObj @returns {number} */ function GetVendorItemPeriodFee( itemObj ) { - if( !ValidateObject( itemObj ) || itemObj.buyValue <= 0 || !vendorUseItemFees || vendorItemFeeDivisor <= 0 || vendorItemFeeAmount <= 0 ) + if( !ValidateObject( itemObj ) || itemObj.buyValue <= 0 || !vendorItemFeesEnabled || vendorItemFeeDivisor <= 0 || vendorItemFeeAmount <= 0 ) return 0; return Math.floor( itemObj.buyValue / vendorItemFeeDivisor ) * vendorItemFeeAmount; @@ -261,7 +263,7 @@ function GetVendorChargePerPeriod( vendor ) if( overrideValue > 0 ) return overrideValue; - return vendorBaseCharge + ( vendorUseItemFees ? GetVendorItemFeeTotal( vendor ) : 0 ); + return vendorBaseCharge + ( vendorItemFeesEnabled ? GetVendorItemFeeTotal( vendor ) : 0 ); } /** @param {Character} vendor @param {number} amount @returns {number} */ @@ -1229,7 +1231,7 @@ function SetVendorRaceGenderBody( vendor, isElf, isFemale ) vendor.id = isFemale ? 0x0191 : 0x0190; if( isFemale ) - RemoveVendorLayerItem( vendor, layerBeard ); + RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Beard ); vendor.Teleport(); } @@ -1518,7 +1520,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton == 5001 ) { - RemoveVendorLayerItem( vendor, layerBeard ); + RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Beard ); SetVendorRaceGenderBody( vendor, isElf, !isFemale ); ShowVendorCustomizeGump( pUser, vendor ); return; @@ -1526,8 +1528,8 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton == 5006 ) { - RemoveVendorLayerItem( vendor, layerHair ); - RemoveVendorLayerItem( vendor, layerBeard ); + RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Hair ); + RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Beard ); SetVendorRaceGenderBody( vendor, !isElf, isFemale ); var newHairStyles = humanHairStyles; @@ -1538,7 +1540,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) newHairStyles = newIsFemale ? femaleElfHairStyles : maleElfHairStyles; if( newHairStyles.length > 0 ) - SetVendorLayerItem( vendor, layerHair, newHairStyles[0].itemID, 0, "vendor hair" ); + SetVendorLayerItem( vendor, VendorEquipmentLayer.Hair, newHairStyles[0].itemID, 0, "vendor hair" ); ShowVendorCustomizeGump( pUser, vendor ); return; @@ -1546,14 +1548,14 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton == 5002 ) { - RemoveVendorLayerItem( vendor, layerHair ); + RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Hair ); ShowVendorCustomizeGump( pUser, vendor ); return; } if( pButton == 5004 ) { - RemoveVendorLayerItem( vendor, layerBeard ); + RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Beard ); ShowVendorCustomizeGump( pUser, vendor ); return; } @@ -1563,9 +1565,9 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) var hairIndex = pButton - 0x1000; if( hairIndex >= 0 && hairIndex < hairStyles.length ) { - var oldHairItem = vendor.FindItemLayer( layerHair ); + var oldHairItem = vendor.FindItemLayer( VendorEquipmentLayer.Hair ); var oldHairHue = ValidateObject( oldHairItem ) ? oldHairItem.colour : 0; - SetVendorLayerItem( vendor, layerHair, hairStyles[hairIndex].itemID, oldHairHue, "vendor hair" ); + SetVendorLayerItem( vendor, VendorEquipmentLayer.Hair, hairStyles[hairIndex].itemID, oldHairHue, "vendor hair" ); } ShowVendorCustomizeGump( pUser, vendor ); @@ -1577,9 +1579,9 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) var beardIndex = pButton - 0x2000; if( !isElf && !isFemale && beardIndex >= 0 && beardIndex < humanBeardStyles.length ) { - var oldBeardItem = vendor.FindItemLayer( layerBeard ); + var oldBeardItem = vendor.FindItemLayer( VendorEquipmentLayer.Beard ); var oldBeardHue = ValidateObject( oldBeardItem ) ? oldBeardItem.colour : 0; - SetVendorLayerItem( vendor, layerBeard, humanBeardStyles[beardIndex].itemID, oldBeardHue, "vendor beard" ); + SetVendorLayerItem( vendor, VendorEquipmentLayer.Beard, humanBeardStyles[beardIndex].itemID, oldBeardHue, "vendor beard" ); } ShowVendorCustomizeGump( pUser, vendor ); @@ -1588,7 +1590,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton >= 0x3000 && pButton < 0x4000 ) { - SetVendorLayerHue( vendor, layerHair, pButton - 0x3000 ); + SetVendorLayerHue( vendor, VendorEquipmentLayer.Hair, pButton - 0x3000 ); ShowVendorCustomizeGump( pUser, vendor ); return; } @@ -1596,7 +1598,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( pButton >= 0x4000 && pButton < 0x5000 ) { if( !isElf && !isFemale ) - SetVendorLayerHue( vendor, layerBeard, pButton - 0x4000 ); + SetVendorLayerHue( vendor, VendorEquipmentLayer.Beard, pButton - 0x4000 ); ShowVendorCustomizeGump( pUser, vendor ); } diff --git a/data/uox.ini b/data/uox.ini index f4b3d05fa..bc1b43fbb 100644 --- a/data/uox.ini +++ b/data/uox.ini @@ -248,7 +248,7 @@ PETBONDINGENABLED=0 VENDORCHARGESENABLED=1 VENDORBASECHARGE=60 VENDORCHARGEHOURS=24 -VENDORUSEITEMFEES=1 +VENDORUSEITEMFEESENABLED=1 VENDORITEMFEEDIVISOR=500 VENDORITEMFEEAMOUNT=3 } diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp index 87a1a2667..34f63d172 100644 --- a/source/SEFunctions.cpp +++ b/source/SEFunctions.cpp @@ -5786,8 +5786,8 @@ JSBool SE_GetServerSetting( JSContext *cx, uintN argc, jsval *vp ) case 410: // VENDORCHARGEHOURS JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorChargeHours() ))); break; - case 411: // VENDORUSEITEMFEES` - JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorUseItemFees() )); + case 411: // VENDORUSEITEMFEESENABLED + JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->VendorUseItemFeesEnabled() )); break; case 412: // VENDORITEMFEEDIVISOR JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeDivisor() ))); @@ -5795,7 +5795,7 @@ JSBool SE_GetServerSetting( JSContext *cx, uintN argc, jsval *vp ) case 413: // VENDORITEMFEEAMOUNT JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorItemFeeAmount() ))); break; - case 414: // ONLYRETURNTOBANK` + case 414: // ONLYRETURNTOBANK JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->OnlyReturnToBank() )); break; case 415: // VENDORMAXFUNDS diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 92a602348..e4dfd682c 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -422,7 +422,7 @@ const std::map CServerData::uox3IniCaseValue {"VENDORCHARGESENABLED", 408}, {"VENDORBASECHARGE", 409}, {"VENDORCHARGEHOURS", 410}, - {"VENDORUSEITEMFEES", 411}, + {"VENDORUSEITEMFEESENABLED", 411}, {"VENDORITEMFEEDIVISOR", 412}, {"VENDORITEMFEEAMOUNT", 413}, {"ONLYRETURNTOBANK", 414}, @@ -551,7 +551,7 @@ constexpr auto BIT_EVENTMANAGERSYSTEM = UI32( 120 ); constexpr auto BIT_QUESTSYSTEMENABLED = UI32( 121 ); constexpr auto BIT_LOGINQUESTENABLED = UI32( 122 ); constexpr auto BIT_VENDORCHARGESENABLED = UI32( 123 ); -constexpr auto BIT_VENDORUSEITEMFEES = UI32( 124 ); +constexpr auto BIT_VENDORUSEITEMFEESENABLED = UI32( 124 ); constexpr auto BIT_ONLYRETURNTOBANK = UI32( 125 ); @@ -968,7 +968,7 @@ auto CServerData::ResetDefaults() -> void VendorChargesEnabled( true ); VendorBaseCharge( 60 ); VendorChargeHours( 24 ); - VendorUseItemFees( true ); + VendorUseItemFeesEnabled( true ); VendorItemFeeDivisor( 500 ); VendorItemFeeAmount( 3 ); OnlyReturnToBank( true ); @@ -5539,17 +5539,17 @@ auto CServerData::VendorChargeHours( SI16 value ) -> void } //o------------------------------------------------------------------------------------------------o -//| Function - CServerData::VendorUseItemFees() +//| Function - CServerData::VendorUseItemFeesEnabled() //o------------------------------------------------------------------------------------------------o //| Purpose - Gets/Sets whether listed item values add extra player vendor upkeep fees //o------------------------------------------------------------------------------------------------o -auto CServerData::VendorUseItemFees() const -> bool +auto CServerData::VendorUseItemFeesEnabled() const -> bool { - return boolVals.test( BIT_VENDORUSEITEMFEES ); + return boolVals.test( BIT_VENDORUSEITEMFEESENABLED ); } -auto CServerData::VendorUseItemFees( bool newVal ) -> void +auto CServerData::VendorUseItemFeesEnabled( bool newVal ) -> void { - boolVals.set( BIT_VENDORUSEITEMFEES, newVal ); + boolVals.set( BIT_VENDORUSEITEMFEESENABLED, newVal ); } //o------------------------------------------------------------------------------------------------o @@ -5979,7 +5979,7 @@ auto CServerData::SaveIni( const std::string &filename ) -> bool ofsOutput << "VENDORCHARGESENABLED=" << ( VendorChargesEnabled() ? 1 : 0 ) << '\n'; ofsOutput << "VENDORBASECHARGE=" << VendorBaseCharge() << '\n'; ofsOutput << "VENDORCHARGEHOURS=" << VendorChargeHours() << '\n'; - ofsOutput << "VENDORUSEITEMFEES=" << ( VendorUseItemFees() ? 1 : 0 ) << '\n'; + ofsOutput << "VENDORUSEITEMFEESENABLED=" << ( VendorUseItemFeesEnabled() ? 1 : 0 ) << '\n'; ofsOutput << "VENDORITEMFEEDIVISOR=" << VendorItemFeeDivisor() << '\n'; ofsOutput << "VENDORITEMFEEAMOUNT=" << VendorItemFeeAmount() << '\n'; ofsOutput << "ONLYRETURNTOBANK=" << ( OnlyReturnToBank() ? 1 : 0 ) << '\n'; @@ -7741,8 +7741,8 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) case 410: // VENDORCHARGEHOURS VendorChargeHours( static_cast( std::stoi( value ))); break; - case 411: // VENDORUSEITEMFEES - VendorUseItemFees( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); + case 411: // VENDORUSEITEMFEESENABLED + VendorUseItemFeesEnabled( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); break; case 412: // VENDORITEMFEEDIVISOR VendorItemFeeDivisor( static_cast( std::stoi( value ))); diff --git a/source/cServerData.h b/source/cServerData.h index 3f2629492..2334d131e 100644 --- a/source/cServerData.h +++ b/source/cServerData.h @@ -340,7 +340,7 @@ class CServerData bool vendorChargesEnabled; // Master toggle for player vendor upkeep charges SI16 vendorBaseCharge; // Flat fee per vendor upkeep charge period SI16 vendorChargeHours; // Number of real hours between vendor upkeep charges - bool vendorUseItemFees; // Add item-based upkeep fees from listed item prices + bool vendorUseItemFeesEnabled; // Add item-based upkeep fees from listed item prices SI16 vendorItemFeeDivisor; // Listed item value divisor used for vendor item fees SI16 vendorItemFeeAmount; // Fee added per divisor step bool onlyReturnToBank; // returned vendor belongings skip player backpack entirely @@ -1405,8 +1405,8 @@ class CServerData auto VendorChargeHours( SI16 value ) -> void; SI16 VendorChargeHours() const; - auto VendorUseItemFees( bool value ) -> void; - auto VendorUseItemFees() const -> bool; + auto VendorUseItemFeesEnabled( bool value ) -> void; + auto VendorUseItemFeesEnabled() const -> bool; auto VendorItemFeeDivisor( SI16 value ) -> void; SI16 VendorItemFeeDivisor() const; From 7926215717281fab27e94632d28a114471822b5c Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Fri, 5 Jun 2026 21:52:03 -0500 Subject: [PATCH 12/26] Update uox.ini --- data/uox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/uox.ini b/data/uox.ini index bc1b43fbb..5e3e0ca9e 100644 --- a/data/uox.ini +++ b/data/uox.ini @@ -251,6 +251,8 @@ VENDORCHARGEHOURS=24 VENDORUSEITEMFEESENABLED=1 VENDORITEMFEEDIVISOR=500 VENDORITEMFEEAMOUNT=3 +ONLYRETURNTOBANK=1 +VENDORMAXFUNDS=16960 } [speedup] From f3a858e5bf0745bf4f5d37908c61ec8db9a2adc2 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:57:06 -0500 Subject: [PATCH 13/26] changes --- data/js/jse_fileassociations.scp | 1 + data/js/npc/ai/playervendor.js | 349 ++++++++++++++----------------- 2 files changed, 157 insertions(+), 193 deletions(-) diff --git a/data/js/jse_fileassociations.scp b/data/js/jse_fileassociations.scp index 8fb66b609..33675fa44 100644 --- a/data/js/jse_fileassociations.scp +++ b/data/js/jse_fileassociations.scp @@ -148,6 +148,7 @@ 3107=npc/pets/petbonding.js 3108=server/network/0xbf_sendnpcghostmode.js 3109=npc/ai/veterinarian.js +3110=npc/ai/playervendor.js // ------------------------ // AI-Stuff diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index a93992a4a..45bf4ba25 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -1,6 +1,6 @@ /// // @ts-check -// Version: 1.1.5 +// Version: 1.1.6 // Max amount of money the vendor can hold in the bank. // Held gold is not included in this limit, but will @@ -13,9 +13,9 @@ var vendorMaxFunds = GetServerSetting( "VendorMaxFunds" ); var onlyReturnToBank = GetServerSetting( "onlyReturnToBank" ); // Vendor upkeep settings -var vendorChargesEnabled = GetServerSetting( "VendorChargesEnabled" );; // Master toggle for vendor upkeep charges -var vendorBaseCharge = GetServerSetting( "VendorBaseCharge" ); // Flat fee per charge period -var vendorChargeHours = GetServerSetting( "VendorChargeHours" ); // Charge every X real hours +var vendorChargesEnabled = GetServerSetting( "VendorChargesEnabled" ); // Master toggle for vendor upkeep charges +var vendorBaseCharge = GetServerSetting( "VendorBaseCharge" ); // Flat fee per charge period +var vendorChargeHours = GetServerSetting( "VendorChargeHours" ); // Charge every X real hours var vendorItemFeesEnabled = GetServerSetting( "VendorUseItemFeesEnabled" ); // Add item-based fee from listed item prices var vendorItemFeeDivisor = GetServerSetting( "VendorItemFeeDivisor" ); // 3 gold per 500 worth of one item var vendorItemFeeAmount = GetServerSetting( "VendorItemFeeAmount" ); // Fee added per divisor step @@ -43,38 +43,138 @@ const VendorEquipmentLayer = { OuterLegs: 0x17 }; -/** @constructor @param {string|null} name @param {number[]} hues @param {number|null} dictID */ -function VendorHueCategory( name, hues, dictID ) -{ - this.name = name; - this.hues = hues; - this.dictID = dictID; -} +const vendorHairHueCategories = [ + { name: null, hues: [ 0x044E, 0x044F, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454 ], dictID: 17111 }, // Black + { name: null, hues: [ 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C ], dictID: 17112 }, // Beige + { name: null, hues: [ 0x045D, 0x045E, 0x045F, 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468, 0x0469, 0x046A, 0x046B, 0x046C ], dictID: 17113 }, // Golden + { name: null, hues: [ 0x046D, 0x046E, 0x046F, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478, 0x0479, 0x047A, 0x047B, 0x047C ], dictID: 17114 }, // Dark Brown + { name: null, hues: [ 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7, 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF, 0x04C0 ], dictID: 17108 }, // Red + { name: null, hues: [ 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC ], dictID: 17105 }, // Auburn + { name: null, hues: [ 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0657, 0x0658, 0x0659, 0x065A, 0x065B, 0x065C, 0x065D, 0x065E, 0x065F, 0x0660 ], dictID: 17103 }, // Brown + { name: null, hues: [ 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, 0x0961, 0x0962, 0x0963, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968 ], dictID: 17110 }, // Blonde + { name: null, hues: [ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ], dictID: 40100 }, // Special Purple + { name: null, hues: [ 32, 33, 34, 35, 36, 37 ], dictID: 40101 }, // Special Red + { name: null, hues: [ 38, 39, 40, 41, 42, 43, 44, 45, 46 ], dictID: 40102 }, // Special Orange + { name: null, hues: [ 54, 55, 56, 57 ], dictID: 40103 }, // Special Yellow + { name: null, hues: [ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 ], dictID: 40104 }, // Special Lime + { name: null, hues: [ 81, 82, 83 ], dictID: 40105 }, // Special Dark Lime + { name: null, hues: [ 89, 90, 91 ], dictID: 40106 }, // Special Ice Blue + { name: null, hues: [ 1153, 1154, 1155 ], dictID: 40107 } // Special Ice White +]; -/** @constructor @param {number} itemID @param {string|null} name @param {number=} dictID */ -function HairOrBeard( itemID, name, dictID ) -{ - this.itemID = itemID; - this.name = name; - this.dictID = dictID; -} +const femaleElfHairStyles = [ + { itemID: 0x2FCC, name: null, dictID: 18035 }, // Flower + { itemID: 0x2FC0, name: null, dictID: 18028 }, // Long Feather + { itemID: 0x2FC1, name: null, dictID: 18029 }, // Short + { itemID: 0x2FC2, name: null, dictID: 18030 }, // Mullet + { itemID: 0x2FCE, name: null, dictID: 18032 }, // Topknot + { itemID: 0x2FCF, name: null, dictID: 18033 }, // Long Braid + { itemID: 0x2FD0, name: null, dictID: 18036 }, // Buns + { itemID: 0x2FD1, name: null, dictID: 18034 } // Spiked +]; -/** @constructor @param {number} itemID @param {string} name */ -function VendorClothingEntry( itemID, name ) -{ - this.itemID = itemID; - this.name = name; -} +const maleElfHairStyles = [ + { itemID: 0x2FBF, name: null, dictID: 18027 }, // Mid Long + { itemID: 0x2FC0, name: null, dictID: 18028 }, // Long Feather + { itemID: 0x2FC1, name: null, dictID: 18029 }, // Short + { itemID: 0x2FC2, name: null, dictID: 18030 }, // Mullet + { itemID: 0x2FCE, name: null, dictID: 18032 }, // Topknot + { itemID: 0x2FCF, name: null, dictID: 18033 }, // Long Braid + { itemID: 0x2FCD, name: null, dictID: 18031 }, // Long + { itemID: 0x2FD1, name: null, dictID: 18034 } // Spiked +]; -/** @constructor @param {number} layer @param {string} name @param {boolean} canDye @param {VendorClothingEntry[]} entries @param {boolean=} compactLayout */ -function VendorClothingCategory( layer, name, canDye, entries, compactLayout ) -{ - this.layer = layer; - this.name = name; - this.canDye = canDye; - this.entries = entries; - this.compactLayout = compactLayout ? true : false; -} +const humanHairStyles = [ + { itemID: 0x203B, name: null, dictID: 18029 }, // Short + { itemID: 0x203C, name: null, dictID: 18031 }, // Long + { itemID: 0x203D, name: null, dictID: 2086 }, // Ponytail + { itemID: 0x2044, name: null, dictID: 2087 }, // Mohawk + { itemID: 0x2045, name: null, dictID: 2080 }, // Pageboy + { itemID: 0x204A, name: null, dictID: 18032 }, // Topknot + { itemID: 0x2047, name: null, dictID: 2088 }, // Curly + { itemID: 0x2048, name: null, dictID: 2081 }, // Receding + { itemID: 0x2049, name: null, dictID: 2082 } // 2-Tails +]; + +const humanBeardStyles = [ + { itemID: 0x2041, name: null, dictID: 18001 }, // Mustache + { itemID: 0x203F, name: null, dictID: 18002 }, // Short Beard + { itemID: 0x204B, name: null, dictID: 40058 }, // Short Beard and Mustache + { itemID: 0x203E, name: null, dictID: 18005 }, // Long Beard + { itemID: 0x204C, name: null, dictID: 40068 }, // Long Beard and Mustache + { itemID: 0x2040, name: null, dictID: 40069 }, // Goatee + { itemID: 0x204D, name: null, dictID: 18000 } // Vandyke +]; + +const vendorClothingCategories = [ + { layer: VendorEquipmentLayer.InnerTorso, name: "Upper Torso", canDye: true, compactLayout: false, entries: [ + { itemID: 0x1517, name: "Shirt" }, + { itemID: 0x1EFD, name: "Fancy Shirt" }, + { itemID: 0x1F01, name: "Plain Dress" }, + { itemID: 0x1EFF, name: "Fancy Dress" }, + { itemID: 0x1F03, name: "Robe" } + ]}, + + { layer: VendorEquipmentLayer.MiddleTorso, name: "Over Chest", canDye: true, compactLayout: false, entries: [ + { itemID: 0x1F7B, name: "Doublet" }, + { itemID: 0x1FA1, name: "Tunic" }, + { itemID: 0x1F9F, name: "Jester Suit" }, + { itemID: 0x1541, name: "Body Sash" }, + { itemID: 0x1FFD, name: "Surcoat" }, + { itemID: 0x153B, name: "Half Apron" }, + { itemID: 0x153D, name: "Full Apron" } + ]}, + + { layer: VendorEquipmentLayer.Shoes, name: "Footwear", canDye: true, compactLayout: false, entries: [ + { itemID: 0x170D, name: "Sandals" }, + { itemID: 0x1710, name: "Shoes" }, + { itemID: 0x170B, name: "Boots" }, + { itemID: 0x1711, name: "Thigh Boots" } + ]}, + + { layer: VendorEquipmentLayer.Helm, name: "Hats", canDye: true, compactLayout: false, entries: [ + { itemID: 0x1544, name: "Skull Cap" }, + { itemID: 0x1540, name: "Bandana" }, + { itemID: 0x1713, name: "Floppy Hat" }, + { itemID: 0x1714, name: "Wide Brim Hat" }, + { itemID: 0x1715, name: "Cap" }, + { itemID: 0x1716, name: "Tall Straw Hat" }, + { itemID: 0x1717, name: "Straw Hat" }, + { itemID: 0x1718, name: "Wizard Hat" }, + { itemID: 0x1719, name: "Bonnet" }, + { itemID: 0x171A, name: "Feathered Hat" }, + { itemID: 0x171B, name: "Tricorne Hat" }, + { itemID: 0x171C, name: "Jester Hat" } + ]}, + + { layer: VendorEquipmentLayer.Pants, name: "Lower Torso", canDye: true, compactLayout: false, entries: [ + { itemID: 0x1539, name: "Long Pants" }, + { itemID: 0x1537, name: "Kilt" }, + { itemID: 0x1516, name: "Skirt" } + ]}, + + { layer: VendorEquipmentLayer.Cloak, name: "Back", canDye: true, compactLayout: false, entries: [ + { itemID: 0x1515, name: "Cloak" } + ]}, + + { layer: VendorEquipmentLayer.OneHand, name: "Held Items", canDye: false, compactLayout: true, entries: [ + { itemID: 0x0DBF, name: "Fishing Pole" }, + { itemID: 0x0E86, name: "Pickaxe" }, + { itemID: 0x0E87, name: "Pitchfork" }, + { itemID: 0x0EC3, name: "Cleaver" }, + { itemID: 0x0F5C, name: "Mace" }, + { itemID: 0x0F6B, name: "Torch" }, + { itemID: 0x102A, name: "Hammer" }, + { itemID: 0x0F61, name: "Longsword" }, + { itemID: 0x13F8, name: "Gnarled Staff" }, + { itemID: 0x0F4F, name: "Crossbow" }, + { itemID: 0x1407, name: "War Mace" }, + { itemID: 0x1443, name: "Two-Handed Axe" }, + { itemID: 0x0F62, name: "Spear" }, + { itemID: 0x13FF, name: "Katana" }, + { itemID: 0x0EFA, name: "Spellbook" } + ]} +]; /** @param {VendorHueCategory} entry @param {Socket|null} socket @returns {string} */ function GetVendorHueCategoryName( entry, socket ) @@ -88,175 +188,42 @@ function GetVendorHueCategoryName( entry, socket ) /** @param {HairOrBeard} entry @param {Socket} socket @returns {string} */ function GetHairOrBeardName( entry, socket ) { - if( entry.dictID ) + if( entry.dictID && socket ) return GetDictionaryEntry( entry.dictID, socket.language ); return entry.name || ""; } -var vendorHairHueCategories = [ - new VendorHueCategory( null, [ 0x044E, 0x044F, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454 ], 17111 ), // Black - new VendorHueCategory( null, [ 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C ], 17112 ), // Beige - new VendorHueCategory( null, [ 0x045D, 0x045E, 0x045F, 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467, 0x0468, 0x0469, 0x046A, 0x046B, 0x046C ], 17113 ), // Golden - new VendorHueCategory( null, [ 0x046D, 0x046E, 0x046F, 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478, 0x0479, 0x047A, 0x047B, 0x047C ], 17114 ), // Dark Brown - new VendorHueCategory( null, [ 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7, 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF, 0x04C0 ], 17108 ), // Red - new VendorHueCategory( null, [ 0x05DD, 0x05DE, 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC ], 17105 ), // Auburn - new VendorHueCategory( null, [ 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0657, 0x0658, 0x0659, 0x065A, 0x065B, 0x065C, 0x065D, 0x065E, 0x065F, 0x0660 ], 17103 ), // Brown - new VendorHueCategory( null, [ 0x08A5, 0x08A6, 0x08A7, 0x08A8, 0x08A9, 0x0961, 0x0962, 0x0963, 0x0964, 0x0965, 0x0966, 0x0967, 0x0968 ], 17110 ), // Blonde - new VendorHueCategory( null, [ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 ], 40100 ), // Special Purple - new VendorHueCategory( null, [ 32, 33, 34, 35, 36, 37 ], 40101 ), // Special Red - new VendorHueCategory( null, [ 38, 39, 40, 41, 42, 43, 44, 45, 46 ], 40102 ), // Special Orange - new VendorHueCategory( null, [ 54, 55, 56, 57 ], 40103 ), // Special Yellow - new VendorHueCategory( null, [ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72 ], 40104 ), // Special Lime - new VendorHueCategory( null, [ 81, 82, 83 ], 40105 ), // Special Dark Lime - new VendorHueCategory( null, [ 89, 90, 91 ], 40106 ), // Special Ice Blue - new VendorHueCategory( null, [ 1153, 1154, 1155 ], 40107 ) // Special Ice White -]; - -var femaleElfHairStyles = [ - new HairOrBeard( 0x2FCC, null, 18035 ), // Flower - new HairOrBeard( 0x2FC0, null, 18028 ), // Long Feather - new HairOrBeard( 0x2FC1, null, 18029 ), // Short - new HairOrBeard( 0x2FC2, null, 18030 ), // Mullet - new HairOrBeard( 0x2FCE, null, 18032 ), // Topknot - new HairOrBeard( 0x2FCF, null, 18033 ), // Long Braid - new HairOrBeard( 0x2FD0, null, 18036 ), // Buns - new HairOrBeard( 0x2FD1, null, 18034 ) // Spiked -]; - -var maleElfHairStyles = [ - new HairOrBeard( 0x2FBF, null, 18027 ), // Mid Long - new HairOrBeard( 0x2FC0, null, 18028 ), // Long Feather - new HairOrBeard( 0x2FC1, null, 18029 ), // Short - new HairOrBeard( 0x2FC2, null, 18030 ), // Mullet - new HairOrBeard( 0x2FCE, null, 18032 ), // Topknot - new HairOrBeard( 0x2FCF, null, 18033 ), // Long Braid - new HairOrBeard( 0x2FCD, null, 18031 ), // Long - new HairOrBeard( 0x2FD1, null, 18034 ) // Spiked -]; - -var humanHairStyles = [ - new HairOrBeard( 0x203B, null, 18029 ), // Short - new HairOrBeard( 0x203C, null, 18031 ), // Long - new HairOrBeard( 0x203D, null, 2086 ), // Ponytail - new HairOrBeard( 0x2044, null, 2087 ), // Mohawk - new HairOrBeard( 0x2045, null, 2080 ), // Pageboy - new HairOrBeard( 0x204A, null, 18032 ), // Topknot - new HairOrBeard( 0x2047, null, 2088 ), // Curly - new HairOrBeard( 0x2048, null, 2081 ), // Receding - new HairOrBeard( 0x2049, null, 2082 ) // 2-Tails -]; - -var humanBeardStyles = [ - new HairOrBeard( 0x2041, null, 18001 ), // Mustache - new HairOrBeard( 0x203F, null, 18002 ), // Short Beard - new HairOrBeard( 0x204B, null, 40058 ), // Short Beard and Mustache - new HairOrBeard( 0x203E, null, 18005 ), // Long Beard - new HairOrBeard( 0x204C, null, 40068 ), // Long Beard and Mustache - new HairOrBeard( 0x2040, null, 40069 ), // Goatee - new HairOrBeard( 0x204D, null, 18000 ) // Vandyke -]; - -var vendorClothingCategories = [ - new VendorClothingCategory( VendorEquipmentLayer.InnerTorso, "Upper Torso", true, [ - new VendorClothingEntry( 0x1517, "Shirt" ), - new VendorClothingEntry( 0x1EFD, "Fancy Shirt" ), - new VendorClothingEntry( 0x1F01, "Plain Dress" ), - new VendorClothingEntry( 0x1EFF, "Fancy Dress" ), - new VendorClothingEntry( 0x1F03, "Robe" ) - ]), - - new VendorClothingCategory( VendorEquipmentLayer.MiddleTorso, "Over Chest", true, [ - new VendorClothingEntry( 0x1F7B, "Doublet" ), - new VendorClothingEntry( 0x1FA1, "Tunic" ), - new VendorClothingEntry( 0x1F9F, "Jester Suit" ), - new VendorClothingEntry( 0x1541, "Body Sash" ), - new VendorClothingEntry( 0x1FFD, "Surcoat" ), - new VendorClothingEntry( 0x153B, "Half Apron" ), - new VendorClothingEntry( 0x153D, "Full Apron" ) - ]), - - new VendorClothingCategory( VendorEquipmentLayer.Shoes, "Footwear", true, [ - new VendorClothingEntry( 0x170D, "Sandals" ), - new VendorClothingEntry( 0x1710, "Shoes" ), - new VendorClothingEntry( 0x170B, "Boots" ), - new VendorClothingEntry( 0x1711, "Thigh Boots" ) - ]), - - new VendorClothingCategory( VendorEquipmentLayer.Helm, "Hats", true, [ - new VendorClothingEntry( 0x1544, "Skull Cap" ), - new VendorClothingEntry( 0x1540, "Bandana" ), - new VendorClothingEntry( 0x1713, "Floppy Hat" ), - new VendorClothingEntry( 0x1714, "Wide Brim Hat" ), - new VendorClothingEntry( 0x1715, "Cap" ), - new VendorClothingEntry( 0x1716, "Tall Straw Hat" ), - new VendorClothingEntry( 0x1717, "Straw Hat" ), - new VendorClothingEntry( 0x1718, "Wizard Hat" ), - new VendorClothingEntry( 0x1719, "Bonnet" ), - new VendorClothingEntry( 0x171A, "Feathered Hat" ), - new VendorClothingEntry( 0x171B, "Tricorne Hat" ), - new VendorClothingEntry( 0x171C, "Jester Hat" ) - ]), - - new VendorClothingCategory( VendorEquipmentLayer.Pants, "Lower Torso", true, [ - new VendorClothingEntry( 0x1539, "Long Pants" ), - new VendorClothingEntry( 0x1537, "Kilt" ), - new VendorClothingEntry( 0x1516, "Skirt" ) - ]), - - new VendorClothingCategory( VendorEquipmentLayer.Cloak, "Back", true, [ - new VendorClothingEntry( 0x1515, "Cloak" ) - ]), - - new VendorClothingCategory( VendorEquipmentLayer.OneHand, "Held Items", false, [ - new VendorClothingEntry( 0x0DBF, "Fishing Pole" ), - new VendorClothingEntry( 0x0E86, "Pickaxe" ), - new VendorClothingEntry( 0x0E87, "Pitchfork" ), - new VendorClothingEntry( 0x0EC3, "Cleaver" ), - new VendorClothingEntry( 0x0F5C, "Mace" ), - new VendorClothingEntry( 0x0F6B, "Torch" ), - new VendorClothingEntry( 0x102A, "Hammer" ), - new VendorClothingEntry( 0x0F61, "Longsword" ), - new VendorClothingEntry( 0x13F8, "Gnarled Staff" ), - new VendorClothingEntry( 0x0F4F, "Crossbow" ), - new VendorClothingEntry( 0x1407, "War Mace" ), - new VendorClothingEntry( 0x1443, "Two-Handed Axe" ), - new VendorClothingEntry( 0x0F62, "Spear" ), - new VendorClothingEntry( 0x13FF, "Katana" ), - new VendorClothingEntry( 0x0EFA, "Spellbook" ) - ], true) -]; - /** @param {Item} itemObj @returns {number} */ function GetVendorItemPeriodFee( itemObj ) { - if( !ValidateObject( itemObj ) || itemObj.buyValue <= 0 || !vendorItemFeesEnabled || vendorItemFeeDivisor <= 0 || vendorItemFeeAmount <= 0 ) + if( itemObj.buyValue <= 0 || !vendorItemFeesEnabled || vendorItemFeeDivisor <= 0 || vendorItemFeeAmount <= 0 ) return 0; return Math.floor( itemObj.buyValue / vendorItemFeeDivisor ) * vendorItemFeeAmount; } -/** @param {Character} vendor @returns {number} */ +/** @type { ( vendor: Character ) => number } */ function GetVendorItemFeeTotal( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 || !ValidateObject( vendor.pack ) ) + if( vendor.aitype != 17 || !ValidateObject( vendor.pack ) ) return 0; var totalFee = 0; var packItem = vendor.pack.FirstItem(); for( ; !vendor.pack.FinishedItems(); packItem = vendor.pack.NextItem() ) { - if( ValidateObject( packItem ) ) + if( ValidateObject( packItem )) totalFee += GetVendorItemPeriodFee( packItem ); } return totalFee; } -/** @param {Character} vendor @returns {number} */ +/** @type { ( vendor: Character ) => number } */ function GetVendorChargePerPeriod( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 || !vendorChargesEnabled ) + if( vendor.aitype != 17 || !vendorChargesEnabled ) return 0; var overrideValue = vendor.GetTag( "VendorChargePerPeriod" ); @@ -269,7 +236,7 @@ function GetVendorChargePerPeriod( vendor ) /** @param {Character} vendor @param {number} amount @returns {number} */ function DepositVendorBankGold( vendor, amount ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 || amount <= 0 ) + if( vendor.aitype != 17 || amount <= 0 ) return 0; var bankGold = vendor.GetTag( "VendorBankAccount" ); @@ -290,7 +257,7 @@ function DepositVendorBankGold( vendor, amount ) /** @param {Character} vendor @param {number} amount @returns {number} */ function WithdrawVendorBankGold( vendor, amount ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 || amount <= 0 ) + if( vendor.aitype != 17 || amount <= 0 ) return 0; var bankGold = vendor.GetTag( "VendorBankAccount" ); @@ -307,7 +274,7 @@ function WithdrawVendorBankGold( vendor, amount ) /** @param {Character} vendor @param {number} charge @returns {boolean} */ function PayVendorCharge( vendor, charge ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 || charge <= 0 ) + if( vendor.aitype != 17 || charge <= 0 ) return false; var bankGold = vendor.GetTag( "VendorBankAccount" ); @@ -334,7 +301,7 @@ function PayVendorCharge( vendor, charge ) /** @param {Character} vendor @returns {number} */ function FlushVendorBankToHeldGold( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return 0; var bankGold = vendor.GetTag( "VendorBankAccount" ); @@ -356,7 +323,7 @@ function GetVendorPeriodsAffordable( vendor ) var bankGold = 0; var heldGold = 0; - if( ValidateObject( vendor ) && vendor.aitype == 17 ) + if( vendor.aitype == 17 ) { bankGold = vendor.GetTag( "VendorBankAccount" ); heldGold = vendor.vendorGoldHeld || 0; @@ -383,9 +350,6 @@ function GetVendorDaysAffordable( vendor ) /** @param {Item} itemObj @param {Character} vendor */ function DropItemAtVendorLocation( itemObj, vendor ) { - if( !ValidateObject( itemObj ) || !ValidateObject( vendor ) ) - return; - itemObj.container = null; itemObj.x = vendor.x; itemObj.y = vendor.y; @@ -397,7 +361,7 @@ function DropItemAtVendorLocation( itemObj, vendor ) /** @param {Item} itemObj @param {Item} container @returns {boolean} */ function TryMoveItemToContainer( itemObj, container ) { - if( !ValidateObject( itemObj ) || !ValidateObject( container ) ) + if( !ValidateObject( container ) ) return false; if( container.totalItemCount >= container.maxItems ) @@ -413,9 +377,6 @@ function TryMoveItemToContainer( itemObj, container ) /** @param {Item} itemObj @param {Character} pUser @param {Character} vendor @returns {number} */ function PlaceItemForOwnerOrDrop( itemObj, pUser, vendor ) { - if( !ValidateObject( itemObj ) || !ValidateObject( pUser ) || !ValidateObject( vendor ) ) - return 0; - var pack = pUser.pack; var bankBox = pUser.FindItemLayer( 29 ); @@ -445,7 +406,7 @@ function ReturnVendorItemsToOwner( vendor, pUser ) { var results = { pack:0, bank:0, ground:0 }; - if( !ValidateObject( vendor ) || vendor.aitype != 17 || !ValidateObject( pUser ) || !ValidateObject( vendor.pack ) ) + if( vendor.aitype != 17 || !ValidateObject( vendor.pack )) return results; var itemList = []; @@ -473,19 +434,21 @@ function ReturnVendorItemsToOwner( vendor, pUser ) /** @param {Character} vendor @returns {number} */ function DropVendorItemsAtLocation( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 || !ValidateObject( vendor.pack ) ) + if( vendor.aitype != 17 || !ValidateObject( vendor.pack ) ) return 0; var itemList = []; var packItem = vendor.pack.FirstItem(); for( ; !vendor.pack.FinishedItems(); packItem = vendor.pack.NextItem() ) { - if( ValidateObject( packItem ) ) + if( ValidateObject( packItem )) itemList.push( packItem ); } for( var i = 0; i < itemList.length; ++i ) - DropItemAtVendorLocation( itemList[i], vendor ); + { + DropItemAtVendorLocation( itemList[i], vendor ); + } return itemList.length; } @@ -800,7 +763,7 @@ function RemoveGoldFromPack( pUser, amount ) return amount <= 0; } -/** @param {Character} pUser @returns {Item|null} */ +/** @type { ( pUser: Character ) => Item|null } */ function GetBankBox( pUser ) { if( !ValidateObject( pUser ) ) @@ -887,7 +850,7 @@ function DepositVendorGoldToBankBox( pUser, goldAmount ) return true; } -/** @param {Character} pUser @param {Character} vendor */ +/** @type { ( pUser: Character, vendor: Character ) => void } */ function CollectVendorGold( pUser, vendor ) { if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) @@ -1256,7 +1219,7 @@ function GetStoredClothingDyeCategory( pUser ) /** @param {Socket} socket @param {Character} vendor */ function ShowPlayerVendorOwnerGump( socket, vendor ) { - if( !socket || !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return; var heldGold = vendor.vendorGoldHeld || 0; @@ -1490,7 +1453,7 @@ function ShowVendorCustomizeGump( pUser, vendor ) myGump.Free(); } -/** @param {Character} pUser @param {Character} vendor @param {number} pButton */ +/** @type { ( pUser: Character, vendor: Character, pButton: number ) => void } */ function HandleVendorCustomizeButton( pUser, vendor, pButton ) { if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) From ebd33892c8e59bc6d01e68e9be2f1e6e269ab55a Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Fri, 5 Jun 2026 23:14:30 -0500 Subject: [PATCH 14/26] changes --- data/js/npc/ai/playervendor.js | 60 +++++++++++++++------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 45bf4ba25..5e5f8cb0d 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -456,7 +456,7 @@ function DropVendorItemsAtLocation( vendor ) /** @param {Character} vendor @returns {Item|null} */ function CreateVendorDismissDeedAtLocation( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return null; var deed = CreateBlankItem( null, vendor, 1, "A vendor deed for " + vendor.name + ".", 0x14F0, 0x0, "ITEM", false ); @@ -473,7 +473,7 @@ function CreateVendorDismissDeedAtLocation( vendor ) /** @param {Character} pUser @param {Character} vendor @returns {Item|null} */ function CreateVendorDismissDeedForOwner( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return null; var deedName = "A vendor deed for " + vendor.name + "."; @@ -496,7 +496,7 @@ function CreateVendorDismissDeedForOwner( pUser, vendor ) /** @param {Character} vendor @returns {number} */ function DropVendorGoldAtLocation( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return 0; var heldGold = vendor.vendorGoldHeld || 0; @@ -523,7 +523,7 @@ function ReturnVendorGoldToOwner( pUser, vendor ) { var result = { amount:0, location:0 }; - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return result; var heldGold = vendor.vendorGoldHeld || 0; @@ -554,7 +554,7 @@ function ReturnVendorGoldToOwner( pUser, vendor ) /** @param {Character} vendor */ function FinalizeVendorRemoval( vendor ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return; if( ValidateObject( vendor.multi ) ) @@ -566,7 +566,7 @@ function FinalizeVendorRemoval( vendor ) /** @param {Character} vendor @param {Character|null} notifyChar */ function RemoveVendorForNoFunds( vendor, notifyChar ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return; var ownerChar = ValidateObject( vendor.owner ) ? vendor.owner : null; @@ -576,7 +576,7 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) ownerSocket.SysMessage( GetDictionaryEntry( 40000, ownerSocket.language ), vendor.name ); var deed = CreateVendorDismissDeedForOwner( ownerChar, vendor ); - if( !ValidateObject( deed ) ) + if( !ValidateObject( deed )) { ownerSocket.SysMessage( GetDictionaryEntry( 40001, ownerSocket.language ) ); return; @@ -619,7 +619,7 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) var totalGold = DropVendorGoldAtLocation( vendor ); var offlineDeed = CreateVendorDismissDeedAtLocation( vendor ); - if( ValidateObject( notifyChar ) && notifyChar.socket ) + if( notifyChar.socket ) { var notifySocket = notifyChar.socket; notifySocket.SysMessage( GetDictionaryEntry( 40010, notifySocket.language ), vendor.name ); @@ -630,7 +630,7 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) if( totalGold > 0 ) notifySocket.SysMessage( GetDictionaryEntry( 40006, notifySocket.language ), totalGold ); - if( ValidateObject( offlineDeed ) ) + if( ValidateObject( offlineDeed )) notifySocket.SysMessage( GetDictionaryEntry( 40009, notifySocket.language ) ); } @@ -640,7 +640,7 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) /** @param {Character} vendor @param {Character|null} notifyChar @returns {boolean} */ function CheckVendorUpkeep( vendor, notifyChar ) { - if( !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return false; if( !vendorChargesEnabled ) @@ -682,16 +682,13 @@ function CheckVendorUpkeep( vendor, notifyChar ) /** @param {Character} pUser @param {Character} vendor */ function StoreVendorForGump( pUser, vendor ) { - if( ValidateObject( pUser ) && ValidateObject( vendor ) && vendor.aitype == 17 ) + if( vendor.aitype == 17 ) pUser.SetTempTag( "PlayerVendorGumpSerial", vendor.serial ); } /** @param {Character} pUser @returns {Character|null} */ function GetStoredVendorForGump( pUser ) { - if( !ValidateObject( pUser ) ) - return null; - var serial = pUser.GetTempTag( "PlayerVendorGumpSerial" ); if( !serial ) return null; @@ -706,7 +703,7 @@ function GetStoredVendorForGump( pUser ) /** @param {Character} pUser @param {Character} vendor */ function OpenVendorBackpack( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket || !ValidateObject( vendor.pack ) ) + if( vendor.aitype != 17 || !pUser.socket || !ValidateObject( vendor.pack ) ) return; pUser.socket.OpenContainer( vendor.pack ); @@ -715,7 +712,7 @@ function OpenVendorBackpack( pUser, vendor ) /** @param {Character} pUser @returns {number} */ function GetPackGoldAmount( pUser ) { - if( !ValidateObject( pUser ) || !ValidateObject( pUser.pack ) ) + if( !ValidateObject( pUser.pack ) ) return 0; var totalGold = 0; @@ -732,7 +729,7 @@ function GetPackGoldAmount( pUser ) /** @param {Character} pUser @param {number} amount @returns {boolean} */ function RemoveGoldFromPack( pUser, amount ) { - if( !ValidateObject( pUser ) || amount <= 0 || !ValidateObject( pUser.pack ) ) + if( amount <= 0 || !ValidateObject( pUser.pack ) ) return false; if( GetPackGoldAmount( pUser ) < amount ) @@ -766,9 +763,6 @@ function RemoveGoldFromPack( pUser, amount ) /** @type { ( pUser: Character ) => Item|null } */ function GetBankBox( pUser ) { - if( !ValidateObject( pUser ) ) - return null; - var bankBox = pUser.FindItemLayer( 29 ); return ValidateObject( bankBox ) ? bankBox : null; } @@ -792,15 +786,15 @@ function CanBankReceiveVendorPayout( pUser ) /** @param {Character} pUser @param {number} checkSize @returns {Item|null} */ function CreateVendorBankCheck( pUser, checkSize ) { - if( !ValidateObject( pUser ) || checkSize <= 0 ) + if( checkSize <= 0 ) return null; var bankBox = GetBankBox( pUser ); - if( !ValidateObject( bankBox ) ) + if( !ValidateObject( bankBox )) return null; var newCheck = CreateDFNItem( pUser.socket, pUser, "bankcheck", 1, "ITEM", false ); - if( !ValidateObject( newCheck ) ) + if( !ValidateObject( newCheck )) return null; newCheck.SetTag( "CheckSize", checkSize ); @@ -837,7 +831,7 @@ function DivideDepositedGold( pTalking, bankBox, depositAmt ) function DepositVendorGoldToBankBox( pUser, goldAmount ) { var bankBox = GetBankBox( pUser ); - if( !ValidateObject( pUser ) || !ValidateObject( bankBox ) || goldAmount <= 0 ) + if( !ValidateObject( bankBox ) || goldAmount <= 0 ) return false; if( bankBox.totalItemCount >= bankBox.maxItems ) @@ -853,7 +847,7 @@ function DepositVendorGoldToBankBox( pUser, goldAmount ) /** @type { ( pUser: Character, vendor: Character ) => void } */ function CollectVendorGold( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; var socket = pUser.socket; @@ -898,7 +892,7 @@ function CollectVendorGold( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor @param {number} amount */ function DepositToVendorBank( pUser, vendor, amount ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; var socket = pUser.socket; @@ -927,7 +921,7 @@ function DepositToVendorBank( pUser, vendor, amount ) return; } - if( !RemoveGoldFromPack( pUser, deposited ) ) + if( !RemoveGoldFromPack( pUser, deposited )) { WithdrawVendorBankGold( vendor, deposited ); socket.SysMessage( GetDictionaryEntry( 40022, socket.language ) ); @@ -943,7 +937,7 @@ function DepositToVendorBank( pUser, vendor, amount ) /** @param {Character} pUser @param {Character} vendor */ function FlushBankToHeld( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; var moved = FlushVendorBankToHeldGold( vendor ); @@ -959,7 +953,7 @@ function FlushBankToHeld( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function DismissVendor( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -967,9 +961,9 @@ function DismissVendor( pUser, vendor ) var socket = pUser.socket; var deed = CreateVendorDismissDeedForOwner( pUser, vendor ); - if( !ValidateObject( deed ) ) + if( !ValidateObject( deed )) { - socket.SysMessage( GetDictionaryEntry( 40027, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40027, socket.language )); return; } @@ -1010,7 +1004,7 @@ function DismissVendor( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function CycleVendorDirection( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1643,7 +1637,7 @@ function ShowVendorClothingGump( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function ShowVendorClothingDyeGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) From e40e3086e27e0dc2db9ecf6488bedeb3efb59298 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Fri, 5 Jun 2026 23:33:02 -0500 Subject: [PATCH 15/26] Update playervendor.js --- data/js/npc/ai/playervendor.js | 111 +++++++++++++++------------------ 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 5e5f8cb0d..39e73a4d7 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -666,14 +666,15 @@ function CheckVendorUpkeep( vendor, notifyChar ) if( periodsOwed <= 0 ) return true; - for( var i = 0; i < periodsOwed; ++i ) - { - if( !PayVendorCharge( vendor, GetVendorChargePerPeriod( vendor ) ) ) - { - RemoveVendorForNoFunds( vendor, notifyChar ); - return false; - } - } + var costPerPeriod = GetVendorChargePerPeriod( vendor ); + for( var i = 0; i < periodsOwed; ++i ) + { + if( !PayVendorCharge( vendor, costPerPeriod ) ) + { + RemoveVendorForNoFunds( vendor, notifyChar ); + return false; + } + } vendor.SetTag( "VendorLastChargeTime", lastChargeTime + ( periodsOwed * chargeInterval ) ); return true; @@ -855,22 +856,22 @@ function CollectVendorGold( pUser, vendor ) if( heldGold <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40012, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40012, socket.language )); return; } - if( !CanBankReceiveVendorPayout( pUser ) ) + if( !CanBankReceiveVendorPayout( pUser )) { - socket.SysMessage( GetDictionaryEntry( 40013, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40013, socket.language )); return; } if( heldGold > 2000 ) { var vendorCheck = CreateVendorBankCheck( pUser, heldGold ); - if( !ValidateObject( vendorCheck ) ) + if( !ValidateObject( vendorCheck )) { - socket.SysMessage( GetDictionaryEntry( 40014, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40014, socket.language )); return; } @@ -879,9 +880,9 @@ function CollectVendorGold( pUser, vendor ) return; } - if( !DepositVendorGoldToBankBox( pUser, heldGold ) ) + if( !DepositVendorGoldToBankBox( pUser, heldGold )) { - socket.SysMessage( GetDictionaryEntry( 40016, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40016, socket.language )); return; } @@ -898,40 +899,40 @@ function DepositToVendorBank( pUser, vendor, amount ) var socket = pUser.socket; if( amount <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40018, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40018, socket.language )); return; } - if( !ValidateObject( pUser.pack ) ) + if( !ValidateObject( pUser.pack )) { - socket.SysMessage( GetDictionaryEntry( 40019, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40019, socket.language )); return; } if( GetPackGoldAmount( pUser ) < amount ) { - socket.SysMessage( GetDictionaryEntry( 40020, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40020, socket.language )); return; } var deposited = DepositVendorBankGold( vendor, amount ); if( deposited <= 0 ) { - socket.SysMessage( GetDictionaryEntry( 40021, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40021, socket.language )); return; } if( !RemoveGoldFromPack( pUser, deposited )) { WithdrawVendorBankGold( vendor, deposited ); - socket.SysMessage( GetDictionaryEntry( 40022, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40022, socket.language )); return; } socket.SysMessage( GetDictionaryEntry( 40023, socket.language ), deposited ); if( deposited < amount ) - socket.SysMessage( GetDictionaryEntry( 40024, socket.language ) ); + socket.SysMessage( GetDictionaryEntry( 40024, socket.language )); } /** @param {Character} pUser @param {Character} vendor */ @@ -943,7 +944,7 @@ function FlushBankToHeld( pUser, vendor ) var moved = FlushVendorBankToHeldGold( vendor ); if( moved <= 0 ) { - pUser.socket.SysMessage( GetDictionaryEntry( 40025, pUser.socket.language ) ); + pUser.socket.SysMessage( GetDictionaryEntry( 40025, pUser.socket.language )); return; } @@ -1020,7 +1021,7 @@ function NormalizeVendorSpeech( vendor, speech ) return ""; var cleanedSpeech = ( "" + speech ).toLowerCase().replace( /^\s+|\s+$/g, "" ); - if( !ValidateObject( vendor ) || vendor.aitype != 17 || !vendor.name ) + if( vendor.aitype != 17 || !vendor.name ) return cleanedSpeech; var vendorName = ( "" + vendor.name ).toLowerCase(); @@ -1036,14 +1037,14 @@ function NormalizeVendorSpeech( vendor, speech ) /** @param {Character} pUser @param {Character} vendor @returns {boolean} */ function VendorAccessBlocked( pUser, vendor ) { - if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser ) ) + if( ValidateObject( vendor.multi ) && vendor.multi.IsOnBanList( pUser )) { if( pUser.socket ) - pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language ) ); + pUser.socket.SysMessage( GetDictionaryEntry( 40059, pUser.socket.language )); return true; } - if( !CheckVendorUpkeep( vendor, pUser ) ) + if( !CheckVendorUpkeep( vendor, pUser )) return true; return false; @@ -1059,7 +1060,7 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "view" || cmd == "browse" || cmd == "look" ) { - if( VendorAccessBlocked( pUser, vendor ) ) + if( VendorAccessBlocked( pUser, vendor )) return 2; OpenVendorBackpack( pUser, vendor ); @@ -1068,7 +1069,7 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( cmd == "buy" || cmd == "purchase" ) { - if( VendorAccessBlocked( pUser, vendor ) ) + if( VendorAccessBlocked( pUser, vendor )) return 2; pUser.BuyFrom( vendor ); @@ -1079,11 +1080,11 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) { if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 ) ); + vendor.TextMessage( GetDictionaryEntry( 40028 )); return 2; } - if( !CheckVendorUpkeep( vendor, pUser ) ) + if( !CheckVendorUpkeep( vendor, pUser )) return 2; CollectVendorGold( pUser, vendor ); @@ -1094,11 +1095,11 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) { if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 ) ); + vendor.TextMessage( GetDictionaryEntry( 40028 )); return 2; } - if( !CheckVendorUpkeep( vendor, pUser ) ) + if( !CheckVendorUpkeep( vendor, pUser )) return 2; if( pUser.socket ) @@ -1113,7 +1114,7 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) { if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 ) ); + vendor.TextMessage( GetDictionaryEntry( 40028 )); return 2; } @@ -1125,7 +1126,7 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) { if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) { - vendor.TextMessage( GetDictionaryEntry( 40028 ) ); + vendor.TextMessage( GetDictionaryEntry( 40028 )); return 2; } @@ -1139,29 +1140,23 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) /** @param {Character} vendor @param {number} layer */ function RemoveVendorLayerItem( vendor, layer ) { - if( !ValidateObject( vendor ) ) - return; - var layerItem = vendor.FindItemLayer( layer ); - if( ValidateObject( layerItem ) ) + if( ValidateObject( layerItem )) layerItem.Delete(); } /** @param {Character} vendor @param {number} layer @param {number} itemID @param {number} hue @param {string} itemName */ function SetVendorLayerItem( vendor, layer, itemID, hue, itemName ) { - if( !ValidateObject( vendor ) ) - return; - var oldItem = vendor.FindItemLayer( layer ); - if( ValidateObject( oldItem ) ) + if( ValidateObject( oldItem )) oldItem.Delete(); if( itemID == 0 ) return; var newItem = CreateBlankItem( vendor.socket ? vendor.socket : null, vendor, 1, itemName, itemID, hue, "ITEM", false ); - if( !ValidateObject( newItem ) ) + if( !ValidateObject( newItem )) return; newItem.container = vendor; @@ -1171,11 +1166,8 @@ function SetVendorLayerItem( vendor, layer, itemID, hue, itemName ) /** @param {Character} vendor @param {number} layer @param {number} hue */ function SetVendorLayerHue( vendor, layer, hue ) { - if( !ValidateObject( vendor ) ) - return; - var layerItem = vendor.FindItemLayer( layer ); - if( ValidateObject( layerItem ) ) + if( ValidateObject( layerItem )) layerItem.colour = hue; } @@ -1196,16 +1188,12 @@ function SetVendorRaceGenderBody( vendor, isElf, isFemale ) /** @param {Character} pUser @param {number} categoryIndex */ function StoreClothingDyeCategory( pUser, categoryIndex ) { - if( ValidateObject( pUser ) ) - pUser.SetTempTag( "PlayerVendorClothingDyeCategory", categoryIndex ); + pUser.SetTempTag( "PlayerVendorClothingDyeCategory", categoryIndex ); } /** @param {Character} pUser @returns {number} */ function GetStoredClothingDyeCategory( pUser ) { - if( !ValidateObject( pUser ) ) - return -1; - var categoryIndex = pUser.GetTempTag( "PlayerVendorClothingDyeCategory" ); return ( categoryIndex === null || categoryIndex === undefined || categoryIndex === "" ) ? -1 : categoryIndex; } @@ -1213,6 +1201,9 @@ function GetStoredClothingDyeCategory( pUser ) /** @param {Socket} socket @param {Character} vendor */ function ShowPlayerVendorOwnerGump( socket, vendor ) { + if( socket == null ) + return; + if( vendor.aitype != 17 ) return; @@ -1365,7 +1356,7 @@ function AddHairHueCategoryPage( socket, myGump, pageNumber, title, hueList, but /** @param {Character} pUser @param {Character} vendor */ function ShowVendorCustomizeGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1450,7 +1441,7 @@ function ShowVendorCustomizeGump( pUser, vendor ) /** @type { ( pUser: Character, vendor: Character, pButton: number ) => void } */ function HandleVendorCustomizeButton( pUser, vendor, pButton ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1564,7 +1555,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) /** @param {Character} pUser @param {Character} vendor */ function ShowVendorClothingGump( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1713,7 +1704,7 @@ function ShowVendorClothingDyeGump( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor @param {number} pButton */ function HandleVendorClothingButton( pUser, vendor, pButton ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) + if( vendor.aitype != 17 ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1801,7 +1792,7 @@ function TrimString( text ) /** @param {Character} pUser @param {Character} vendor */ function BeginRenameVendor( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1815,7 +1806,7 @@ function BeginRenameVendor( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function BeginRenameVendorShop( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) @@ -1829,7 +1820,7 @@ function BeginRenameVendorShop( pUser, vendor ) /** @param {Character} pUser @param {Character} vendor */ function BeginDepositVendorGold( pUser, vendor ) { - if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 || !pUser.socket ) + if( vendor.aitype != 17 || !pUser.socket ) return; if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) From b6679fb9134b4deaed870a87177c67382434e462 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 6 Jun 2026 00:02:57 -0500 Subject: [PATCH 16/26] Update playervendor.js --- data/js/npc/ai/playervendor.js | 63 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 39e73a4d7..9f73f554d 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -1,24 +1,23 @@ /// // @ts-check -// Version: 1.1.6 - -// Max amount of money the vendor can hold in the bank. -// Held gold is not included in this limit, but will -// be used first to pay upkeep before bank funds are used. -var vendorMaxFunds = GetServerSetting( "VendorMaxFunds" ); - -// If true, returned vendor belongings skip player backpack entirely. -// Items, gold and vendor deed will try bank box first, then drop at vendor location. -// If false, belongings try backpack first, then bank box, then ground. -var onlyReturnToBank = GetServerSetting( "onlyReturnToBank" ); - -// Vendor upkeep settings -var vendorChargesEnabled = GetServerSetting( "VendorChargesEnabled" ); // Master toggle for vendor upkeep charges -var vendorBaseCharge = GetServerSetting( "VendorBaseCharge" ); // Flat fee per charge period -var vendorChargeHours = GetServerSetting( "VendorChargeHours" ); // Charge every X real hours -var vendorItemFeesEnabled = GetServerSetting( "VendorUseItemFeesEnabled" ); // Add item-based fee from listed item prices -var vendorItemFeeDivisor = GetServerSetting( "VendorItemFeeDivisor" ); // 3 gold per 500 worth of one item -var vendorItemFeeAmount = GetServerSetting( "VendorItemFeeAmount" ); // Fee added per divisor step +// Version: 1.1.7 + +const VendorSettings = { + // Max amount of money the vendor can hold in the bank. + // Held gold is not included in this limit, but will + // be used first to pay upkeep before bank funds are used. + get MaxFunds() { return GetServerSetting( "VendorMaxFunds" ); }, + // If true, returned vendor belongings skip player backpack entirely. + // Items, gold and vendor deed will try bank box first, then drop at vendor location. + // If false, belongings try backpack first, then bank box, then ground. + get OnlyReturnToBank() { return GetServerSetting( "onlyReturnToBank" ); }, + get ChargesEnabled() { return GetServerSetting( "VendorChargesEnabled" ); },// Master toggle for vendor upkeep charges + get BaseCharge() { return GetServerSetting( "VendorBaseCharge" ); },// Flat fee per charge period + get ChargeHours() { return GetServerSetting( "VendorChargeHours" ); },// Charge every X real hours + get ItemFeesEnabled() { return GetServerSetting( "VendorUseItemFeesEnabled" ); },// Add item-based fee from listed item prices + get ItemFeeDivisor() { return GetServerSetting( "VendorItemFeeDivisor" ); },// 3 gold per 500 worth of one item + get ItemFeeAmount() { return GetServerSetting( "VendorItemFeeAmount" ); } // Fee added per divisor step +} const VendorEquipmentLayer = { OneHand: 0x01, @@ -197,10 +196,10 @@ function GetHairOrBeardName( entry, socket ) /** @param {Item} itemObj @returns {number} */ function GetVendorItemPeriodFee( itemObj ) { - if( itemObj.buyValue <= 0 || !vendorItemFeesEnabled || vendorItemFeeDivisor <= 0 || vendorItemFeeAmount <= 0 ) + if( itemObj.buyValue <= 0 || !VendorSettings.ItemFeesEnabled || VendorSettings.ItemFeeDivisor <= 0 || VendorSettings.ItemFeeAmount <= 0 ) return 0; - return Math.floor( itemObj.buyValue / vendorItemFeeDivisor ) * vendorItemFeeAmount; + return Math.floor( itemObj.buyValue / VendorSettings.ItemFeeDivisor ) * VendorSettings.ItemFeeAmount; } /** @type { ( vendor: Character ) => number } */ @@ -223,14 +222,14 @@ function GetVendorItemFeeTotal( vendor ) /** @type { ( vendor: Character ) => number } */ function GetVendorChargePerPeriod( vendor ) { - if( vendor.aitype != 17 || !vendorChargesEnabled ) + if( vendor.aitype != 17 || !VendorSettings.ChargesEnabled ) return 0; var overrideValue = vendor.GetTag( "VendorChargePerPeriod" ); if( overrideValue > 0 ) return overrideValue; - return vendorBaseCharge + ( vendorItemFeesEnabled ? GetVendorItemFeeTotal( vendor ) : 0 ); + return VendorSettings.BaseCharge + ( VendorSettings.ItemFeesEnabled ? GetVendorItemFeeTotal( vendor ) : 0 ); } /** @param {Character} vendor @param {number} amount @returns {number} */ @@ -243,7 +242,7 @@ function DepositVendorBankGold( vendor, amount ) if( bankGold < 0 ) bankGold = 0; - var roomLeft = vendorMaxFunds - bankGold; + var roomLeft = VendorSettings.MaxFunds - bankGold; if( roomLeft <= 0 ) return 0; @@ -338,7 +337,7 @@ function GetVendorPeriodsAffordable( vendor ) /** @param {Character} vendor @returns {number} */ function GetVendorHoursAffordable( vendor ) { - return GetVendorPeriodsAffordable( vendor ) * vendorChargeHours; + return GetVendorPeriodsAffordable( vendor ) * VendorSettings.ChargeHours; } /** @param {Character} vendor @returns {number} */ @@ -380,7 +379,7 @@ function PlaceItemForOwnerOrDrop( itemObj, pUser, vendor ) var pack = pUser.pack; var bankBox = pUser.FindItemLayer( 29 ); - if( onlyReturnToBank ) + if( VendorSettings.OnlyReturnToBank ) { if( TryMoveItemToContainer( itemObj, bankBox ) ) return 2; @@ -588,7 +587,7 @@ function RemoveVendorForNoFunds( vendor, notifyChar ) if(( itemResults.pack + itemResults.bank + itemResults.ground ) > 0 ) { - if( onlyReturnToBank ) + if( VendorSettings.OnlyReturnToBank ) ownerSocket.SysMessage( GetDictionaryEntry( 40002, ownerSocket.language ), itemResults.bank, itemResults.ground ); else ownerSocket.SysMessage( GetDictionaryEntry( 40003, ownerSocket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); @@ -643,10 +642,10 @@ function CheckVendorUpkeep( vendor, notifyChar ) if( vendor.aitype != 17 ) return false; - if( !vendorChargesEnabled ) + if( !VendorSettings.ChargesEnabled ) return true; - var chargeInterval = vendorChargeHours * 60 * 60; + var chargeInterval = VendorSettings.ChargeHours * 60 * 60; if( chargeInterval <= 0 ) return true; @@ -976,7 +975,7 @@ function DismissVendor( pUser, vendor ) if(( itemResults.pack + itemResults.bank + itemResults.ground ) > 0 ) { - if( onlyReturnToBank ) + if( VendorSettings.OnlyReturnToBank ) socket.SysMessage( GetDictionaryEntry( 40002, socket.language ), itemResults.bank, itemResults.ground ); else socket.SysMessage( GetDictionaryEntry( 40003, socket.language ), itemResults.pack, itemResults.bank, itemResults.ground ); @@ -1250,7 +1249,7 @@ function ShowPlayerVendorOwnerGump( socket, vendor ) myGump.AddButton( 390, 209, 4005, 4007, 1, 0, 0 ); myGump.AddHTMLGump( 425, 210, 120, 20, false, false, "" + GetDictionaryEntry( 18762, socket.language ) + "" ); - if( !vendorChargesEnabled ) + if( !VendorSettings.ChargesEnabled ) { myGump.AddHTMLGump( 40, 25, 260, 20, false, false, "" + GetDictionaryEntry( 40035, socket.language ) + "" ); myGump.AddText( 300, 25, 2603, GetDictionaryEntry( 40043, socket.language ) ); @@ -1285,7 +1284,7 @@ function ShowPlayerVendorOwnerGump( socket, vendor ) myGump.AddText( 300, 120, 1153, "" + perPeriod ); myGump.AddHTMLGump( 40, 144, 260, 20, false, false, "" + GetDictionaryEntry( 40041, socket.language ) + "" ); - myGump.AddText( 300, 144, 1153, "" + vendorChargeHours ); + myGump.AddText( 300, 144, 1153, "" + VendorSettings.ChargeHours ); myGump.AddHTMLGump( 40, 168, 260, 20, false, false, "" + GetDictionaryEntry( 40042, socket.language ) + "" ); myGump.AddText( 300, 168, 1153, "" + itemFeeTotal ); From 511b64258d177b539d45ee68c98d8d5e61031ae0 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 6 Jun 2026 00:24:01 -0500 Subject: [PATCH 17/26] Update playervendor.js --- data/js/npc/ai/playervendor.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 9f73f554d..b05812414 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -1453,18 +1453,21 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) if( isElf ) hairStyles = isFemale ? femaleElfHairStyles : maleElfHairStyles; + // Return to vendor owner menu if( pButton == 5000 ) { ShowPlayerVendorOwnerGump( pUser.socket, vendor ); return; } + // Refresh vendor customize menu if( pButton == 5007 ) { ShowVendorCustomizeGump( pUser, vendor ); return; } + // Toggle vendor gender if( pButton == 5001 ) { RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Beard ); @@ -1473,6 +1476,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Toggle vendor race if( pButton == 5006 ) { RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Hair ); @@ -1493,6 +1497,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Remove vendor hair if( pButton == 5002 ) { RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Hair ); @@ -1500,6 +1505,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Remove vendor beard if( pButton == 5004 ) { RemoveVendorLayerItem( vendor, VendorEquipmentLayer.Beard ); @@ -1507,6 +1513,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Set vendor hair style if( pButton >= 0x1000 && pButton < ( 0x1000 + 256 ) ) { var hairIndex = pButton - 0x1000; @@ -1521,6 +1528,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Set vendor beard style if( pButton >= 0x2000 && pButton < ( 0x2000 + 256 ) ) { var beardIndex = pButton - 0x2000; @@ -1535,6 +1543,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Set vendor hair color if( pButton >= 0x3000 && pButton < 0x4000 ) { SetVendorLayerHue( vendor, VendorEquipmentLayer.Hair, pButton - 0x3000 ); @@ -1542,6 +1551,7 @@ function HandleVendorCustomizeButton( pUser, vendor, pButton ) return; } + // Set vendor beard color if( pButton >= 0x4000 && pButton < 0x5000 ) { if( !isElf && !isFemale ) @@ -1709,18 +1719,21 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) if( !ValidateObject( vendor.owner ) || vendor.owner.serial != pUser.serial ) return; + // Return to vendor customize menu if( pButton == 0x8FFF ) { ShowVendorCustomizeGump( pUser, vendor ); return; } + // Return to vendor clothing menu if( pButton == 0x8FFE ) { ShowVendorClothingGump( pUser, vendor ); return; } + // Remove selected clothing layer if( pButton >= 0x7000 && pButton < ( 0x7000 + 100 ) ) { var removeCatIndex = pButton - 0x7000; @@ -1732,6 +1745,7 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) return; } + // Equip selected clothing item if( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 ) ) { var entryValue = pButton - 0x5000; @@ -1752,6 +1766,7 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) return; } + // Open clothing dye menu if( pButton >= 0x8000 && pButton < ( 0x8000 + vendorClothingCategories.length ) ) { var dyeCatIndex = pButton - 0x8000; @@ -1763,6 +1778,7 @@ function HandleVendorClothingButton( pUser, vendor, pButton ) return; } + // Set selected clothing color if( pButton >= 0x9000 && pButton < ( 0x9000 + 0x1000 ) ) { var hueValue = pButton - 0x9000; @@ -1895,6 +1911,7 @@ function onGumpPress( pSock, pButton, gumpData ) if( !CheckVendorUpkeep( vendor, pUser ) ) return; + // Handle vendor customize buttons if( pButton == 5000 || pButton == 5001 || pButton == 5002 || pButton == 5004 || pButton == 5006 || pButton == 5007 || ( pButton >= 0x1000 && pButton < ( 0x1000 + 256 ) ) || ( pButton >= 0x2000 && pButton < ( 0x2000 + 256 ) ) || @@ -1905,6 +1922,7 @@ function onGumpPress( pSock, pButton, gumpData ) return; } + // Handle vendor clothing buttons if( pButton == 0x8FFF || pButton == 0x8FFE || ( pButton >= 0x5000 && pButton < ( 0x5000 + 10000 ) ) || ( pButton >= 0x7000 && pButton < ( 0x7000 + 100 ) ) || From e7f917581fbd318d26943fc2ce380b95dcc1bbab Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 13 Jun 2026 16:36:13 -0500 Subject: [PATCH 18/26] fixes --- data/js/npc/ai/playervendor.js | 24 ++++++++++++++++-------- data/js/server/house/playerVendorDeed.js | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index b05812414..df969064a 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -6,17 +6,17 @@ const VendorSettings = { // Max amount of money the vendor can hold in the bank. // Held gold is not included in this limit, but will // be used first to pay upkeep before bank funds are used. - get MaxFunds() { return GetServerSetting( "VendorMaxFunds" ); }, + get MaxFunds() { return GetSafeNumber( GetServerSetting( "VendorMaxFunds" ), 1000000 ); }, // If true, returned vendor belongings skip player backpack entirely. // Items, gold and vendor deed will try bank box first, then drop at vendor location. // If false, belongings try backpack first, then bank box, then ground. - get OnlyReturnToBank() { return GetServerSetting( "onlyReturnToBank" ); }, - get ChargesEnabled() { return GetServerSetting( "VendorChargesEnabled" ); },// Master toggle for vendor upkeep charges - get BaseCharge() { return GetServerSetting( "VendorBaseCharge" ); },// Flat fee per charge period - get ChargeHours() { return GetServerSetting( "VendorChargeHours" ); },// Charge every X real hours - get ItemFeesEnabled() { return GetServerSetting( "VendorUseItemFeesEnabled" ); },// Add item-based fee from listed item prices - get ItemFeeDivisor() { return GetServerSetting( "VendorItemFeeDivisor" ); },// 3 gold per 500 worth of one item - get ItemFeeAmount() { return GetServerSetting( "VendorItemFeeAmount" ); } // Fee added per divisor step + get OnlyReturnToBank() { return GetSafeNumber( GetServerSetting( "onlyReturnToBank" ), 0 ) != 0; }, + get ChargesEnabled() { return GetSafeNumber( GetServerSetting( "VendorChargesEnabled" ), 0 ) != 0; },// Master toggle for vendor upkeep charges + get BaseCharge() { return GetSafeNumber( GetServerSetting( "VendorBaseCharge" ), 0 ); },// Flat fee per charge period + get ChargeHours() { return GetSafeNumber( GetServerSetting( "VendorChargeHours" ), 24 ); },// Charge every X real hours + get ItemFeesEnabled() { return GetSafeNumber( GetServerSetting( "VendorUseItemFeesEnabled" ), 0 ) != 0; },// Add item-based fee from listed item prices + get ItemFeeDivisor() { return GetSafeNumber( GetServerSetting( "VendorItemFeeDivisor" ), 500 ); },// 3 gold per 500 worth of one item + get ItemFeeAmount() { return GetSafeNumber( GetServerSetting( "VendorItemFeeAmount" ), 3 ); } // Fee added per divisor step } const VendorEquipmentLayer = { @@ -175,6 +175,14 @@ const vendorClothingCategories = [ ]} ]; +function GetSafeNumber( value, defaultValue ) +{ + if( value === null || value === undefined || value === "" || isNaN( value )) + return defaultValue; + + return Number( value ); +} + /** @param {VendorHueCategory} entry @param {Socket|null} socket @returns {string} */ function GetVendorHueCategoryName( entry, socket ) { diff --git a/data/js/server/house/playerVendorDeed.js b/data/js/server/house/playerVendorDeed.js index 7a70f9d68..7a8681a26 100644 --- a/data/js/server/house/playerVendorDeed.js +++ b/data/js/server/house/playerVendorDeed.js @@ -80,7 +80,7 @@ function onUseChecked( pUser, iUsed ) // Add the player vendor to the house's list of vendors iMulti.AddVendor( npcVendor ); - npcVendor.SetTag( "VendorBankAccount",1000 ); + npcVendor.SetTag( "VendorBankAccount",0 ); npcVendor.AddScriptTrigger( 3110 ); var vendorName = iUsed.GetTag( "vendorName" ); if( vendorName ) From 125ef642ed9f25e10c946bc0eee9e0523830f045 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sat, 13 Jun 2026 21:06:35 -0500 Subject: [PATCH 19/26] Update shoplist.dfn --- data/dfndata/items/shoplist.dfn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/dfndata/items/shoplist.dfn b/data/dfndata/items/shoplist.dfn index 188bebb33..88adb7e76 100644 --- a/data/dfndata/items/shoplist.dfn +++ b/data/dfndata/items/shoplist.dfn @@ -407,6 +407,7 @@ RSHOPITEM=0x097e RSHOPITEM=0x098c RSHOPITEM=0x103c RSHOPITEM=0x09f2 +SELLITEM=playervendordeed SELLITEM=0x099f SELLITEM=0x099b SELLITEM=0x09c7 @@ -1550,6 +1551,7 @@ RSHOPITEM=0x1f98 RSHOPITEM=0x09c8 RSHOPITEM=0x09c4 RSHOPITEM=0x098d +SELLITEM=playervendordeed SELLITEM=0x097b SELLITEM=0x09bb SELLITEM=0x09f2 From cf798849943bd0f523f4584f4b89219d9d188729 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 14 Jun 2026 10:56:23 -0500 Subject: [PATCH 20/26] Fixes --- data/js/npc/ai/playervendor.js | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index df969064a..645f7e9e9 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -6,17 +6,17 @@ const VendorSettings = { // Max amount of money the vendor can hold in the bank. // Held gold is not included in this limit, but will // be used first to pay upkeep before bank funds are used. - get MaxFunds() { return GetSafeNumber( GetServerSetting( "VendorMaxFunds" ), 1000000 ); }, + get MaxFunds() { return GetServerSetting( "VendorMaxFunds" ); }, // If true, returned vendor belongings skip player backpack entirely. // Items, gold and vendor deed will try bank box first, then drop at vendor location. // If false, belongings try backpack first, then bank box, then ground. - get OnlyReturnToBank() { return GetSafeNumber( GetServerSetting( "onlyReturnToBank" ), 0 ) != 0; }, - get ChargesEnabled() { return GetSafeNumber( GetServerSetting( "VendorChargesEnabled" ), 0 ) != 0; },// Master toggle for vendor upkeep charges - get BaseCharge() { return GetSafeNumber( GetServerSetting( "VendorBaseCharge" ), 0 ); },// Flat fee per charge period - get ChargeHours() { return GetSafeNumber( GetServerSetting( "VendorChargeHours" ), 24 ); },// Charge every X real hours - get ItemFeesEnabled() { return GetSafeNumber( GetServerSetting( "VendorUseItemFeesEnabled" ), 0 ) != 0; },// Add item-based fee from listed item prices - get ItemFeeDivisor() { return GetSafeNumber( GetServerSetting( "VendorItemFeeDivisor" ), 500 ); },// 3 gold per 500 worth of one item - get ItemFeeAmount() { return GetSafeNumber( GetServerSetting( "VendorItemFeeAmount" ), 3 ); } // Fee added per divisor step + get OnlyReturnToBank() { return GetServerSetting( "onlyReturnToBank" ); }, + get ChargesEnabled() { return GetServerSetting( "VendorChargesEnabled" ); },// Master toggle for vendor upkeep charges + get BaseCharge() { return GetServerSetting( "VendorBaseCharge" ); },// Flat fee per charge period + get ChargeHours() { return GetServerSetting( "VendorChargeHours" ); },// Charge every X real hours + get ItemFeesEnabled() { return GetServerSetting( "VendorUseItemFeesEnabled" ); },// Add item-based fee from listed item prices + get ItemFeeDivisor() { return GetServerSetting( "VendorItemFeeDivisor" ); },// 3 gold per 500 worth of one item + get ItemFeeAmount() { return GetServerSetting( "VendorItemFeeAmount" ); } // Fee added per divisor step } const VendorEquipmentLayer = { @@ -175,14 +175,6 @@ const vendorClothingCategories = [ ]} ]; -function GetSafeNumber( value, defaultValue ) -{ - if( value === null || value === undefined || value === "" || isNaN( value )) - return defaultValue; - - return Number( value ); -} - /** @param {VendorHueCategory} entry @param {Socket|null} socket @returns {string} */ function GetVendorHueCategoryName( entry, socket ) { @@ -204,10 +196,10 @@ function GetHairOrBeardName( entry, socket ) /** @param {Item} itemObj @returns {number} */ function GetVendorItemPeriodFee( itemObj ) { - if( itemObj.buyValue <= 0 || !VendorSettings.ItemFeesEnabled || VendorSettings.ItemFeeDivisor <= 0 || VendorSettings.ItemFeeAmount <= 0 ) + if( itemObj.buyvalue <= 0 || !VendorSettings.ItemFeesEnabled || VendorSettings.ItemFeeDivisor <= 0 || VendorSettings.ItemFeeAmount <= 0 ) return 0; - return Math.floor( itemObj.buyValue / VendorSettings.ItemFeeDivisor ) * VendorSettings.ItemFeeAmount; + return Math.floor( itemObj.buyvalue / VendorSettings.ItemFeeDivisor ) * VendorSettings.ItemFeeAmount; } /** @type { ( vendor: Character ) => number } */ @@ -471,7 +463,7 @@ function CreateVendorDismissDeedAtLocation( vendor ) return null; deed.type = 217; - deed.buyValue = 2000; + deed.buyvalue = 2000; deed.SetTag( "vendorName", vendor.name ); DropItemAtVendorLocation( deed, vendor ); return deed; @@ -495,7 +487,7 @@ function CreateVendorDismissDeedForOwner( pUser, vendor ) return null; deed.type = 217; - deed.buyValue = 2000; + deed.buyvalue = 2000; deed.SetTag( "vendorName", vendor.name ); return deed; } From d226d7b78a7b3eb8c742946b0c5c71e384c36b77 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 21 Jun 2026 11:48:49 -0500 Subject: [PATCH 21/26] vendorPrice --- data/js/npc/ai/playervendor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 645f7e9e9..2e7aaddb5 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -196,10 +196,10 @@ function GetHairOrBeardName( entry, socket ) /** @param {Item} itemObj @returns {number} */ function GetVendorItemPeriodFee( itemObj ) { - if( itemObj.buyvalue <= 0 || !VendorSettings.ItemFeesEnabled || VendorSettings.ItemFeeDivisor <= 0 || VendorSettings.ItemFeeAmount <= 0 ) + if( itemObj.vendorPrice <= 0 || !VendorSettings.ItemFeesEnabled || VendorSettings.ItemFeeDivisor <= 0 || VendorSettings.ItemFeeAmount <= 0 ) return 0; - return Math.floor( itemObj.buyvalue / VendorSettings.ItemFeeDivisor ) * VendorSettings.ItemFeeAmount; + return Math.floor( itemObj.vendorPrice / VendorSettings.ItemFeeDivisor ) * VendorSettings.ItemFeeAmount; } /** @type { ( vendor: Character ) => number } */ From 3c2f6d930386b8e668dfa9ca92526394fe7031ef Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 21 Jun 2026 12:54:59 -0500 Subject: [PATCH 22/26] upkeep timer --- data/js/npc/ai/playervendor.js | 26 ++++++++++++++++++++++++ data/js/server/house/playerVendorDeed.js | 1 + 2 files changed, 27 insertions(+) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 2e7aaddb5..10be714ec 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -19,6 +19,10 @@ const VendorSettings = { get ItemFeeAmount() { return GetServerSetting( "VendorItemFeeAmount" ); } // Fee added per divisor step } +const VendorTimer = { + Upkeep: 90 +}; + const VendorEquipmentLayer = { OneHand: 0x01, TwoHand: 0x02, @@ -2030,4 +2034,26 @@ function onSpeechInput( pUser, targObj, pSpeech, pSpeechID ) ShowPlayerVendorOwnerGump( socket, vendor ); break; } +} + +/** @type { ( timerObj: BaseObject, timerID: number ) => void } */ +function onTimer( timerObj, timerID ) +{ + if( timerID != VendorTimer.Upkeep ) + return; + + if( !ValidateObject( timerObj ) || !timerObj.isChar || timerObj.aitype != 17 ) + return; + + if( CheckVendorUpkeep( timerObj, null ) ) + StartVendorUpkeepTimer( timerObj ); +} + + +function StartVendorUpkeepTimer( vendor ) +{ + if( vendor.aitype != 17 ) + return; + + vendor.StartTimer( 60000, VendorTimer.Upkeep, true ); } \ No newline at end of file diff --git a/data/js/server/house/playerVendorDeed.js b/data/js/server/house/playerVendorDeed.js index 7a8681a26..d52a19537 100644 --- a/data/js/server/house/playerVendorDeed.js +++ b/data/js/server/house/playerVendorDeed.js @@ -82,6 +82,7 @@ function onUseChecked( pUser, iUsed ) iMulti.AddVendor( npcVendor ); npcVendor.SetTag( "VendorBankAccount",0 ); npcVendor.AddScriptTrigger( 3110 ); + npcVendor.StartTimer( 60000, 90, 3110 ); var vendorName = iUsed.GetTag( "vendorName" ); if( vendorName ) { From 959c2013128508c6beb3e53984a496594a489217 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 21 Jun 2026 13:45:22 -0500 Subject: [PATCH 23/26] update --- data/js/npc/ai/playervendor.js | 4 + source/CResponse.cpp | 145 --------------------------------- source/CResponse.h | 37 --------- 3 files changed, 4 insertions(+), 182 deletions(-) diff --git a/data/js/npc/ai/playervendor.js b/data/js/npc/ai/playervendor.js index 10be714ec..88fc8da89 100644 --- a/data/js/npc/ai/playervendor.js +++ b/data/js/npc/ai/playervendor.js @@ -1059,6 +1059,9 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( !ValidateObject( pUser ) || !ValidateObject( vendor ) || vendor.aitype != 17 ) return 0; + if( !pUser.InRange( vendor, 3 )) + return 0; + var cmd = NormalizeVendorSpeech( vendor, speech ); if( cmd == "view" || cmd == "browse" || cmd == "look" ) @@ -1066,6 +1069,7 @@ function HandleVendorSpeechCommand( pUser, vendor, speech ) if( VendorAccessBlocked( pUser, vendor )) return 2; + vendor.TextMessage( "Take a look at my goods."); OpenVendorBackpack( pUser, vendor ); return 2; } diff --git a/source/CResponse.cpp b/source/CResponse.cpp index 96031ceff..118e8616e 100644 --- a/source/CResponse.cpp +++ b/source/CResponse.cpp @@ -242,13 +242,6 @@ bool WhichResponse( CSocket *mSock, CChar *mChar, std::string text, CChar *tChar case TW_BUY: tResp = new CVendorBuyResponse( false, oldstrutil::upper( text )); break; case TW_VENDORSELL: tResp = new CVendorSellResponse( true, oldstrutil::upper( text )); break; case TW_SELL: tResp = new CVendorSellResponse( false, oldstrutil::upper( text )); break; - case TW_VENDORVIEW: tResp = new CVendorViewResponse( true, oldstrutil::upper( text )); break; - case TW_VIEW: tResp = new CVendorViewResponse( false, oldstrutil::upper( text )); break; - case TW_VENDORGOLD: tResp = new CVendorGoldResponse( true, oldstrutil::upper( text )); break; - case TW_COLLECT: [[fallthrough]]; - case TW_GOLD: tResp = new CVendorGoldResponse( false, oldstrutil::upper( text )); break; - case TW_VENDORSTATUS: tResp = new CVendorStatusResponse( true, oldstrutil::upper( text )); break; - case TW_STATUS: tResp = new CVendorStatusResponse( false, oldstrutil::upper( text )); break; case TW_VENDORDISMISS: tResp = new CVendorDismissResponse( true, oldstrutil::upper( text )); break; case TW_DISMISS: tResp = new CVendorDismissResponse( false, oldstrutil::upper( text )); break; case TW_HOUSEBAN: tResp = new CHouseMultiResponse( TARGET_HOUSEBAN, 585 ); break; @@ -1032,144 +1025,6 @@ bool CVendorSellResponse::Handle( CSocket *mSock, CChar *mChar, CChar *vendorNpc return false; } -CVendorViewResponse::CVendorViewResponse( bool vendVal, const std::string &text ) : CBaseVendorResponse( vendVal, text ) -{ -} -//o------------------------------------------------------------------------------------------------o -//| Function - CVendorViewResponse::Handle() -//o------------------------------------------------------------------------------------------------o -//| Purpose - Handles response to players wanting to view the items a vendor has for sale -//o------------------------------------------------------------------------------------------------o -bool CVendorViewResponse::Handle( CSocket *mSock, [[maybe_unused]] CChar *mChar, CChar *vendorNpc ) -{ - if( vendorNpc->GetNpcAiType() == AI_PLAYERVENDOR ) - { - CItem *pack = nullptr; - vendorNpc->TextMessage( mSock, 385, TALK, false ); // Take a look at my goods. - pack = vendorNpc->GetPackItem(); - if( ValidateObject( pack )) - { - mSock->OpenPack( pack, true ); - } - } - if( !saidVendor ) - return false; - - return true; -} - -CVendorGoldResponse::CVendorGoldResponse( bool vendVal, const std::string &text ) : CBaseVendorResponse( vendVal, text ) -{ -} -//o------------------------------------------------------------------------------------------------o -//| Function - CVendorGoldResponse::Handle() -//o------------------------------------------------------------------------------------------------o -//| Purpose - Handles response to players wanting to withdraw their earnings from their vendor -//o------------------------------------------------------------------------------------------------o -bool CVendorGoldResponse::Handle( CSocket *mSock, [[maybe_unused]] CChar *mChar, CChar *vendorNpc ) -{ - if( vendorNpc->GetNpcAiType() == AI_PLAYERVENDOR ) - { - CChar *mChar = mSock->CurrcharObj(); - if( mChar == vendorNpc->GetOwnerObj() ) - { - UI32 pay = 0; - auto give = vendorNpc->GetHoldG(); - auto earned = vendorNpc->GetHoldG(); - - if( vendorNpc->GetHoldG() <= 0 ) - { - vendorNpc->TextMessage( mSock, 1326, TALK, false ); // I have no gold waiting for you. - vendorNpc->SetHoldG( 0 ); - } - else if( vendorNpc->GetHoldG() > 0 && vendorNpc->GetHoldG() <= MAX_STACK ) - { - if( vendorNpc->GetHoldG() > 9 ) - { - pay = static_cast( vendorNpc->GetHoldG() / 10 ); - give = vendorNpc->GetHoldG() - pay; - } - else - { - pay = vendorNpc->GetHoldG(); - give = 0; - } - vendorNpc->SetHoldG( 0 ); - } - else - { - UI32 t = vendorNpc->GetHoldG() - MAX_STACK; // yank of 65 grand, then do calculations - vendorNpc->SetHoldG( t ); - pay = 6554; - give = 58981; - if( t > 0 ) - { - vendorNpc->TextMessage( mSock, 1327, TALK, false ); // You still have money left to claim. - } - } - if( give ) - { - Items->CreateScriptItem( mSock, mChar, "0x0EED", give, OT_ITEM, true ); - } - - // Today's purchases total %i gold. I am keeping %i gold for my self. Here is the remaining %i gold. Have a nice day. - vendorNpc->TextMessage( mSock, 1328, TALK, 0, earned, pay, give ); - } - else - { - vendorNpc->TextMessage( mSock, 1329, TALK, false ); // I don't work for you! - } - } - if( !saidVendor ) - return false; - - return true; -} - -CVendorStatusResponse::CVendorStatusResponse( bool vendVal, const std::string &text ) : CBaseVendorResponse( vendVal, text ) -{ -} -//o------------------------------------------------------------------------------------------------o -//| Function - CVendorStatusResponse::Handle() -//o------------------------------------------------------------------------------------------------o -//| Purpose - Handles response to players wanting to see the status of their vendor -//o------------------------------------------------------------------------------------------------o -bool CVendorStatusResponse::Handle( CSocket *mSock, [[maybe_unused]] CChar *mChar, CChar *vendorNpc ) -{ - if( vendorNpc->GetNpcAiType() == AI_PLAYERVENDOR ) - { - CChar *mChar = mSock->CurrcharObj(); - if( mChar == vendorNpc->GetOwnerObj() ) - { - if( vendorNpc->GetHoldG() <= 0 ) - { - vendorNpc->TextMessage( mSock, 1326, TALK, false ); // I have no gold waiting for you. - } - else - { - UI32 pay = 0; - if( vendorNpc->GetHoldG() > 9 ) - { - pay = static_cast( vendorNpc->GetHoldG() / 10 ); - } - else - { - pay = vendorNpc->GetHoldG(); - } - vendorNpc->TextMessage( mSock, 1782, TALK, 0, vendorNpc->GetHoldG(), pay ); // Today's purchases total %i gold. I am keeping %i gold for my self. - } - } - else - { - vendorNpc->TextMessage( mSock, 1329, TALK, false ); // I don't work for you! - } - } - if( !saidVendor ) - return false; - - return true; -} - CVendorDismissResponse::CVendorDismissResponse( bool vendVal, const std::string &text ) : CBaseVendorResponse( vendVal, text ) { } diff --git a/source/CResponse.h b/source/CResponse.h index b1434f29b..5bbb6caed 100644 --- a/source/CResponse.h +++ b/source/CResponse.h @@ -22,9 +22,6 @@ enum TriggerWords TW_HOUSEBAN = 0x0034, // I Ban Thee TW_STOP2 = 0x0036, TW_VENDORBUY = 0x003C, // Vendor Buy/Purchase - TW_VENDORVIEW = 0x003D, // Vendor View/Browse/Look - TW_VENDORGOLD = 0x003E, // Vendor Gold/Collect/Get - TW_VENDORSTATUS = 0x003F, // Vendor Status/Info TW_VENDORDISMISS = 0x0040, // Vendor Dismiss/Replace TW_SETNAME = 0x0042, // Set Name TW_BOATFORWARD = 0x0045, // Forward @@ -79,7 +76,6 @@ enum TriggerWords TW_TRAINSMITH = 0x0076, // Train Blacksmith/Smith/Blacksmithy/Smithing/Blacksmithing TW_FOLLOW2 = 0x00E8, // Follow - TW_GOLD = 0x0134, // Gold TW_TRASHBARREL = 0x013E, // I wish to place a trash barrel TW_VENDORSELL = 0x014D, // Vendor Sell TW_COME = 0x0155, // Come @@ -107,9 +103,6 @@ enum TriggerWords TW_STAY = 0x016F, // Stay TW_ALLSTAY = 0x0170, // All Stay TW_BUY = 0x0171, // Buy - TW_VIEW = 0x0172, // View - TW_COLLECT = 0x0173, // Collect - TW_STATUS = 0x0174, // Status TW_DISMISS = 0x0175, // Dismiss TW_SELL = 0x0177, // Sell @@ -291,36 +284,6 @@ class CVendorSellResponse : public CBaseVendorResponse virtual bool Handle( CSocket *mSock, CChar *mChar, CChar *Npc ) override; }; -class CVendorViewResponse : public CBaseVendorResponse -{ -public: - CVendorViewResponse( bool vendVal, const std::string &text ); - virtual ~CVendorViewResponse() - { - } - virtual bool Handle( CSocket *mSock, CChar *mChar, CChar *Npc ) override; -}; - -class CVendorGoldResponse : public CBaseVendorResponse -{ -public: - CVendorGoldResponse( bool vendVal, const std::string &text ); - virtual ~CVendorGoldResponse() - { - } - virtual bool Handle( CSocket *mSock, CChar *mChar, CChar *Npc ) override; -}; - -class CVendorStatusResponse : public CBaseVendorResponse -{ -public: - CVendorStatusResponse( bool vendVal, const std::string &text ); - virtual ~CVendorStatusResponse() - { - } - virtual bool Handle( CSocket *mSock, CChar *mChar, CChar *Npc ) override; -}; - class CVendorDismissResponse : public CBaseVendorResponse { public: From 402c362d006097e128fcd41a10b651303cd9ecdc Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:39:45 -0500 Subject: [PATCH 24/26] Update CResponse.h --- source/CResponse.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/CResponse.h b/source/CResponse.h index 5bbb6caed..f36095784 100644 --- a/source/CResponse.h +++ b/source/CResponse.h @@ -22,6 +22,9 @@ enum TriggerWords TW_HOUSEBAN = 0x0034, // I Ban Thee TW_STOP2 = 0x0036, TW_VENDORBUY = 0x003C, // Vendor Buy/Purchase + TW_VENDORVIEW = 0x003D, // Vendor View/Browse/Look + TW_VENDORGOLD = 0x003E, // Vendor Gold/Collect/Get + TW_VENDORSTATUS = 0x003F, // Vendor Status/Info TW_VENDORDISMISS = 0x0040, // Vendor Dismiss/Replace TW_SETNAME = 0x0042, // Set Name TW_BOATFORWARD = 0x0045, // Forward @@ -76,6 +79,7 @@ enum TriggerWords TW_TRAINSMITH = 0x0076, // Train Blacksmith/Smith/Blacksmithy/Smithing/Blacksmithing TW_FOLLOW2 = 0x00E8, // Follow + TW_GOLD = 0x0134, // Gold TW_TRASHBARREL = 0x013E, // I wish to place a trash barrel TW_VENDORSELL = 0x014D, // Vendor Sell TW_COME = 0x0155, // Come @@ -103,6 +107,9 @@ enum TriggerWords TW_STAY = 0x016F, // Stay TW_ALLSTAY = 0x0170, // All Stay TW_BUY = 0x0171, // Buy + TW_VIEW = 0x0172, // View + TW_COLLECT = 0x0173, // Collect + TW_STATUS = 0x0174, // Status TW_DISMISS = 0x0175, // Dismiss TW_SELL = 0x0177, // Sell From 08c83bb503e94261231bd19044c71a1e516aabce Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:49:43 -0500 Subject: [PATCH 25/26] fixes --- source/SEFunctions.cpp | 2 +- source/cServerData.cpp | 6 +++--- source/cServerData.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/SEFunctions.cpp b/source/SEFunctions.cpp index 34f63d172..562a3a5fb 100644 --- a/source/SEFunctions.cpp +++ b/source/SEFunctions.cpp @@ -5799,7 +5799,7 @@ JSBool SE_GetServerSetting( JSContext *cx, uintN argc, jsval *vp ) JS_SET_RVAL( cx, vp, BOOLEAN_TO_JSVAL( cwmWorldState->ServerData()->OnlyReturnToBank() )); break; case 415: // VENDORMAXFUNDS - JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorMaxFunds() ))); + JS_SET_RVAL( cx, vp, INT_TO_JSVAL( static_cast( cwmWorldState->ServerData()->VendorMaxFunds() ))); break; default: ScriptError( cx, "GetServerSetting: Invalid server setting name provided" ); diff --git a/source/cServerData.cpp b/source/cServerData.cpp index e4dfd682c..39a983e84 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -5599,11 +5599,11 @@ auto CServerData::OnlyReturnToBank( bool newVal ) -> void //o------------------------------------------------------------------------------------------------o //| Purpose - Gets/Sets the Max amount of money the vendor can hold in the bank. //o------------------------------------------------------------------------------------------------o -auto CServerData::VendorMaxFunds() const -> SI16 +auto CServerData::VendorMaxFunds() const -> UI32 { return vendorMaxFunds; } -auto CServerData::VendorMaxFunds( SI16 value ) -> void +auto CServerData::VendorMaxFunds( UI32 value ) -> void { vendorMaxFunds = value; } @@ -7754,7 +7754,7 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) OnlyReturnToBank( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); break; case 415: // VENDORMAXFUNDS - VendorMaxFunds( static_cast( std::stoi( value ))); + VendorMaxFunds( static_cast( std::stoi( value ))); break; default: rValue = false; diff --git a/source/cServerData.h b/source/cServerData.h index 2334d131e..030b28036 100644 --- a/source/cServerData.h +++ b/source/cServerData.h @@ -344,7 +344,7 @@ class CServerData SI16 vendorItemFeeDivisor; // Listed item value divisor used for vendor item fees SI16 vendorItemFeeAmount; // Fee added per divisor step bool onlyReturnToBank; // returned vendor belongings skip player backpack entirely - SI16 vendorMaxFunds; // Max amount of money the vendor can hold in the bank. + UI32 vendorMaxFunds; // Max amount of money the vendor can hold in the bank. // SpeedUp R64 npcWalkingSpeed; // Speed at which walking NPCs move @@ -1417,8 +1417,8 @@ class CServerData auto OnlyReturnToBank( bool value ) -> void; auto OnlyReturnToBank() const -> bool; - auto VendorMaxFunds( SI16 value ) -> void; - SI16 VendorMaxFunds() const; + auto VendorMaxFunds( UI32 value ) -> void; + UI32 VendorMaxFunds() const; SI16 ServerTimeDay() const; UI08 ServerTimeHours() const; From 92b6875eb184c3ece4ac0ccba6e46504a5701d30 Mon Sep 17 00:00:00 2001 From: Dragon Slayer <85514184+DragonSlayer62@users.noreply.github.com> Date: Sun, 21 Jun 2026 18:01:33 -0500 Subject: [PATCH 26/26] Update cServerData.cpp --- source/cServerData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/cServerData.cpp b/source/cServerData.cpp index 39a983e84..0750efdc5 100644 --- a/source/cServerData.cpp +++ b/source/cServerData.cpp @@ -7754,7 +7754,7 @@ auto CServerData::HandleLine( const std::string& tag, const std::string& value ) OnlyReturnToBank( ( static_cast( std::stoul( value, nullptr, 0 ) ) >= 1 ? true : false ) ); break; case 415: // VENDORMAXFUNDS - VendorMaxFunds( static_cast( std::stoi( value ))); + VendorMaxFunds( static_cast( std::stoul( value, nullptr, 0 ))); break; default: rValue = false;