diff --git a/data/dfndata/items/misc/houseteleporters.dfn b/data/dfndata/items/misc/houseteleporters.dfn new file mode 100644 index 000000000..c2c3df69d --- /dev/null +++ b/data/dfndata/items/misc/houseteleporters.dfn @@ -0,0 +1,24 @@ +[base_house_teleporter] +{ +get=base_item +name=a house teleporter +weight=100 +decay=1 +script=5080 +origin=hs +movable=1 +sectionid=house_teleporter +} + +[houseteleporter] +{ +get=base_house_teleporter +id=0x40BB +} + +[chargedhouseteleporter] +{ +get=base_house_teleporter +id=0x574A +custominttag=chargeable 1 +} \ No newline at end of file diff --git a/data/dictionaries/dictionary.CSY b/data/dictionaries/dictionary.CSY index 4c66d7eec..e0321859c 100644 --- a/data/dictionaries/dictionary.CSY +++ b/data/dictionaries/dictionary.CSY @@ -5693,5 +5693,37 @@ 30003=Šampion padl! 30004=Byl jsi odměněn Svitkem moci! 30005=Energie svatyně ubývá, protože nejsou přítomni žádní vyzyvatelé... +// [30600-30650] Teleport domu +30600=Pro propojení musí být tento objekt ve vašem batohu. +30601=Pro propojení zaměřte druhý teleport v batohu. +30602=Tento teleport je plně nabitý. +30603=Pro dobití zaměřte předmět pro dobíjení v batohu. +30604=Zabezpečení tohoto teleportu nelze změnit. +30605=Zabezpečení teleportu nastaveno na: %s. +30606=Tento teleport nelze přejmenovat. +30607=Tento teleport musí být propojen, než bude možné jej přejmenovat. +30608=Pro propojení musí být oba teleporty ve vašem batohu. +30609=Pro propojení zaměřte druhý teleport v batohu. +30610=Zdrojový teleport nenalezen. +30611=Toto není teleport domu. +30612=Musíte zaměřit druhý teleport. +30613=Tyto teleporty jsou různých typů a nelze je propojit. +30614=Oba teleporty musí být ve vašem batohu, aby se propojily. +30615=Teleporty propojené. +30616=Zaměřte se na dobíjecí předmět pro dobití teleportu. +30617=Tento předmět musí být ve vašem batohu. +30618=Teleport domu nelze dále nabíjet. +30619=Dobíjecí předmět se rozpadne na prach, když posiluje Teleport domu. +30620=Aby fungoval, musí být uzamčen v domě. +30621=Musí být umístěn uvnitř domu. +30622=Tento teleport může používat pouze majitel domu a spolumajitelé. +30623=Toto nyní nemůžete použít. +30624=Tento teleport není propojen. +30625=Cílový teleport není správně umístěn. +30626=V tomto teleportu nezbývají žádné náboje. +30627=Tento teleport je plně nabitý. +30628=Teleport nebyl nalezen. +30629=Tento teleport musí být propojen, než bude možné jej přejmenovat. +30630=Název teleportu nastaven na: %s } EOF diff --git a/data/dictionaries/dictionary.ENG b/data/dictionaries/dictionary.ENG index 7c6a7ef35..42440421e 100644 --- a/data/dictionaries/dictionary.ENG +++ b/data/dictionaries/dictionary.ENG @@ -5693,5 +5693,37 @@ 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... +// [30600-30650 ] House Teleporter +30600=This must be in your backpack to link it. +30601=Target the other teleporter in your backpack to link. +30602=This teleporter is fully charged. +30603=Target recharge item in your backpack to recharge +30604=You cannot change this teleporter's security. +30605=Teleporter security set to: %s +30606=You cannot rename this teleporter. +30607=This teleporter must be linked before it can be renamed. +30608=To link, both teleporters must be in your backpack. +30609=Target the other teleporter in your backpack to link. +30610=Source teleporter not found. +30611=That is not a house teleporter. +30612=You must target the other teleporter. +30613=These teleporters are different types and cannot be linked. +30614=Both teleporters must be in your backpack to link. +30615=Teleporters linked. +30616=Target recharge item to recharge the teleporter. +30617=This item must be in your backpack. +30618=The House Teleporter cannot be charged any further. +30619=The recharge item crumbles to dust as it strengthens the House Teleporter. +30620=This must be locked down in a house to function. +30621=This must be placed inside a house. +30622=Only the house owner and co-owners may use this teleporter. +30623=You cannot use that right now. +30624=This teleporter is not linked. +30625=The destination teleporter is not properly placed. +30626=There are no charges left in this teleporter. +30627=This teleporter is fully charged. +30628=Teleporter not found. +30629=This teleporter must be linked before it can be renamed. +30630=Teleporter name set to: %s } EOF diff --git a/data/dictionaries/dictionary.FRE b/data/dictionaries/dictionary.FRE index 33f64c63b..ff1e163e6 100644 --- a/data/dictionaries/dictionary.FRE +++ b/data/dictionaries/dictionary.FRE @@ -5857,5 +5857,36 @@ 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... +// [30600-30650] Téléporteur de maison +30600=Cet objet doit être dans votre sac à dos pour pouvoir le lier. +30601=Ciblez l'autre téléporteur dans votre sac à dos pour le lier. +30602=Ce téléporteur est entièrement chargé. +30603=Ciblez l'objet de recharge dans votre sac à dos pour le recharger. +30604=Vous ne pouvez pas modifier la sécurité de ce téléporteur. +30605=Sécurité du téléporteur définie sur : %s +30606=Vous ne pouvez pas renommer ce téléporteur. +30607=Ce téléporteur doit être lié avant de pouvoir être renommé. +30608=Pour les lier, les deux téléporteurs doivent être dans votre sac à dos. +30609=Ciblez l'autre téléporteur dans votre sac à dos pour le lier. +30610=Téléporteur source introuvable. +30611=Ce n'est pas un téléporteur de maison. +30612=Vous devez cibler l'autre téléporteur. +30613=Ces téléporteurs sont de types différents et ne peuvent pas être liés. +30614=Les deux téléporteurs doivent être dans votre sac à dos pour les lier. +30615=Téléporteurs liés. +30616=Ciblez l'objet de recharge pour recharger le téléporteur. +30617=Cet objet doit être dans votre sac à dos. +30618=Le téléporteur de maison ne peut pas être chargé davantage. +30619=L'objet de recharge se désintègre en poussière en renforçant le téléporteur de maison. +30620=Cet objet doit être verrouillé dans une maison pour fonctionner. +30621=Cet objet doit être placé à l'intérieur d'une maison. +30622=Seuls le propriétaire et les copropriétaires de la maison peuvent utiliser ce téléporteur. +30623=Vous ne pouvez pas utiliser cet objet pour le moment. +30624=Ce téléporteur n'est pas lié. +30625=Le téléporteur de destination n'est pas correctement placé. +30626=Il n'y a plus de charges dans ce téléporteur. +30627=Ce téléporteur est entièrement chargé. +30628=Téléporteur introuvable. 30629=Ce téléporteur doit être connecté avant de pouvoir être renommé. +30630=Nom du téléporteur défini sur : %s } EOF diff --git a/data/dictionaries/dictionary.GER b/data/dictionaries/dictionary.GER index 8cec50d60..c200190d2 100644 --- a/data/dictionaries/dictionary.GER +++ b/data/dictionaries/dictionary.GER @@ -5693,5 +5693,37 @@ 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... +// [30600-30650] Hausteleporter +30600=Dieses Objekt muss sich in Ihrem Rucksack befinden, um es zu verknüpfen. +30601=Wählen Sie den anderen Teleporter in Ihrem Rucksack aus, um ihn zu verknüpfen. +30602=Dieser Teleporter ist vollständig aufgeladen. +30603=Wählen Sie ein Aufladeobjekt in Ihrem Rucksack aus, um den Teleporter aufzuladen. +30604=Sie können die Sicherheitseinstellungen dieses Teleporters nicht ändern. +30605=Sicherheitseinstellungen des Teleporters: %s +30606=Sie können diesen Teleporter nicht umbenennen. +30607=Dieser Teleporter muss verknüpft sein, bevor er umbenannt werden kann. +30608=Um die Teleporter zu verknüpfen, müssen sich beide in Ihrem Rucksack befinden. +30609=Wählen Sie den anderen Teleporter in Ihrem Rucksack aus, um ihn zu verknüpfen. +30610=Quell-Teleporter nicht gefunden. +30611=Das ist kein Hausteleporter. +30612=Sie müssen den anderen Teleporter auswählen. +30613=Diese Teleporter sind unterschiedlichen Typs und können nicht verknüpft werden. +30614=Beide Teleporter müssen sich in Ihrem Rucksack befinden, um sie zu verknüpfen. +30615=Teleporter verknüpft. +30616=Wählen Sie ein Aufladeobjekt aus, um den Teleporter aufzuladen. +30617=Dieses Objekt muss sich in Ihrem Rucksack befinden. +30618=Der Hausteleporter kann nicht weiter aufgeladen werden. +30619=Das Aufladeobjekt zerfällt zu Staub, während es den Hausteleporter verstärkt. +30620=Dieses Objekt muss in einem Haus platziert und gesichert werden, damit es funktioniert. +30621=Dieses Objekt muss in einem Haus platziert werden. +30622=Nur der Hausbesitzer und die Miteigentümer dürfen diesen Teleporter benutzen. +30623=Sie können das im Moment nicht verwenden. +30624=Dieser Teleporter ist nicht verknüpft. +30625=Der Ziel-Teleporter ist nicht richtig platziert. +30626=Dieser Teleporter hat keine Ladungen mehr. +30627=Dieser Teleporter ist vollständig aufgeladen. +30628=Teleporter nicht gefunden. +30629=Dieser Teleporter muss verknüpft werden, bevor er umbenannt werden kann. +30630=Teleportername festgelegt auf: %s } EOF diff --git a/data/dictionaries/dictionary.ITA b/data/dictionaries/dictionary.ITA index fded04dd5..a13e01d97 100644 --- a/data/dictionaries/dictionary.ITA +++ b/data/dictionaries/dictionary.ITA @@ -5693,5 +5693,37 @@ 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... +// [30600-30650] Teletrasporto per casa +30600=Questo oggetto deve essere nel tuo zaino per poterlo collegare. +30601=Seleziona l'altro teletrasporto nel tuo zaino per collegarli. +30602=Questo teletrasporto è completamente carico. +30603=Seleziona l'oggetto di ricarica nel tuo zaino per ricaricarlo. +30604=Non puoi modificare la sicurezza di questo teletrasporto. +30605=Sicurezza del teletrasporto impostata su: %s +30606=Non puoi rinominare questo teletrasporto. +30607=Questo teletrasporto deve essere collegato prima di poter essere rinominato. +30608=Per il collegamento, entrambi i teletrasporti devono essere nel tuo zaino. +30609=Seleziona l'altro teletrasporto nel tuo zaino per collegarli. +30610=Teletrasporto di origine non trovato. +30611=Questo non è un teletrasporto per casa. +30612=Devi selezionare l'altro teletrasporto. +30613=Questi teletrasporti sono di tipi diversi e non possono essere collegati. +30614=Entrambi i teletrasporti devono essere nel tuo zaino per il collegamento. +30615=Teletrasporti collegati. +30616=Seleziona l'oggetto di ricarica per ricaricare il teletrasporto. +30617=Questo oggetto deve essere nel tuo zaino. +30618=Il teletrasporto per casa non può essere caricato ulteriormente. +30619=L'oggetto di ricarica si sbriciola in polvere mentre potenzia il teletrasporto per casa. +30620=Questo deve essere posizionato all'interno di una casa per funzionare. +30621=Questo deve essere posizionato all'interno di una casa. +30622=Solo il proprietario e i comproprietari della casa possono usare questo teletrasporto. +30623=Non puoi usarlo in questo momento. +30624=Questo teletrasporto non è collegato. +30625=Il teletrasporto di destinazione non è posizionato correttamente. +30626=Non ci sono più cariche in questo teletrasporto. +30627=Questo teletrasporto è completamente carico. +30628=Teletrasporto non trovato. +30629=Questo teletrasporto deve essere collegato prima di poter essere rinominato. +30630=Nome del teletrasporto impostato su: %s } EOF diff --git a/data/dictionaries/dictionary.POL b/data/dictionaries/dictionary.POL index 50af51c7c..41a2db28c 100644 --- a/data/dictionaries/dictionary.POL +++ b/data/dictionaries/dictionary.POL @@ -5693,5 +5693,37 @@ 30003=Mistrz został pokonany! 30004=Otrzymałeś Zwoj mocy! 30005=Energia kapliczki słabnie z powodu braku pretendentów... +// [30600-30650] Teleporter domowy +30600=Aby połączyć teleportery, oba muszą znajdować się w twoim plecaku. +30601=Wybierz drugi teleporter w swoim plecaku, aby go połączyć. +30602=Ten teleporter jest w pełni naładowany. +30603=Wybierz przedmiot do ładowania w swoim plecaku, aby naładować teleporter. +30604=Nie możesz zmienić zabezpieczeń tego teleportera. +30605=Zabezpieczenia teleportera ustawione na: %s +30606=Nie możesz zmienić nazwy tego teleportera. +30607=Ten teleporter musi być połączony, zanim będzie można zmienić jego nazwę. +30608=Aby połączyć teleportery, oba muszą znajdować się w twoim plecaku. +30609=Wybierz drugi teleporter w swoim plecaku, aby go połączyć. +30610=Nie znaleziono teleportera źródłowego. +30611=To nie jest teleporter domowy. +30612=Musisz wybrać drugi teleporter. +30613=Te teleportery są różnych typów i nie można ich połączyć. +30614=Oba teleportery muszą znajdować się w twoim plecaku, aby je połączyć. +30615=Teleportery połączone. +30616=Wybierz przedmiot do ładowania, aby naładować teleporter. +30617=Ten przedmiot musi znajdować się w twoim plecaku. +30618=Teleportera domowego nie można już bardziej naładować. +30619=Przedmiot do ładowania rozpada się w pył, wzmacniając teleporter domowy. +30620=Aby działał, musi być umieszczony w domu. +30621=Musi być umieszczony wewnątrz domu. +30622=Tylko właściciel domu i współwłaściciele mogą korzystać z tego teleportera. +30623=Nie możesz tego teraz użyć. +30624=Ten teleporter nie jest połączony. +30625=Teleporter docelowy nie jest prawidłowo umieszczony. +30626=W tym teleporterze nie pozostały żadne ładunki. +30627=Ten teleporter jest w pełni naładowany. +30628=Nie znaleziono teleportera. +30629=Ten teleport musi zostać połączony, zanim będzie można zmienić jego nazwę. +30630=Nazwa teleportera została zmieniona na: %s } EOF diff --git a/data/dictionaries/dictionary.PTG b/data/dictionaries/dictionary.PTG index b6987987f..e4ee2f3b7 100644 --- a/data/dictionaries/dictionary.PTG +++ b/data/dictionaries/dictionary.PTG @@ -5693,5 +5693,37 @@ 30003=O Campeão caiu! 30004=Foste recompensado com um Pergaminho de Poder! 30005=A energia do santuário diminui sem desafiantes presentes... +// [30600-30650 ] Teletransportador de Casa +30600=Este item deve estar na sua mochila para o ligar. +30601=Selecione o outro teletransportador da sua mochila para o ligar. +30602=Este teletransportador está totalmente carregado. +30603=Selecione o item de recarga na sua mochila para o recarregar. +30604=Não pode alterar a segurança deste teletransportador. +30605=Segurança do teletransportador definida como: %s +30606=Não pode renomear este teletransportador. +30607=Este teletransportador necessita de ser ligado antes de poder ser renomeado. +30608=Para ligar, ambos os teletransportadores devem estar na sua mochila. +30609=Selecione o outro teletransportador da sua mochila para o ligar. +30610=Teletransportador de origem não encontrado. +30611=Este não é um teletransportador de casa. +30612=Deve selecionar o outro teletransportador. +30613=Estes teletransportadores são de tipos diferentes e não podem ser ligados. +30614=Ambos os teletransportadores têm de estar na sua mochila para serem ligados. +30615=Teletransportadores ligados. +30616=Selecione o item de recarga para recarregar o teletransportador. +30617=Este item deve estar na sua mochila. +30618=O Teletransportador de Casa não pode ser recarregado. +30619=O item de recarga desfaz-se em pó ao fortalecer o Teletransportador de Casa. +30620=Este item deve ser instalado no interior de uma casa para funcionar. +30621=Este item deve ser colocado dentro de uma casa. +30622=Apenas o dono da casa e os coproprietários podem utilizar este teletransportador. +30623=Não pode usar isso agora. +30624=Este teletransportador não está ligado. +30625=O teletransportador de destino não está corretamente posicionado. +30626=Não restam cargas neste teletransportador. +30627=Este teletransportador está totalmente carregado. +30628=Teletransportador não encontrado. +30629=Este teletransportador necessita de ser ligado antes de poder ser renomeado. +30630=Nome do teletransportador definido como: %s } EOF diff --git a/data/dictionaries/dictionary.SPA b/data/dictionaries/dictionary.SPA index 34f5560ab..2afaf2ec1 100644 --- a/data/dictionaries/dictionary.SPA +++ b/data/dictionaries/dictionary.SPA @@ -5693,5 +5693,37 @@ 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... +// [30600-30650] Teletransportador de casa +30600=Esto debe estar en tu mochila para poder vincularlo. +30601=Selecciona el otro teletransportador en tu mochila para vincularlos. +30602=Este teletransportador está completamente cargado. +30603=Selecciona el objeto de recarga en tu mochila para recargarlo. +30604=No puedes cambiar la seguridad de este teletransportador. +30605=Seguridad del teletransportador establecida en: %s +30606=No puedes cambiar el nombre de este teletransportador. +30607=Este teletransportador debe estar vinculado antes de poder cambiarle el nombre. +30608=Para vincularlos, ambos teletransportadores deben estar en tu mochila. +30609=Selecciona el otro teletransportador en tu mochila para vincularlos. +30610=Teletransportador de origen no encontrado. +30611=Eso no es un teletransportador de casa. +30612=Debes seleccionar el otro teletransportador. +30613=Estos teletransportadores son de tipos diferentes y no se pueden vincular. +30614=Ambos teletransportadores deben estar en tu mochila para vincularlos. +30615=Teletransportadores vinculados. +30616=Selecciona el objeto de recarga para recargar el teletransportador. +30617=Este objeto debe estar en tu mochila. +30618=El teletransportador de casa no se puede cargar más. +30619=El objeto de recarga se desintegra al fortalecer el teletransportador de casa. +30620=Esto debe estar asegurado en una casa para funcionar. +30621=Esto debe colocarse dentro de una casa. +30622=Solo el propietario y los copropietarios de la casa pueden usar este teletransportador. +30623=No puedes usar eso ahora mismo. +30624=Este teletransportador no está vinculado. +30625=El teletransportador de destino no está colocado correctamente. +30626=No quedan cargas en este teletransportador. +30627=Este teletransportador está completamente cargado. +30628=Teletransportador no encontrado. +30629=Este teletransportador debe estar vinculado antes de poder cambiarle el nombre. +30630=Nombre del teletransportador establecido a: %s } EOF diff --git a/data/dictionaries/dictionary.ZRO b/data/dictionaries/dictionary.ZRO index a49b7576a..217f9ce6b 100644 --- a/data/dictionaries/dictionary.ZRO +++ b/data/dictionaries/dictionary.ZRO @@ -5693,5 +5693,37 @@ 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... +// [30600-30650 ] House Teleporter +30600=This must be in your backpack to link it. +30601=Target the other teleporter in your backpack to link. +30602=This teleporter is fully charged. +30603=Target recharge item in your backpack to recharge +30604=You cannot change this teleporter's security. +30605=Teleporter security set to: %s +30606=You cannot rename this teleporter. +30607=This teleporter must be linked before it can be renamed. +30608=To link, both teleporters must be in your backpack. +30609=Target the other teleporter in your backpack to link. +30610=Source teleporter not found. +30611=That is not a house teleporter. +30612=You must target the other teleporter. +30613=These teleporters are different types and cannot be linked. +30614=Both teleporters must be in your backpack to link. +30615=Teleporters linked. +30616=Target recharge item to recharge the teleporter. +30617=This item must be in your backpack. +30618=The House Teleporter cannot be charged any further. +30619=The recharge item crumbles to dust as it strengthens the House Teleporter. +30620=This must be locked down in a house to function. +30621=This must be placed inside a house. +30622=Only the house owner and co-owners may use this teleporter. +30623=You cannot use that right now. +30624=This teleporter is not linked. +30625=The destination teleporter is not properly placed. +30626=There are no charges left in this teleporter. +30627=This teleporter is fully charged. +30628=Teleporter not found. +30629=This teleporter must be linked before it can be renamed. +30630=Teleporter name set to: %s } EOF diff --git a/data/js/item/houseteleporter.js b/data/js/item/houseteleporter.js new file mode 100644 index 000000000..bc9572894 --- /dev/null +++ b/data/js/item/houseteleporter.js @@ -0,0 +1,807 @@ +/// +// @ts-check + +const chargeItemIDReq = 0x1f60; +const chargeItemSectionIDReq = "0x1f60"; +const chargeAmount = 5; +const chargeMax = 1000; +const teleporterIDReq = [0x40BB, 0x574A]; +const teleporterSectionIDReq = "house_teleporter"; +const coOwnHousesOnSameAccount = GetServerSetting( "CoOwnHousesOnSameAccount" ); + +/** @type { ( item: Item | BaseObject ) => boolean } */ +function IsTeleporterItem( item ) +{ + if( !item || !item.isItem ) + return false; + + if( item.sectionID == teleporterSectionIDReq ) + return true; + + for( var i = 0; i < teleporterIDReq.length; i++ ) + { + if( item.id == teleporterIDReq[i] ) + return true; + } + return false; +} + +/** @type { ( teleItem: Item ) => Item | null } */ +function GetLinkedTeleporter( teleItem ) +{ + if( !IsTeleporterItem( teleItem )) + return null; + + var linkSer = teleItem.GetTag( "LinkSer" ); + if( linkSer <= 0 ) + return null; + + var other = CalcItemFromSer( linkSer ); + if( !IsTeleporterItem( other )) + return null; + + return other; +} + +/** @type { ( teleItem: Item ) => number } */ +function GetSharedCharges( teleItem ) +{ + if( !IsTeleporterItem( teleItem )) + return 0; + + var cur = teleItem.GetTag( "Charges" ); + if( cur < 0 ) + cur = 0; + + var other = GetLinkedTeleporter( teleItem ); + if( IsTeleporterItem( other )) + { + var otherCur = other.GetTag( "Charges" ); + if( otherCur < 0 ) + otherCur = 0; + + if( otherCur > cur ) + cur = otherCur; + } + + if( cur > chargeMax ) + cur = chargeMax; + + return cur; +} + +/** @type { ( teleItem: Item, newValue: number ) => void } */ +function SetSharedCharges( teleItem, newValue ) +{ + if( !IsTeleporterItem( teleItem )) + return; + + if( newValue < 0 ) + newValue = 0; + + if( newValue > chargeMax ) + newValue = chargeMax; + + teleItem.SetTag( "Charges", newValue ); + teleItem.Refresh(); + + var other = GetLinkedTeleporter( teleItem ); + if( IsTeleporterItem( other )) + { + other.SetTag( "Charges", newValue ); + other.Refresh(); + } +} + +/** @type { ( teleporterA: Item, teleporterB: Item ) => void } */ +function SyncLinkedChargesOnLink( teleporterA, teleporterB ) +{ + if( !IsTeleporterItem( teleporterA ) || !IsTeleporterItem( teleporterB )) + return; + + var aCharge = teleporterA.GetTag( "Charges" ); + var bCharge = teleporterB.GetTag( "Charges" ); + + if( aCharge < 0 ) + aCharge = 0; + if( bCharge < 0 ) + bCharge = 0; + + var shared = aCharge + bCharge; + if( shared > chargeMax ) + shared = chargeMax; + + teleporterA.SetTag( "Charges", shared ); + teleporterB.SetTag( "Charges", shared ); + teleporterA.Refresh(); + teleporterB.Refresh(); +} + +/** @type { ( mode: number ) => string } */ +function SecurityName( mode ) +{ + if( mode == 1 ) + return "Friends"; + if( mode == 2 ) + return "Anyone"; + return "Owner/Co-Owners"; +} + +/** @type { ( pChar: Character, teleItem: Item ) => boolean } */ +function CanManageTeleporter( pChar, teleItem ) +{ + if( !ValidateObject( pChar ) || !ValidateObject( teleItem )) + return false; + + if( pChar.isGM ) + return true; + + var multiHouse = teleItem.multi; + if( !ValidateObject( multiHouse )) + return false; + + if( multiHouse.IsOwner( pChar )) + return true; + + if( multiHouse.IsOnOwnerList( pChar )) + return true; + + if( coOwnHousesOnSameAccount && ValidateObject( multiHouse.owner )) + { + if( multiHouse.owner.accountNum == pChar.accountNum ) + return true; + } + + return false; +} + +/** @type { ( pChar: Character, teleItem: Item ) => boolean } */ +function CanUseHouseTeleporter( pChar, teleItem ) +{ + if( !ValidateObject( pChar ) || !ValidateObject( teleItem )) + return false; + + if( pChar.isGM ) + return true; + + var multiHouse = teleItem.multi; + if( !ValidateObject( multiHouse )) + return false; + + var mode = teleItem.GetTag( "Security" ); + if( mode != 0 && mode != 1 && mode != 2 ) + mode = 0; + + if( multiHouse.IsOwner( pChar )) + return true; + + if( multiHouse.IsOnOwnerList( pChar )) + return true; + + if( coOwnHousesOnSameAccount && ValidateObject( multiHouse.owner )) + { + if( multiHouse.owner.accountNum == pChar.accountNum ) + return true; + } + + if( mode == 1 ) + { + if( multiHouse.IsOnFriendList( pChar )) + return true; + return false; + } + + if( mode == 2 ) + return true; + + return false; +} + +/** @type { ( tSock: Socket, baseObj: BaseObject ) => boolean } */ +function onContextMenuRequest( socket, targObj ) +{ + var pUser = socket.currentChar; + if( !ValidateObject( pUser )) + return true; + + if( !IsTeleporterItem( targObj )) + return true; + + var inPack = false; + if( ValidateObject( pUser.pack )) + { + var root0 = FindRootContainer( targObj, 0 ); + inPack = ( ValidateObject( root0 ) && root0.isItem && root0.serial == pUser.pack.serial ); + } + + var canShowSecurity = false; + if( targObj.movable == 3 && ValidateObject( targObj.multi ) && CanManageTeleporter( pUser, targObj )) + canShowSecurity = true; + + var canShowRename = false; + if( targObj.movable == 3 && ValidateObject( targObj.multi ) && CanManageTeleporter( pUser, targObj )) + { + var linkSerTmp = targObj.GetTag( "LinkSer" ); + if( linkSerTmp > 0 ) + { + var otherTmp = CalcItemFromSer( linkSerTmp ); + if( IsTeleporterItem( otherTmp ) && otherTmp.movable == 3 ) + canShowRename = true; + } + } + + var numEntries = 1; + if( inPack ) + numEntries++; + + if( targObj.id == 0x574A && targObj.GetTag( "chargeable" ) == 1 ) + numEntries++; + + if( canShowSecurity ) + numEntries++; + + if( canShowRename ) + numEntries++; + + var offset = 12; + var toSend = new Packet(); + var packetLen = 12 + ( numEntries * 8 ); + + toSend.ReserveSize( packetLen ); + toSend.WriteByte( 0, 0xBF ); + toSend.WriteShort( 1, packetLen ); + toSend.WriteShort( 3, 0x14 ); + toSend.WriteShort( 5, 0x0001 ); + toSend.WriteLong( 7, targObj.serial ); + toSend.WriteByte( 11, numEntries ); + + toSend.WriteShort( offset, 0x0101 ); + toSend.WriteShort( offset += 2, 2140 ); + toSend.WriteShort( offset += 2, 0x0020 ); + toSend.WriteShort( offset += 2, 0x03E0 ); + offset += 2; + + if( inPack ) + { + toSend.WriteShort( offset, 0x0102 ); + toSend.WriteShort( offset += 2, 5119 ); + toSend.WriteShort( offset += 2, 0x0020 ); + toSend.WriteShort( offset += 2, 0x03E0 ); + offset += 2; + } + + if( targObj.id == 0x574A && targObj.GetTag( "chargeable" ) == 1 ) + { + toSend.WriteShort( offset, 0x0103 ); + toSend.WriteShort( offset += 2, 5042 ); + toSend.WriteShort( offset += 2, 0x0020 ); + toSend.WriteShort( offset += 2, 0x03E0 ); + offset += 2; + } + + if( canShowSecurity ) + { + toSend.WriteShort( offset, 0x0104 ); + toSend.WriteShort( offset += 2, 6203 ); + toSend.WriteShort( offset += 2, 0x0020 ); + toSend.WriteShort( offset += 2, 0x03E0 ); + offset += 2; + } + + if( canShowRename ) + { + toSend.WriteShort( offset, 0x0105 ); + toSend.WriteShort( offset += 2, 404 ); + toSend.WriteShort( offset += 2, 0x0020 ); + toSend.WriteShort( offset += 2, 0x03E0 ); + offset += 2; + } + + socket.Send( toSend ); + toSend.Free(); + + return false; +} + +/** @type { ( tSock: Socket, baseObj: BaseObject, popupEntry: number ) => boolean } */ +function onContextMenuSelect( socket, targObj, popupEntry ) +{ + var pUser = socket.currentChar; + if( !ValidateObject( pUser )) + return true; + + if( !IsTeleporterItem( targObj )) + return true; + + if( popupEntry == 0x0101 ) + { + var linkSer = targObj.GetTag( "LinkSer" ); + var linked = false; + if( linkSer > 0 ) + { + var other = CalcItemFromSer( linkSer ); + if( IsTeleporterItem( other )) + linked = true; + } + + if( targObj.id == 0x574A && targObj.GetTag( "chargeable" ) == 1 ) + { + var charge = GetSharedCharges( targObj ); + socket.SysMessage( "Teleporter: " + ( linked ? "Linked" : "Unlinked" ) + " | Charges: " + charge + "/" + chargeMax ); + } + else + { + socket.SysMessage( "Teleporter: " + ( linked ? "Linked" : "Unlinked" )); + } + return false; + } + + if( popupEntry == 0x0102 ) + { + var inPackLink = false; + if( ValidateObject( pUser.pack )) + { + var root1 = FindRootContainer( targObj, 0 ); + inPackLink = ( ValidateObject( root1 ) && root1.isItem && root1.serial == pUser.pack.serial ); + } + + if( !inPackLink ) + { + socket.SysMessage( GetDictionaryEntry( 30600, socket.language )); + return false; + } + + pUser.SetTempTag( "LinkSrcSer", targObj.serial ); + socket.CustomTarget( 0, GetDictionaryEntry( 30601, socket.language )); // Target the other teleporter in your backpack to link. + targObj.Refresh(); + return false; + } + + if( popupEntry == 0x0103 ) + { + if( targObj.GetTag( "chargeable" ) != 1 ) + return false; + + var cur = GetSharedCharges( targObj ); + if( cur >= chargeMax ) + { + socket.SysMessage( GetDictionaryEntry( 30602, socket.language )); + return false; + } + + pUser.SetTempTag( "RechargeSer", targObj.serial ); + socket.CustomTarget( 1, GetDictionaryEntry( 30603, socket.language )); // Target recharge item in your backpack to recharge. + targObj.Refresh(); + return false; + } + + if( popupEntry == 0x0104 ) + { + if( !( targObj.movable == 3 && ValidateObject( targObj.multi ) && CanManageTeleporter( pUser, targObj ))) + { + socket.SysMessage( GetDictionaryEntry( 30604, socket.language )); // You cannot change this teleporter's security + return false; + } + + var curMode = targObj.GetTag( "Security" ); + if( curMode != 0 && curMode != 1 && curMode != 2 ) + curMode = 0; + + var nextMode = curMode + 1; + if( nextMode > 2 ) + nextMode = 0; + + targObj.SetTag( "Security", nextMode ); + socket.SysMessage( "Teleporter security set to: " + SecurityName( nextMode )); // Teleporter security set to: %s + targObj.Refresh(); + return false; + } + + if( popupEntry == 0x0105 ) + { + if( !( targObj.movable == 3 && ValidateObject( targObj.multi ) && CanManageTeleporter( pUser, targObj ))) + { + socket.SysMessage( GetDictionaryEntry( 30606, socket.language )); // You cannot rename this teleporter. + return false; + } + + var linkSer2 = targObj.GetTag( "LinkSer" ); + if( linkSer2 <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 30607, socket.language )); // This teleporter must be linked before it can be renamed. + return false; + } + + var other2 = CalcItemFromSer( linkSer2 ); + if( !IsTeleporterItem( other2 )) + { + socket.SysMessage( GetDictionaryEntry( 30607, socket.language )); // This teleporter must be linked before it can be renamed. + return false; + } + + pUser.SetTempTag( "RenameSer", targObj.serial ); + pUser.SpeechInput( 1, targObj ); + return false; + } + + return false; +} + +/** @type { ( user: Character, iUsing: Item ) => boolean } */ +function onUseChecked( pUser, iUsed ) +{ + var pSocket = pUser.socket; + if( pSocket == null ) + return false; + + if( !IsTeleporterItem( iUsed )) + return false; + + var inPackUse = false; + if( ValidateObject( pUser.pack )) + { + var root2 = FindRootContainer( iUsed, 0 ); + inPackUse = ( ValidateObject( root2 ) && root2.isItem && root2.serial == pUser.pack.serial ); + } + + if( !inPackUse ) + { + pSocket.SysMessage( GetDictionaryEntry( 30608, pSocket.language )); // To link, both teleporters must be in your backpack. + return false; + } + + pUser.SetTempTag( "LinkSrcSer", iUsed.serial ); + pSocket.CustomTarget( 0, GetDictionaryEntry( 30609, pSocket.language )); // Target the other teleporter in your backpack to link. + return false; +} + +/** @type { ( tSock: Socket, target: Character | Item | null ) => void } */ +function onCallback0( socket, target ) +{ + var pUser = socket.currentChar; + if( !ValidateObject( pUser )) + return; + + if( socket.GetWord( 1 )) + return; + + var srcSer = pUser.GetTempTag( "LinkSrcSer" ); + var teleporterA = CalcItemFromSer( srcSer ); + var teleporterB = target; + + if( !IsTeleporterItem( teleporterA )) + { + socket.SysMessage( GetDictionaryEntry( 30610, socket.language )); // Source teleporter not found. + return; + } + if( !IsTeleporterItem( teleporterB )) + { + socket.SysMessage( GetDictionaryEntry( 30611, socket.language )); // That is not a house teleporter. + return; + } + if( teleporterA.serial == teleporterB.serial ) + { + socket.SysMessage( GetDictionaryEntry( 30612, socket.language )); // You must target the other teleporter. + return; + } + if( teleporterA.id != teleporterB.id ) + { + socket.SysMessage( GetDictionaryEntry( 30613, socket.language )); // These teleporters are different types and cannot be linked. + return; + } + + var aInPack = false; + var bInPack = false; + + if( ValidateObject( pUser.pack )) + { + var rootA = FindRootContainer( teleporterA, 0 ); + var rootB = FindRootContainer( teleporterB, 0 ); + + aInPack = ( ValidateObject( rootA ) && rootA.isItem && rootA.serial == pUser.pack.serial ); + bInPack = ( ValidateObject( rootB ) && rootB.isItem && rootB.serial == pUser.pack.serial ); + } + + if( !aInPack || !bInPack ) + { + socket.SysMessage( GetDictionaryEntry( 30614, socket.language )); // Both teleporters must be in your backpack to link. + return; + } + + UnlinkOther( teleporterA, teleporterB.serial ); + UnlinkOther( teleporterB, teleporterA.serial ); + + teleporterA.SetTag( "LinkSer", teleporterB.serial ); + teleporterB.SetTag( "LinkSer", teleporterA.serial ); + + // Make both share the same charge pool immediately + if( teleporterA.GetTag( "chargeable" ) == 1 && teleporterB.GetTag( "chargeable" ) == 1 ) + SyncLinkedChargesOnLink( teleporterA, teleporterB ); + + socket.SysMessage( GetDictionaryEntry( 30615, socket.language )); // Teleporters linked. +} + +/** @type { ( tSock: Socket, target: Character | Item | null ) => void } */ +function onCallback1( socket, target ) +{ + var pUser = socket.currentChar; + if( !ValidateObject( pUser )) + return; + + if( socket.GetWord( 1 )) + return; + + var teleporterSerial = pUser.GetTempTag( "RechargeSer" ); + var teleporter = CalcItemFromSer( teleporterSerial ); + if( !ValidateObject( teleporter ) || !teleporter.isItem || teleporter.GetTag( "chargeable" ) != 1 ) + return; + + var scroll = target; + if( !( ValidateObject( scroll ) && scroll.isItem && ( scroll.id == chargeItemIDReq || scroll.sectionID == chargeItemSectionIDReq ))) + { + socket.SysMessage( GetDictionaryEntry( 30616, socket.language )); + return; + } + + var scrollInPack = false; + if( ValidateObject( pUser.pack )) + { + var root3 = FindRootContainer( scroll, 0 ); + scrollInPack = ( ValidateObject( root3 ) && root3.isItem && root3.serial == pUser.pack.serial ); + } + + if( !scrollInPack ) + { + socket.SysMessage( GetDictionaryEntry( 30617, socket.language ));// This item must be in your backpack. + return; + } + + var cur = GetSharedCharges( teleporter ); + var stackAmt = scroll.amount; + if( stackAmt < 1 ) + stackAmt = 1; + + var remaining = chargeMax - cur; + if( remaining <= 0 ) + { + socket.SysMessage( GetDictionaryEntry( 30618, socket.language ));// The House Teleporter cannot be charged any further. + return; + } + + var needScrolls = Math.ceil( remaining / chargeAmount ); + var useScrolls = needScrolls; + + if( useScrolls > stackAmt ) + useScrolls = stackAmt; + if( useScrolls < 1 ) + useScrolls = 1; + + if( stackAmt > useScrolls ) + scroll.amount = stackAmt - useScrolls; + else + scroll.Delete(); + + cur += ( useScrolls * chargeAmount ); + if( cur > chargeMax ) + cur = chargeMax; + + SetSharedCharges( teleporter, cur ); + + socket.SysMessage( GetDictionaryEntry( 30619, socket.language ));// The recharge item crumbles to dust as it strengthens the House Teleporter. +} + +/** @type { ( tile: Item, keepSer: number ) => void } */ +function UnlinkOther( tile, keepSer ) +{ + var old = tile.GetTag( "LinkSer" ); + tile.SetTag( "LinkSer", null ); + + if( old > 0 && old != keepSer ) + { + var oldtele = CalcItemFromSer( old ); + if( IsTeleporterItem( oldtele )) + { + oldtele.SetTag( "LinkSer", null ); + + if( oldtele.GetTag( "chargeable" ) == 1 ) + { + oldtele.SetTag( "Charges", 0 ); + oldtele.Refresh(); + } + } + } +} + +/** @type { ( targSock: Socket, objColliding: Character, objCollideWith: BaseObject ) => boolean } */ +function onCollide( trgSock, pColliding, objCollidedWith ) +{ + if( !ValidateObject( pColliding ) || !pColliding.isChar ) + return false; + + if( !IsTeleporterItem( objCollidedWith )) + return false; + + if( trgSock == null ) + return false; + + if( objCollidedWith.movable != 3 ) + { + trgSock.SysMessage( GetDictionaryEntry( 30620, trgSock.language )); // This must be locked down in a house to function. + return false; + } + + var iMulti = FindMulti( objCollidedWith.x, objCollidedWith.y, objCollidedWith.z, objCollidedWith.worldnumber, objCollidedWith.instanceID ); + var insideHouse = ( ValidateObject( iMulti ) && iMulti.IsInMulti( objCollidedWith )); + + if( !insideHouse ) + { + trgSock.SysMessage( GetDictionaryEntry( 30621, trgSock.language )); // This must be placed inside a house. + return false; + } + + if( !CanUseHouseTeleporter( pColliding, objCollidedWith )) + { + trgSock.SysMessage( GetDictionaryEntry( 30622, trgSock.language )); // Only the house owner and co-owners may use this teleporter. + return false; + } + + if( pColliding.dead || pColliding.criminal ) + { + trgSock.SysMessage( GetDictionaryEntry( 30623, trgSock.language )); // You cannot use that right now. + return false; + } + + var linkSer = objCollidedWith.GetTag( "LinkSer" ); + if( linkSer <= 0 ) + { + trgSock.SysMessage( GetDictionaryEntry( 30624, trgSock.language )); // This teleporter is not linked. + return false; + } + + var other = CalcItemFromSer( linkSer ); + if( !IsTeleporterItem( other )) + { + trgSock.SysMessage( GetDictionaryEntry( 30624, trgSock.language )); // This teleporter is not linked. + return false; + } + + if( other.movable != 3 ) + { + trgSock.SysMessage( GetDictionaryEntry( 30625, trgSock.language )); // The destination teleporter is not properly placed. + return false; + } + + var destMulti = FindMulti( other.x, other.y, other.z, other.worldnumber, other.instanceID ); + var destInsideHouse = ( ValidateObject( destMulti ) && destMulti.IsInMulti( other )); + if( !destInsideHouse ) + { + trgSock.SysMessage( GetDictionaryEntry( 30625, trgSock.language ));// The destination teleporter is not properly placed. + return false; + } + + if( objCollidedWith.GetTag( "chargeable" ) == 1 ) + { + var charge = GetSharedCharges( objCollidedWith ); + if( charge <= 0 ) + { + trgSock.SysMessage( GetDictionaryEntry( 30626, trgSock.language )); // There are no charges left in this teleporter. + return false; + } + + SetSharedCharges( objCollidedWith, charge - 1 ); + } + + // Collect nearby following pets before teleporting player + var petsToMove = []; + var followerList = pColliding.GetFollowerList(); + for( var i = 0; i < followerList.length; i++ ) + { + var tempFollower = followerList[i]; + if( ValidateObject( tempFollower ) && tempFollower.wandertype == 1 && tempFollower.InRange( pColliding, 24 )) + petsToMove.push( tempFollower ); + } + + pColliding.Teleport( other.x, other.y, other.z, other.worldnumber, other.instanceID ); + + for( var j = 0; j < petsToMove.length; j++ ) + { + if( ValidateObject( petsToMove[j] )) + { + petsToMove[j].Teleport( other.x, other.y, other.z, other.worldnumber, other.instanceID ); + petsToMove[j].Follow( pColliding ); + } + } + + return false; +} + +/** @type { ( myChar: Character, myItem: Item, mySpeech: string, mySpeechId: number ) => void } */ +function onSpeechInput( pUser, targObj, pSpeech, pSpeechID ) +{ + var pSocket = pUser.socket; + if( !pSocket ) + return; + + if( pSpeechID != 1 ) + return; + + if( pSpeech == null ) + return; + + pSpeech = ( "" + pSpeech ).replace(/^\s+|\s+$/g, "" ); + if( pSpeech.length <= 0 ) + { + pSocket.SysMessage( GetDictionaryEntry( 9270, pSocket.language ));// too short / none entered + return; + } + if( pSpeech.length > 60 ) + { + pSocket.SysMessage( GetDictionaryEntry( 9271, pSocket.language ));// too long (we'll reuse) + return; + } + + var srcSer = pUser.GetTempTag( "RenameSer" ); + var teleA = CalcItemFromSer( srcSer ); + if( !IsTeleporterItem( teleA )) + { + pSocket.SysMessage( GetDictionaryEntry( 30628, pSocket.language )); // Teleporter not found. + return; + } + + var linkSer = teleA.GetTag( "LinkSer" ); + if( linkSer <= 0 ) + { + pSocket.SysMessage( GetDictionaryEntry( 30629, pSocket.language ));// This teleporter must be linked before it can be renamed. + return; + } + + var teleB = CalcItemFromSer( linkSer ); + if( !IsTeleporterItem( teleB )) + { + pSocket.SysMessage( GetDictionaryEntry( 30629, pSocket.language ));// This teleporter must be linked before it can be renamed. + return; + } + + teleA.name = pSpeech; + teleB.name = pSpeech; + + teleA.Refresh(); + teleB.Refresh(); + + pSocket.SysMessage( "Teleporter name set to: " + pSpeech ); +} + +/** @type { ( myObj: BaseObject, pSocket: Socket ) => string } */ +function onTooltip( myObj, pSocket ) +{ + if( !ValidateObject( myObj ) || !myObj.isItem ) + return ""; + + if( !IsTeleporterItem( myObj )) + return ""; + + var parts = []; + var secMode = myObj.GetTag( "Security" ); + if( secMode != 0 && secMode != 1 && secMode != 2 ) + secMode = 0; + + parts.push( "Security: " + SecurityName( secMode )); + + if( myObj.id == 0x574A && myObj.GetTag( "chargeable" ) == 1 ) + { + var charge = GetSharedCharges( myObj ); + parts.push( "Charges: " + charge + "/" + chargeMax ); + } + + var linkSer = myObj.GetTag( "LinkSer" ); + var linked = false; + if( linkSer > 0 ) + { + var other = CalcItemFromSer( linkSer ); + if( IsTeleporterItem( other )) + linked = true; + } + parts.push( "Link: " + ( linked ? "Linked" : "Unlinked" )); + + return parts.join( "
" ); +} \ No newline at end of file diff --git a/data/js/jse_fileassociations.scp b/data/js/jse_fileassociations.scp index 5b993348f..2f86dfe54 100644 --- a/data/js/jse_fileassociations.scp +++ b/data/js/jse_fileassociations.scp @@ -327,6 +327,7 @@ 5063=item/recipescroll.js 5064=item/runicatlas.js 5070=item/dawns_music_box.js +5080=item/houseteleporter.js 5300=item/etherealstatuettes.js 5301=npc/pets/dismountetherealmount.js