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;