diff --git a/docs/classes/Player.md b/docs/classes/Player.md index 76a7c1b..3d13336 100644 --- a/docs/classes/Player.md +++ b/docs/classes/Player.md @@ -974,3 +974,7914 @@ In this script: With this script in place, the server will automatically reset the weekly honor status for all online players every Sunday at midnight, providing a consistent and automated way to manage player progress in a custom PvP system. +## CompleteQuest +This method allows you to complete a quest for the player by providing the quest entry ID. It will attempt to satisfy all quest requirements and complete the quest if the player has it in their quest log. + +### Parameters +* entry: number - The entry ID of the quest to be completed. + +### Example Usage +Here's an example of how to use the `CompleteQuest` method to automatically complete a specific quest when the player reaches a certain level: + +```typescript +const QUEST_ENTRY_ID = 1234; // Replace with the actual quest entry ID +const REQUIRED_LEVEL = 20; // Replace with the desired level requirement + +const OnLevelUp: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + const newLevel = player.GetLevel(); + + if (oldLevel < REQUIRED_LEVEL && newLevel >= REQUIRED_LEVEL) { + if (player.HasQuest(QUEST_ENTRY_ID)) { + player.CompleteQuest(QUEST_ENTRY_ID); + player.SendBroadcastMessage("Congratulations! You have automatically completed the quest."); + } else { + player.SendBroadcastMessage("You have reached the required level, but you don't have the quest."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => OnLevelUp(...args)); +``` + +In this example: +1. We define the `QUEST_ENTRY_ID` constant with the entry ID of the quest we want to complete automatically. +2. We define the `REQUIRED_LEVEL` constant with the desired level requirement for completing the quest. +3. We register the `OnLevelUp` event handler for the `PLAYER_EVENT_ON_LEVEL_CHANGE` event. +4. Inside the event handler, we retrieve the player's new level using `player.GetLevel()`. +5. We check if the player's old level is below the required level and the new level is greater than or equal to the required level. +6. If the level requirement is met, we check if the player has the quest using `player.HasQuest(QUEST_ENTRY_ID)`. +7. If the player has the quest, we call `player.CompleteQuest(QUEST_ENTRY_ID)` to complete the quest automatically. +8. We send a broadcast message to the player informing them about the automatic quest completion. +9. If the player doesn't have the quest, we send a different message indicating that they have reached the required level but don't have the quest. + +This script ensures that when the player reaches the specified level (`REQUIRED_LEVEL`), if they have the quest with the given entry ID (`QUEST_ENTRY_ID`), it will be automatically completed. The player will receive a broadcast message confirming the completion or informing them if they don't have the quest. + +Note: Make sure to replace `QUEST_ENTRY_ID` with the actual entry ID of the quest you want to complete, and adjust the `REQUIRED_LEVEL` according to your desired level requirement. + +## DurabilityLoss +Damages the specified [Item](./item.md) by reducing its durability by a percentage. If the item's durability reaches 0, it will be destroyed. + +### Parameters +* item: [Item](./item.md) - The item to damage. +* percent: number - The percentage of durability to remove from the item (0-100). + +### Example Usage +Damage equipped items on death based on item quality: +```typescript +const onPlayerDeath: player_event_on_death = (event: number, player: Player, killer: Unit) => { + const items = player.GetEquippedItems(); + for (const item of items) { + switch (item.GetQuality()) { + case ItemQuality.ITEM_QUALITY_POOR: + case ItemQuality.ITEM_QUALITY_NORMAL: + player.DurabilityLoss(item, 5); + break; + case ItemQuality.ITEM_QUALITY_UNCOMMON: + player.DurabilityLoss(item, 7); + break; + case ItemQuality.ITEM_QUALITY_RARE: + player.DurabilityLoss(item, 10); + break; + case ItemQuality.ITEM_QUALITY_EPIC: + player.DurabilityLoss(item, 12); + break; + case ItemQuality.ITEM_QUALITY_LEGENDARY: + case ItemQuality.ITEM_QUALITY_ARTIFACT: + player.DurabilityLoss(item, 15); + break; + default: + break; + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => onPlayerDeath(...args)); +``` + +In this example, when a player dies, their equipped items will lose durability based on the item's quality. Poor and normal quality items will lose 5% durability, uncommon items will lose 7%, rare items will lose 10%, epic items will lose 12%, and legendary and artifact items will lose 15% durability. + +This script adds an extra layer of item management for players, encouraging them to repair their gear regularly and be more cautious in combat to avoid losing valuable items due to durability loss. + +## DurabilityLossAll +Damages all equipped items on the player by a percentage amount. Optionally, you can specify to damage items in the player's inventory as well. + +### Parameters +* percent: number - The percentage of durability to be lost on each item. Value must be between 0 and 100. +* inventory?: boolean - (Optional) If set to true, items in the player's inventory will also lose durability. Default is false. + +### Example Usage +In this example, we create a script that damages all equipped items and items in the inventory by 20% when the player dies in combat. + +```typescript +const onPlayerDeath: player_event_on_death = (event: PlayerEvents, player: Player, killer: Unit) => { + const DURABILITY_LOSS_PERCENT = 20; + const DAMAGE_INVENTORY = true; + + // Check if the player was killed by another player or creature + if (killer && (killer.IsPlayer() || killer.IsCreature())) { + // Apply durability loss to all equipped items and items in the inventory + player.DurabilityLossAll(DURABILITY_LOSS_PERCENT, DAMAGE_INVENTORY); + + // Send a message to the player + player.SendBroadcastMessage(`You have lost ${DURABILITY_LOSS_PERCENT}% durability on all your items!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => onPlayerDeath(...args)); +``` + +In this script: +1. We define the percentage of durability loss (`DURABILITY_LOSS_PERCENT`) as 20%. +2. We set `DAMAGE_INVENTORY` to `true` to indicate that we want to damage items in the player's inventory as well. +3. When the player dies, we check if the killer is either a player or a creature using the `IsPlayer()` and `IsCreature()` methods. +4. If the killer is valid, we call the `DurabilityLossAll()` method on the player, passing in the `DURABILITY_LOSS_PERCENT` and `DAMAGE_INVENTORY` values. +5. Finally, we send a broadcast message to the player informing them about the durability loss on their items. + +This script ensures that when a player dies in combat against another player or a creature, they lose 20% durability on all their equipped items and items in their inventory. The player is also notified about the durability loss through a broadcast message. + +Note: Make sure to adjust the `DURABILITY_LOSS_PERCENT` value according to your desired gameplay balance. A higher percentage will result in more significant durability loss, while a lower percentage will be less punishing. + +## DurabilityPointLossForEquipSlot +This method sets the durability loss for an equipped item in a specific slot. The durability loss is applied when the player takes damage or dies. This can be used to adjust the rate at which equipped items lose durability in certain situations. + +### Parameters +* slot: number - The equipment slot index. Use the EquipmentSlots enum for valid slot indices. + +### Example Usage +Increase weapon durability loss in a challenging area: +```typescript +const CHALLENGING_AREA_MAP_ID = 123; +const CHALLENGING_AREA_DURABILITY_LOSS_MULTIPLIER = 2; + +const updateDurabilityLoss: player_event_on_update = (event: number, player: Player, diff: number) => { + if (player.GetMapId() === CHALLENGING_AREA_MAP_ID) { + const weaponSlot = EquipmentSlots.EQUIPMENT_SLOT_MAINHAND; + const offhandSlot = EquipmentSlots.EQUIPMENT_SLOT_OFFHAND; + + const weaponItem = player.GetItemByPos(255, weaponSlot); + const offhandItem = player.GetItemByPos(255, offhandSlot); + + if (weaponItem) { + const baseDurabilityLoss = player.GetUInt32Value(UnitFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS + weaponSlot); + const increasedDurabilityLoss = baseDurabilityLoss * CHALLENGING_AREA_DURABILITY_LOSS_MULTIPLIER; + player.DurabilityPointLossForEquipSlot(weaponSlot); + player.SetUInt32Value(UnitFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS + weaponSlot, increasedDurabilityLoss); + } + + if (offhandItem) { + const baseDurabilityLoss = player.GetUInt32Value(UnitFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS + offhandSlot); + const increasedDurabilityLoss = baseDurabilityLoss * CHALLENGING_AREA_DURABILITY_LOSS_MULTIPLIER; + player.DurabilityPointLossForEquipSlot(offhandSlot); + player.SetUInt32Value(UnitFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS + offhandSlot, increasedDurabilityLoss); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => updateDurabilityLoss(...args)); +``` +In this example: +1. We define a challenging area map ID and a durability loss multiplier. +2. In the `player_event_on_update` event, we check if the player is in the challenging area. +3. If the player is in the challenging area, we get the player's main-hand and off-hand weapon items. +4. For each equipped weapon, we: + - Get the base durability loss value from the player's fields. + - Calculate the increased durability loss by multiplying the base value with the multiplier. + - Apply the durability point loss for the corresponding equipment slot using `DurabilityPointLossForEquipSlot`. + - Set the increased durability loss value back to the player's fields. + +This script will cause the player's weapons to lose durability at an increased rate while in the challenging area, making item maintenance more important and adding an extra layer of difficulty to the area. + +## DurabilityPointsLoss +This method allows you to set the durability loss for a specific item equipped by the player. The durability loss is applied instantly, reducing the item's current durability by the specified number of points. + +### Parameters +* item: [Item](./item.md) - The item to apply the durability loss to. The item must be equipped by the player. +* points: number - The number of durability points to subtract from the item's current durability. + +### Example Usage +In this example, we create a script that applies a durability loss to a player's equipped weapon whenever they enter combat with a creature that has a specific entry ID. + +```typescript +const CREATURE_ENTRY_ID = 1234; // Replace with the desired creature entry ID +const DURABILITY_LOSS_POINTS = 5; + +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + if (enemy.IsCreature() && enemy.ToCreature().GetEntry() === CREATURE_ENTRY_ID) { + const mainHandItem = player.GetItemByPos(InventorySlots.INVENTORY_SLOT_BAG_0, EquipmentSlots.EQUIPMENT_SLOT_MAINHAND); + if (mainHandItem) { + player.DurabilityPointsLoss(mainHandItem, DURABILITY_LOSS_POINTS); + player.SendBroadcastMessage(`Your weapon loses ${DURABILITY_LOSS_POINTS} durability points!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script: +1. We define constants for the creature entry ID and the number of durability points to subtract. +2. We register a player event handler for the `PLAYER_EVENT_ON_ENTER_COMBAT` event using `RegisterPlayerEvent`. +3. Inside the event handler, we check if the enemy is a creature and if its entry ID matches the desired creature entry ID. +4. If the conditions are met, we retrieve the player's main hand item using `GetItemByPos` with the appropriate inventory and equipment slot constants. +5. If the main hand item exists, we call the `DurabilityPointsLoss` method, passing the item and the number of durability points to subtract. +6. Finally, we send a broadcast message to the player informing them about the durability loss on their weapon. + +With this script, whenever the player enters combat with a creature that has the specified entry ID, their main hand weapon will lose the specified number of durability points. The player will also receive a broadcast message indicating the durability loss. + +Note: Make sure to replace `CREATURE_ENTRY_ID` with the actual entry ID of the creature you want to trigger the durability loss for, and adjust `DURABILITY_LOSS_POINTS` to the desired number of durability points to subtract. + +## DurabilityPointsLossAll +This method will reduce the durability of all equipped items on the player by the specified amount of points. Optionally, it can also reduce the durability of items in the player's inventory bags. + +### Parameters +* points: number - The amount of durability points to reduce on each item. Each point represents 0.01% durability loss. +* inventory?: boolean - (Optional) If set to true, the durability loss will also be applied to items in the player's inventory bags. + +### Example Usage +In this example, we create a script that applies a durability loss to all players in a raid group whenever a boss creature dies. The amount of durability loss is based on the raid difficulty, and it also applies to items in the inventory. + +```typescript +const BOSS_ENTRY = 12345; // Replace with the actual boss creature entry ID + +const onCreatureDeath: creature_event_on_creature_death = (event: number, creature: Creature, killer: Unit) => { + if (creature.GetEntry() === BOSS_ENTRY) { + const players = creature.GetPlayersInRangeSet(100); // Get all players within 100 yards of the boss + const raidDifficulty = creature.GetMapDifficulty(); // Get the raid difficulty (10 man, 25 man, etc.) + + let durabilityLoss = 0; + switch (raidDifficulty) { + case 1: // 10 man normal + durabilityLoss = 1000; // 10% durability loss + break; + case 2: // 25 man normal + durabilityLoss = 1500; // 15% durability loss + break; + case 3: // 10 man heroic + durabilityLoss = 2000; // 20% durability loss + break; + case 4: // 25 man heroic + durabilityLoss = 2500; // 25% durability loss + break; + } + + players.forEach((player) => { + player.DurabilityPointsLossAll(durabilityLoss, true); // Apply durability loss to equipped items and inventory + player.SendBroadcastMessage("Your items have suffered durability loss from the boss encounter!"); + }); + } +}; + +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_CREATURE_DEATH, (...args) => onCreatureDeath(...args)); +``` + +In this script: +1. We define the boss creature entry ID (replace `BOSS_ENTRY` with the actual ID). +2. In the `onCreatureDeath` event handler, we check if the died creature is the boss. +3. If it's the boss, we get all players within 100 yards of the boss using `GetPlayersInRangeSet()`. +4. We determine the raid difficulty using `GetMapDifficulty()` and set the `durabilityLoss` accordingly. +5. We iterate over each player in the range and apply the durability loss to their equipped items and inventory using `DurabilityPointsLossAll()`. +6. We send a broadcast message to each player informing them about the durability loss. +7. Finally, we register the event handler for the boss creature's death event using `RegisterCreatureEvent()`. + +This script adds an extra challenge and consequence to the boss encounter by causing durability loss to the players' items, requiring them to repair their gear after the fight. + +## DurabilityRepair +Repairs an equipped item at a specific inventory slot position. This can be used to repair an individual item on the player. +The player must be able to afford the cost of the repair and must be near a vendor that can repair the item. + +### Parameters +* position: number - Equipment slot to repair item in. +* cost: boolean - If true, the player will be charged the cost of the repair +* discountMod: number - Reputation discount on the cost of the repair if any (default: 1 no discount). +* guildBank: boolean - If true, the cost of the repair will be taken from the guild bank if the player has permissions (default: false) + +### Returns +Returns: number - The total cost of the repair + +### Example Usage: +This example will repair the players main hand weapon for free when they kill a creature based on the entry id of the creature. +```typescript +const CREATURE_ID = 400; +const EQUIPMENT_SLOT_MAINHAND = 15; + +const RepairOnKill: player_event_on_kill = (event: number, player: Player, creature: Creature) => { + + if(creature.GetEntry() === CREATURE_ID) { + + const [item] = player.GetItemByPos(255, EQUIPMENT_SLOT_MAINHAND); + + if(item) { + // don't charge for repair + const repairCost = player.DurabilityRepair(EQUIPMENT_SLOT_MAINHAND, false, 1); + + // Inform the player of the free repair + player.SendBroadcastMessage(`Your item ${item.GetName()} has been repaired for free!`); + player.SendBroadcastMessage(`This would normally cost: ${repairCost} copper`); + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => RepairOnKill(...args)); +``` + +In this example, when a player kills a specific creature, their main hand weapon will be repaired for free if it exists. The player will be informed of the free repair and the cost it would have been. + +## DurabilityRepairAll +Repairs all items in the player's inventory and equipped items. This method can be used to repair items at a discounted rate, and can also be used to repair items using the player's guild bank funds. + +### Parameters +* cost?: boolean - If set to true, the method will only return the total repair cost without actually repairing the items. Default is false. +* discountMod?: number - A discount modifier to apply to the repair cost. Default is 1.0 (no discount). +* guidBank?: boolean - If set to true, the method will use the player's guild bank funds to pay for the repairs. Default is false. + +### Returns +* number - The total repair cost. + +### Example Usage +Repair all items at a 20% discount using the player's own funds: +```typescript +function repairItems(player: Player) { + const discountMod = 0.8; + const repairCost = player.DurabilityRepairAll(false, discountMod); + + if (repairCost == 0) { + player.SendBroadcastMessage("All your items are fully repaired."); + } else { + player.SendBroadcastMessage(`Your items have been repaired for ${repairCost} gold.`); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (event, player, msg) => { + if (msg == "!repair") { + repairItems(player); + } +}); +``` + +In this example, when the player types "!repair" in the chat, the `repairItems` function will be called. The function repairs all the player's items at a 20% discount using the player's own funds. If the total repair cost is 0, it means all items are already fully repaired. Otherwise, the function sends a message to the player with the total repair cost. + +Here's another example that repairs all items using the player's guild bank funds: + +```typescript +function repairItemsGuildBank(player: Player) { + const repairCost = player.DurabilityRepairAll(true, 1.0, true); + + if (repairCost == 0) { + player.SendBroadcastMessage("All your items are fully repaired."); + return; + } + + const guild = player.GetGuild(); + + if (!guild) { + player.SendBroadcastMessage("You are not a member of a guild."); + return; + } + + const guildBankMoney = guild.GetBankMoney(); + + if (guildBankMoney < repairCost) { + player.SendBroadcastMessage("Your guild bank does not have enough funds to repair your items."); + return; + } + + guild.SetBankMoney(guildBankMoney - repairCost); + player.DurabilityRepairAll(false, 1.0, true); + player.SendBroadcastMessage(`Your items have been repaired for ${repairCost} gold using your guild bank funds.`); +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (event, player, msg) => { + if (msg == "!repairguild") { + repairItemsGuildBank(player); + } +}); +``` + +In this example, when the player types "!repairguild" in the chat, the `repairItemsGuildBank` function will be called. The function first checks the repair cost without actually repairing the items. If the cost is 0, it means all items are already fully repaired. + +If the player is not a member of a guild, a message is sent to the player and the function returns. If the player is a member of a guild, the function checks if the guild bank has enough funds to cover the repair cost. If not, a message is sent to the player and the function returns. + +If the guild bank has enough funds, the function subtracts the repair cost from the guild bank funds, repairs all the player's items using the guild bank funds, and sends a message to the player with the total repair cost. + +## EquipItem +Equips an item to the specified equipment slot on the player. If an item is already equipped in that slot, it will be replaced. + +### Parameters +- `item`: [Item](./item.md) - The item to be equipped. If `nil`, the `entry` parameter will be used to create the item. +- `entry`: number - The item entry ID from the `item_template` table. This is only used if `item` is `nil`. +- `slot`: number - The equipment slot to equip the item to. Use the `EquipmentSlots` enum for valid slot IDs. + +### Returns +[Item](./item.md) - The item that was equipped, or `nil` if the operation failed. + +### Example Usage +Equip a specific item to the player's main hand slot: +```typescript +const SULFURAS_HAND_OF_RAGNAROS_ENTRY = 17182; + +const onLoginEquipLegendary: player_event_on_login = (event: number, player: Player) => { + const legendaryWeapon = player.AddItem(SULFURAS_HAND_OF_RAGNAROS_ENTRY, 1); + if (legendaryWeapon) { + player.EquipItem(legendaryWeapon, 0, EquipmentSlots.EQUIPMENT_SLOT_MAINHAND); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => onLoginEquipLegendary(...args)); +``` + +Equip the best available item for each equipment slot: +```typescript +const onLevelUpImproveGear: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + const equipSlots = [ + EquipmentSlots.EQUIPMENT_SLOT_HEAD, + EquipmentSlots.EQUIPMENT_SLOT_NECK, + EquipmentSlots.EQUIPMENT_SLOT_SHOULDERS, + EquipmentSlots.EQUIPMENT_SLOT_CHEST, + EquipmentSlots.EQUIPMENT_SLOT_WAIST, + EquipmentSlots.EQUIPMENT_SLOT_LEGS, + EquipmentSlots.EQUIPMENT_SLOT_FEET, + EquipmentSlots.EQUIPMENT_SLOT_WRISTS, + EquipmentSlots.EQUIPMENT_SLOT_HANDS, + EquipmentSlots.EQUIPMENT_SLOT_FINGER1, + EquipmentSlots.EQUIPMENT_SLOT_FINGER2, + EquipmentSlots.EQUIPMENT_SLOT_TRINKET1, + EquipmentSlots.EQUIPMENT_SLOT_TRINKET2, + EquipmentSlots.EQUIPMENT_SLOT_BACK, + EquipmentSlots.EQUIPMENT_SLOT_MAINHAND, + EquipmentSlots.EQUIPMENT_SLOT_OFFHAND, + EquipmentSlots.EQUIPMENT_SLOT_RANGED, + EquipmentSlots.EQUIPMENT_SLOT_TABARD, + ]; + + for (const slot of equipSlots) { + const bestItemEntry = GetBestItemForPlayerBySlot(player, slot); + if (bestItemEntry) { + player.EquipItem(nil, bestItemEntry, slot); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => onLevelUpImproveGear(...args)); +``` +In this example, `GetBestItemForPlayerBySlot` is a custom function that would determine the best item for the player to equip in each slot based on their class, level, and other factors. The specific implementation is not shown here, but it would likely involve querying the `item_template` table and applying various heuristics to score and rank the available items. + +## FailQuest +This method sets a specific quest as failed for the player. When a quest is failed, it is removed from the player's active quests and cannot be completed or turned in. This can be useful for scripting custom quest interactions or implementing quest failure conditions. + +### Parameters +* entry: number - The ID of the quest to be marked as failed. Quest IDs can be found in the `quest_template` table in the world database. + +### Example Usage +In this example, we have a custom script that checks if the player has an item in their inventory when they try to complete a quest. If the player does not have the required item, the quest is marked as failed. + +```typescript +const REQUIRED_ITEM_ENTRY = 12345; +const QUEST_ENTRY = 678; + +const onQuestComplete: player_event_on_quest_complete = (event: number, player: Player, quest: number) => { + if (quest === QUEST_ENTRY) { + const requiredItem = player.GetItemByEntry(REQUIRED_ITEM_ENTRY); + + if (!requiredItem) { + player.SendBroadcastMessage("You do not have the required item to complete this quest."); + player.FailQuest(QUEST_ENTRY); + return false; // Prevent the quest from being completed + } + + // Additional logic for successful quest completion + player.SendBroadcastMessage("Quest completed! You had the required item."); + player.RemoveItem(requiredItem, 1); // Remove the required item from the player's inventory + } + + return true; // Allow the quest to be completed if conditions are met +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => onQuestComplete(...args)); +``` + +In this script: +1. We define the required item entry (`REQUIRED_ITEM_ENTRY`) and the quest entry (`QUEST_ENTRY`) as constants. +2. We register a player event handler for the `PLAYER_EVENT_ON_QUEST_COMPLETE` event. +3. When the player tries to complete the specified quest, we check if they have the required item in their inventory using the `GetItemByEntry` method. +4. If the player does not have the required item, we send them a message using `SendBroadcastMessage`, fail the quest using `FailQuest`, and return `false` to prevent the quest from being completed. +5. If the player has the required item, we send them a success message, remove the required item from their inventory using `RemoveItem`, and return `true` to allow the quest to be completed. + +By using the `FailQuest` method, we can implement custom quest failure conditions and handle them accordingly in our scripts. + +## GetAccountId +Returns the unique account ID for the player. This ID corresponds to the ID in the `account` table of the `auth` database. + +### Parameters +This method does not take any parameters. + +### Returns +* `number` - The player's account ID. + +### Example Usage +This example demonstrates how to retrieve a player's account ID and store it in the database for later use, such as tracking player activity or rewards. + +```typescript +// Event handler for player login +const OnLogin: player_event_on_login = (event: number, player: Player) => { + // Get the player's account ID + const accountId = player.GetAccountId(); + + // Get the current date and time + const currentDate = new Date(); + const dateString = currentDate.toISOString().slice(0, 19).replace('T', ' '); + + // Insert the player's account ID and login timestamp into the database + const query = ` + INSERT INTO player_activity (account_id, last_login) + VALUES (${accountId}, '${dateString}') + ON DUPLICATE KEY UPDATE last_login = '${dateString}'; + `; + + // Execute the SQL query + ExecuteQuery(query, (result: QueryResult) => { + if (result) { + console.log(`Logged player activity for account ID: ${accountId}`); + } else { + console.error(`Failed to log player activity for account ID: ${accountId}`); + } + }); +}; + +// Register the event handler for player login +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. When a player logs in, the `OnLogin` event handler is triggered. +2. The player's account ID is retrieved using `player.GetAccountId()`. +3. The current date and time are formatted as a string. +4. An SQL query is constructed to insert or update the player's account ID and login timestamp in the `player_activity` table. +5. The query is executed using `ExecuteQuery()`, which takes the SQL query and a callback function. +6. If the query is successful, a success message is logged; otherwise, an error message is logged. + +By storing the player's account ID and login timestamp in the database, you can track player activity, implement reward systems based on playtime, or perform other account-related operations. + +Note: Make sure to replace `player_activity` with the actual name of your database table and adjust the table structure according to your needs. + +## GetAccountName +Returns the account name of the player. + +### Parameters +None + +### Returns +string - The account name of the player. + +### Example Usage +This example demonstrates how to retrieve the account name of a player and use it to log a message when the player enters the world. + +```typescript +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const accountName = player.GetAccountName(); + + // Log the player's account name and character name + console.log(`Player ${player.GetName()} with account ${accountName} has logged in.`); + + // Check if the account name starts with "GM" + if (accountName.startsWith("GM")) { + // Send a welcome message to the player + player.SendBroadcastMessage("Welcome, Game Master! Your presence is greatly appreciated."); + + // Grant the player a special item + const gmItem = player.AddItem(12345, 1); + if (gmItem) { + player.SendBroadcastMessage(`You have been granted a special GM item: ${gmItem.GetName()}`); + } + } else { + // Send a regular welcome message to the player + player.SendBroadcastMessage("Welcome to the server! Enjoy your adventures."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: + +1. We define a callback function `OnLogin` that is triggered when a player logs in. + +2. Inside the callback, we retrieve the player's account name using `player.GetAccountName()` and store it in the `accountName` variable. + +3. We log a message using `console.log()` to display the player's account name and character name. + +4. We check if the account name starts with "GM" using the `startsWith()` method. + +5. If the account name starts with "GM": + - We send a special welcome message to the player using `player.SendBroadcastMessage()`. + - We grant the player a special GM item using `player.AddItem()` and store the added item in the `gmItem` variable. + - If the item is successfully added (i.e., `gmItem` is truthy), we send another message to the player informing them about the granted item. + +6. If the account name does not start with "GM", we send a regular welcome message to the player. + +7. Finally, we register the `OnLogin` callback function to the `PLAYER_EVENT_ON_LOGIN` event using `RegisterPlayerEvent()`. + +This example showcases how the `GetAccountName()` method can be used to retrieve the account name of a player and perform different actions based on the account name, such as sending customized messages or granting special items to game masters. + +## GetActiveSpec +Returns the active specialization ID for the player. This method can be used to determine which spec the player is currently using. + +### Parameters +None + +### Returns +number - The active specialization ID of the player. + +### Example Usage +This example demonstrates how to reward players with different items based on their active specialization. + +```typescript +const WARRIOR_SPEC_ARMS = 0; +const WARRIOR_SPEC_FURY = 1; +const WARRIOR_SPEC_PROTECTION = 2; + +const REWARD_ITEM_ARMS = 30001; +const REWARD_ITEM_FURY = 30002; +const REWARD_ITEM_PROTECTION = 30003; + +const RewardPlayerBySpec: player_event_on_quest_complete = (event: number, player: Player, quest: Quest, opt: number): void => { + const activeSpec = player.GetActiveSpec(); + + switch (activeSpec) { + case WARRIOR_SPEC_ARMS: + player.AddItem(REWARD_ITEM_ARMS, 1); + break; + case WARRIOR_SPEC_FURY: + player.AddItem(REWARD_ITEM_FURY, 1); + break; + case WARRIOR_SPEC_PROTECTION: + player.AddItem(REWARD_ITEM_PROTECTION, 1); + break; + default: + // Default reward for other classes or unknown specs + player.AddItem(REWARD_ITEM_ARMS, 1); + break; + } + + player.SendBroadcastMessage("You have been rewarded based on your active specialization!"); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => RewardPlayerBySpec(...args)); +``` + +In this example, when a player completes a quest, the `RewardPlayerBySpec` function is called. It retrieves the player's active specialization using `player.GetActiveSpec()`. Based on the active spec, the player is rewarded with a specific item using `player.AddItem()`. The reward items are defined as constants (`REWARD_ITEM_ARMS`, `REWARD_ITEM_FURY`, `REWARD_ITEM_PROTECTION`) and correspond to different item entry IDs. + +If the player is a Warrior, they will receive a different reward item based on their active spec (Arms, Fury, or Protection). For other classes or unknown specs, a default reward item is given. + +Finally, a broadcast message is sent to the player using `player.SendBroadcastMessage()` to inform them that they have been rewarded based on their active specialization. + +This example showcases how `GetActiveSpec()` can be used to customize rewards or actions based on a player's active specialization, providing a more tailored experience for different specs within a class. + +## GetArenaPoints +Retrieves the current amount of Arena Points the player has accumulated through Arena PvP matches. + +### Parameters +This method does not take any parameters. + +### Returns +- `number` - The amount of Arena Points the player currently possesses. + +### Example Usage +In this example, we will create a script that rewards players with bonus gold and items based on the amount of Arena Points they have accumulated. The script will be triggered when a player talks to an NPC. + +```typescript +const ARENA_POINTS_THRESHOLD = 1000; +const BONUS_GOLD_AMOUNT = 100; +const BONUS_ITEM_ENTRY = 12345; +const BONUS_ITEM_COUNT = 5; + +const OnGossipHello: npc_event_on_gossip_hello = (event: number, player: Player, object: WorldObject) => { + const arenaPoints = player.GetArenaPoints(); + + if (arenaPoints >= ARENA_POINTS_THRESHOLD) { + player.ModifyMoney(BONUS_GOLD_AMOUNT * 10000); // Convert copper to gold + player.SendNotification(`You have been rewarded with ${BONUS_GOLD_AMOUNT} gold for your Arena achievements!`); + + const item = player.AddItem(BONUS_ITEM_ENTRY, BONUS_ITEM_COUNT); + if (item) { + player.SendNotification(`You have also received ${BONUS_ITEM_COUNT}x [${item.GetName()}] as a bonus reward!`); + } else { + player.SendNotification("Your inventory is full. Please make room and talk to me again to claim your item reward."); + } + } else { + player.SendNotification(`You need at least ${ARENA_POINTS_THRESHOLD} Arena Points to claim the bonus rewards. Keep up the good fight!`); + } + + player.GossipComplete(); +}; + +RegisterNpcEvent(NPC_ENTRY, NpcEvents.GOSSIP_HELLO, (...args) => OnGossipHello(...args)); +``` + +In this script: +1. We define constants for the Arena Points threshold, bonus gold amount, bonus item entry, and bonus item count. +2. When a player interacts with the NPC (triggering the `GOSSIP_HELLO` event), we retrieve the player's current Arena Points using `player.GetArenaPoints()`. +3. If the player's Arena Points are greater than or equal to the defined threshold: + - We reward the player with bonus gold using `player.ModifyMoney()` and send a notification. + - We attempt to add the bonus item(s) to the player's inventory using `player.AddItem()`. + - If the item(s) are successfully added, we send a notification to the player with the item details. + - If the player's inventory is full, we send a notification asking them to make room and talk to the NPC again. +4. If the player's Arena Points are below the threshold, we send a notification encouraging them to continue participating in Arena matches. +5. Finally, we complete the gossip interaction with `player.GossipComplete()`. + +This script demonstrates how `player.GetArenaPoints()` can be used in combination with other methods to create a more complex and interactive system that rewards players based on their Arena achievements. + +## GetBaseSkillValue +Returns the base skill value for a given skill ID. The base skill value represents the player's proficiency in a particular skill without any temporary modifiers or bonuses. + +### Parameters +* skill: number - The ID of the skill to retrieve the base value for. Skill IDs can be found in the SkillLine.dbc file. + +### Returns +* number - The base skill value for the specified skill ID. + +### Example Usage +```typescript +const SKILL_HERBALISM = 182; +const SKILL_ALCHEMY = 171; + +const CheckProfessions: player_event_on_login = (event: number, player: Player) => { + const herbalismSkill = player.GetBaseSkillValue(SKILL_HERBALISM); + const alchemySkill = player.GetBaseSkillValue(SKILL_ALCHEMY); + + if (herbalismSkill >= 300 && alchemySkill >= 300) { + // Player has both Herbalism and Alchemy skills at or above 300 + player.SendBroadcastMessage("You are a master of Herbalism and Alchemy!"); + + // Reward the player with a special potion recipe + const RECIPE_FLASK_OF_ENHANCED_INTELLECT = 22566; + player.AddItem(RECIPE_FLASK_OF_ENHANCED_INTELLECT, 1); + } else if (herbalismSkill >= 300) { + // Player has Herbalism skill at or above 300 + player.SendBroadcastMessage("You are a master of Herbalism!"); + + // Reward the player with a rare herb + const HERB_GOLDEN_SANSAM = 13464; + player.AddItem(HERB_GOLDEN_SANSAM, 5); + } else if (alchemySkill >= 300) { + // Player has Alchemy skill at or above 300 + player.SendBroadcastMessage("You are a master of Alchemy!"); + + // Reward the player with a special potion + const POTION_FLASK_OF_CHROMATIC_RESISTANCE = 13513; + player.AddItem(POTION_FLASK_OF_CHROMATIC_RESISTANCE, 3); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => CheckProfessions(...args)); +``` +In this example, when a player logs in, their Herbalism and Alchemy skill levels are checked using the `GetBaseSkillValue` method. If the player has both skills at or above 300, they are considered a master of both professions and are rewarded with a special potion recipe. If they have only one of the skills at or above 300, they receive a corresponding reward based on their mastery in that profession. + +This script demonstrates how the `GetBaseSkillValue` method can be used to retrieve the player's base skill levels and make decisions or grant rewards based on their proficiency in various skills. + +## GetBattlegroundId +Returns the current battleground instance id the player is in. If the player is not in a battleground the value will be 0. + +### Parameters +This method does not have any parameters + +### Returns +number - The current [BattleGround](./BattleGround.md) ID or 0 if not in a battleground. + +### Example Usage: +Log to chat channel the player's current battleground +```typescript +const CHAT_MSG_ADDON = 0xFFFFFFFF; + +function OnChat(event: OnChatEvent, player: Player, message: string, type: ChatMsg): void { + // Check if the message is from a logged in player + if (type == ChatMsg.CHAT_MSG_SYSTEM) { + return; + } + + if(message === '!bg') { + const bgId = player.GetBattlegroundId(); + if(bgId === 0) { + player.SendBroadcastMessage('You are currently not in a battleground'); + } else { + const bgName = GetBattlegroundName(bgId); + player.SendBroadcastMessage(`You are currently in Battleground: ${bgName} (${bgId})`); + } + } +} + +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_CHAT, OnChat); +``` +Create a timed loot bonus event for players in a BattleGround +```typescript +const BG_CHANCE = 25; // 25% chance to reward bonus loot +const BG_ITEM_ENTRY_BONUS = 29434; // Badge of Justice + +function OnLootItem(event: PlayerEvents, player: Player, item: Item, count: number) { + if(player.GetBattlegroundId() > 0) { + // Player is in a battleground + if(MathRand(1,100) <= BG_CHANCE) { + // Award bonus loot + player.SendBroadcastMessage(`You have won a BONUS ${GetItemLink(BG_ITEM_ENTRY_BONUS)}`); + player.AddItem(BG_ITEM_ENTRY_BONUS); + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, OnLootItem); +``` + +## GetBattlegroundTypeId +Returns the current battleground type ID for the player. This can be used to determine which battleground the player is currently in. + +### Parameters +None + +### Returns +BattleGroundTypeId: [BattleGroundTypeId](./constants.md#battlegroundtypeid) - The current battleground type ID. + +### Example Usage +Reward players with bonus honor when they win a specific battleground. +```typescript +const BG_AV_ID = BattleGroundTypeId.BATTLEGROUND_AV; +const BG_BONUS_HONOR = 100; + +const OnBattlegroundEnd: player_event_on_battleground_end = (event: number, player: Player, bgId: number, bgInstanceId: number, team: number, winner: number, duration: number) => { + const playerTeam = player.GetTeam(); + const playerBGId = player.GetBattlegroundTypeId(); + + if (playerBGId === BG_AV_ID && winner === playerTeam) { + const honorBeforeBonus = player.GetHonorPoints(); + player.ModifyHonorPoints(BG_BONUS_HONOR); + const honorAfterBonus = player.GetHonorPoints(); + + player.SendBroadcastMessage(`Congratulations on winning Alterac Valley! You have been awarded ${BG_BONUS_HONOR} bonus honor!`); + player.SendBroadcastMessage(`Your honor has increased from ${honorBeforeBonus} to ${honorAfterBonus}.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_BATTLEGROUND_END, (...args) => OnBattlegroundEnd(...args)); +``` + +In this example, when a player wins a battleground, the script checks if the battleground was Alterac Valley using `GetBattlegroundTypeId()`. If it was, the player is awarded bonus honor points using `ModifyHonorPoints()`. The script also sends the player messages using `SendBroadcastMessage()` to inform them of the bonus honor and their updated total honor points, which are obtained using `GetHonorPoints()` before and after the bonus is applied. + +## GetChampioningFaction +Returns the faction ID the player is currently championing. This is used in Wrath of the Lich King for the Argent Tournament quests and rewards. + +### Parameters +None + +### Returns +factionId: number - The faction ID the player is currently championing, or 0 if not championing any faction. + +### Example Usage +This example listens for the PLAYER_EVENT_ON_QUEST_ABANDON event and checks if the player is abandoning a quest from their championing faction. If so, it removes the championing flag and sends a message to the player. + +```typescript +const ARGENT_TOURNAMENT_FACTION_ID = 1106; + +const onQuestAbandon: player_event_on_quest_abandon = (event: number, player: Player, quest: Quest) => { + const championingFaction = player.GetChampioningFaction(); + + if (championingFaction === ARGENT_TOURNAMENT_FACTION_ID) { + const questTemplate = quest.GetQuestTemplate(); + + if (questTemplate && questTemplate.GetQuestFactionGroup() === championingFaction) { + player.SetChampioningFaction(0); + player.SendBroadcastMessage("You have abandoned a quest from your championing faction. Your championing status has been removed."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_ABANDON, (...args) => onQuestAbandon(...args)); +``` + +In this example: +1. We define the constant `ARGENT_TOURNAMENT_FACTION_ID` with the value 1106, which represents the faction ID for the Argent Tournament. +2. We create a function `onQuestAbandon` that listens for the `PLAYER_EVENT_ON_QUEST_ABANDON` event. +3. Inside the function, we get the player's current championing faction using `player.GetChampioningFaction()`. +4. We check if the player is championing the Argent Tournament faction by comparing the returned faction ID with `ARGENT_TOURNAMENT_FACTION_ID`. +5. If the player is championing the Argent Tournament faction, we get the quest template using `quest.GetQuestTemplate()`. +6. We check if the quest template exists and if its faction group matches the player's championing faction. +7. If the conditions are met, we remove the player's championing status by calling `player.SetChampioningFaction(0)`. +8. Finally, we send a broadcast message to the player informing them that their championing status has been removed. + +This example demonstrates how to use the `GetChampioningFaction` method to retrieve the player's current championing faction and take appropriate actions based on that information. + +## GetChatTag +Returns the active GM chat tag for the player. GM chat tags are used to identify the rank or role of a GM in chat messages. + +### Parameters +This method does not take any parameters. + +### Returns +chat_tag: number - The active GM chat tag for the player. + +### Example Usage +This example demonstrates how to retrieve a player's GM chat tag and use it to determine their GM rank. It then applies a buff to the player based on their rank. + +```typescript +const GMRankHandler: player_event_on_login = (event: number, player: Player) => { + const GM_CHAT_TAG_JUNIOR = 1; + const GM_CHAT_TAG_SENIOR = 2; + const GM_CHAT_TAG_LEAD = 3; + + const BUFF_JUNIOR_GM = 12345; + const BUFF_SENIOR_GM = 23456; + const BUFF_LEAD_GM = 34567; + + const chatTag = player.GetChatTag(); + + switch (chatTag) { + case GM_CHAT_TAG_JUNIOR: + player.AddAura(BUFF_JUNIOR_GM, player); + player.SendBroadcastMessage("Welcome, Junior GM! Your buff has been applied."); + break; + case GM_CHAT_TAG_SENIOR: + player.AddAura(BUFF_SENIOR_GM, player); + player.SendBroadcastMessage("Welcome, Senior GM! Your buff has been applied."); + break; + case GM_CHAT_TAG_LEAD: + player.AddAura(BUFF_LEAD_GM, player); + player.SendBroadcastMessage("Welcome, Lead GM! Your buff has been applied."); + break; + default: + player.SendBroadcastMessage("Welcome, player! You do not have any GM privileges."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => GMRankHandler(...args)); +``` + +In this example: +1. We define constants for the different GM chat tags and their corresponding buff IDs. +2. When a player logs in, we retrieve their GM chat tag using `player.GetChatTag()`. +3. We use a switch statement to determine the player's GM rank based on their chat tag. +4. Depending on the GM rank, we apply the appropriate buff to the player using `player.AddAura()`. +5. We send a personalized welcome message to the player using `player.SendBroadcastMessage()`, informing them of their GM rank and the applied buff. +6. If the player does not have any GM privileges (i.e., their chat tag doesn't match any of the defined constants), we send a generic welcome message. + +This example showcases how the `GetChatTag()` method can be used to differentiate between players with different GM ranks and provide them with specific buffs or privileges based on their rank. + +## GetCoinage +Returns the amount of money the player has in copper. Copper is the lowest denomination of currency in World of Warcraft. There are 100 copper in a silver, and 100 silver in a gold. + +### Parameters +None + +### Returns +coinage: number - The amount of money the player has in copper. + +### Example Usage: +This example charges a player 1 gold when they die, and sends them a message with how much money they have left. +```typescript +const DEATH_COST = 10000; // 100 copper = 1 silver, 100 silver = 1 gold + +const onPlayerDeath: player_event_on_death = (event: number, player: Player, killer: Unit) => { + const playerMoney = player.GetCoinage(); + + if (playerMoney >= DEATH_COST) { + player.ModifyMoney(-DEATH_COST); + player.SendBroadcastMessage(`You have paid ${DEATH_COST / 100} silver to recover from death. You now have ${(playerMoney - DEATH_COST) / 10000} gold remaining.`); + } else { + player.SendBroadcastMessage(`You do not have enough money to pay the death cost. You need ${(DEATH_COST - playerMoney) / 100} more silver.`); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => onPlayerDeath(...args)); +``` + +Another example could be a script that rewards players with bonus money for killing a certain number of creatures: +```typescript +const KILL_COUNT_GOAL = 100; +const BONUS_MONEY = 50000; // 5 gold + +let playerKillCounts: { [playerGuid: number]: number } = {}; + +const onCreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + const playerGuid = player.GetGUIDLow(); + + if (!(playerGuid in playerKillCounts)) { + playerKillCounts[playerGuid] = 0; + } + + playerKillCounts[playerGuid]++; + + if (playerKillCounts[playerGuid] == KILL_COUNT_GOAL) { + player.ModifyMoney(BONUS_MONEY); + player.SendBroadcastMessage(`Congratulations! You have killed ${KILL_COUNT_GOAL} creatures and earned a bonus of ${BONUS_MONEY / 10000} gold!`); + playerKillCounts[playerGuid] = 0; + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => onCreatureKill(...args)); +``` + +## GetComboPoints +Returns the current number of combo points the player has on their target. + +### Parameters +None + +### Returns +* number - The current number of combo points the player has on their target. + +### Example Usage +This example demonstrates how to retrieve the player's current combo points and use them to determine the damage of a custom spell. + +```typescript +const CUSTOM_SPELL_ID = 123456; +const COMBO_POINT_DAMAGE_MODIFIER = 0.2; + +const CustomSpellDamageCalculator: SpellCastFn = (event: number, caster: WorldObject, target: WorldObject, spell: number): boolean => { + if (spell === CUSTOM_SPELL_ID && caster.IsPlayer()) { + const player = caster.ToPlayer(); + const comboPoints = player.GetComboPoints(); + const baseDamage = 100; + const totalDamage = baseDamage * (1 + (comboPoints * COMBO_POINT_DAMAGE_MODIFIER)); + + player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_SYSTEM, 0, `Casting custom spell with ${comboPoints} combo points for ${totalDamage} damage.`); + + target.ToUnit().DealDamage(player, totalDamage, DamageEffectType.DIRECT_DAMAGE, DamageSchoolMask.NORMAL, CUSTOM_SPELL_ID); + + player.ClearComboPoints(); + + return false; + } + return true; +}; + +RegisterSpellCastFn(CUSTOM_SPELL_ID, CustomSpellDamageCalculator); +``` + +In this example: +1. We define a custom spell ID and a combo point damage modifier constant. +2. We create a `CustomSpellDamageCalculator` function that will be called when our custom spell is cast. +3. Inside the function, we check if the spell being cast is our custom spell and if the caster is a player. +4. If the conditions are met, we retrieve the player's current combo points using `GetComboPoints()`. +5. We calculate the total damage based on a base damage value and the number of combo points, using our damage modifier. +6. We send a message to the player informing them of the number of combo points used and the total damage dealt. +7. We deal the calculated damage to the target using `DealDamage()`. +8. We clear the player's combo points using `ClearComboPoints()` to consume them. +9. Finally, we register our `CustomSpellDamageCalculator` function to be called whenever our custom spell is cast using `RegisterSpellCastFn()`. + +This example showcases how `GetComboPoints()` can be used in conjunction with other player methods and custom logic to create unique gameplay mechanics in your mod. + +## GetComboTarget +Returns the current [Unit](./unit.md) that the player has combo points on. This is useful for abilities or effects that consume or modify combo points. + +### Parameters +None + +### Returns +[Unit](./unit.md) - The unit that the player has combo points on. If no combo points are active, this will return `nil`. + +### Example Usage +In this example, we'll create a script that allows a rogue player to use a custom ability that consumes all combo points on their current target to deal bonus damage. If no combo points are active, the ability will have no effect. + +```typescript +const CUSTOM_ABILITY_ENTRY = 12345; +const COMBO_POINT_DAMAGE_BONUS = 50; + +const CustomAbility: player_event_on_cast_spell = (event: number, player: Player, spell: number, skipCheck: boolean) => { + // Check if the spell cast is our custom ability + if (spell == CUSTOM_ABILITY_ENTRY) { + const comboTarget = player.GetComboTarget(); + + // If a combo target exists, consume combo points and deal bonus damage + if (comboTarget) { + const comboPoints = player.GetComboPoints(); + const bonusDamage = comboPoints * COMBO_POINT_DAMAGE_BONUS; + + player.ClearComboPoints(); + player.DealDamage(comboTarget, bonusDamage, true); + + player.SendAreaTriggerMessage(`You consume ${comboPoints} combo points to deal ${bonusDamage} bonus damage!`); + } else { + player.SendAreaTriggerMessage("No combo points active. Custom ability has no effect."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CAST_SPELL, (...args) => CustomAbility(...args)); +``` + +In this script: + +1. We define constants for our custom ability's entry ID and the damage bonus per combo point. +2. In the `CustomAbility` function, we check if the spell being cast matches our custom ability entry. +3. If it does, we use `GetComboTarget()` to retrieve the current combo target. +4. If a combo target exists, we: + - Get the current number of combo points using `GetComboPoints()`. + - Calculate the bonus damage based on the number of combo points. + - Clear the combo points using `ClearComboPoints()`. + - Deal the bonus damage to the combo target using `DealDamage()`. + - Send a message to the player indicating the number of combo points consumed and bonus damage dealt. +5. If no combo target exists, we send a message to the player indicating that the custom ability has no effect. + +This script demonstrates how `GetComboTarget()` can be used in conjunction with other methods to create custom abilities or effects that interact with the rogue/druid combo point mechanic. + +## GetCompletedQuestCount +Returns the total number of quests that the player has completed across all zones and expansions. + +### Parameters +None + +### Returns +completedQuestCount: number - The total number of quests completed by the player. + +### Example Usage +This example demonstrates how to reward players with bonus gold and experience based on the number of quests they have completed. The script listens for the `PLAYER_EVENT_ON_LEVEL_CHANGE` event and checks if the player's level is divisible by 10. If so, it calculates a bonus reward based on the number of completed quests and grants the player bonus gold and experience. + +```typescript +const BONUS_GOLD_PER_QUEST = 10; +const BONUS_EXP_PER_QUEST = 100; + +const onPlayerLevelChange: player_event_on_level_change = (event: number, player: Player, oldLevel: number): void => { + const newLevel = player.GetLevel(); + + if (newLevel % 10 === 0) { + const completedQuestCount = player.GetCompletedQuestCount(); + const bonusGold = completedQuestCount * BONUS_GOLD_PER_QUEST; + const bonusExp = completedQuestCount * BONUS_EXP_PER_QUEST; + + player.ModifyMoney(bonusGold); + player.GiveXP(bonusExp, true); + + player.SendNotification(`Congratulations on reaching level ${newLevel}!`); + player.SendNotification(`As a reward for completing ${completedQuestCount} quests, you have been granted ${bonusGold} bonus gold and ${bonusExp} bonus experience!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => onPlayerLevelChange(...args)); +``` + +In this example: +1. We define constants `BONUS_GOLD_PER_QUEST` and `BONUS_EXP_PER_QUEST` to specify the amount of bonus gold and experience to grant per completed quest. + +2. We register a callback function `onPlayerLevelChange` for the `PLAYER_EVENT_ON_LEVEL_CHANGE` event. + +3. Inside the callback function, we check if the player's new level is divisible by 10 using the modulo operator (`%`). + +4. If the level is divisible by 10, we retrieve the total number of completed quests using `player.GetCompletedQuestCount()`. + +5. We calculate the bonus gold and experience by multiplying the number of completed quests by the respective bonus constants. + +6. We grant the player the bonus gold using `player.ModifyMoney(bonusGold)` and bonus experience using `player.GiveXP(bonusExp, true)`. + +7. Finally, we send notifications to the player informing them about reaching the new level and the bonus rewards they have received. + +This script encourages players to complete more quests by rewarding them with bonus gold and experience at significant level milestones. The bonus rewards scale based on the number of quests completed, providing an incentive for players to actively engage in questing throughout their journey. + +## GetCorpse +Retrieves the player's corpse object, which represents the player's physical remains upon death. + +### Parameters +None + +### Returns +corpse: [Corpse](./corpse.md) - The player's corpse object. + +### Example Usage +This example demonstrates how to use the `GetCorpse` method to retrieve a player's corpse and perform actions based on its properties. + +```typescript +const OnPlayerDeath: player_event_on_death = (event: number, player: Player, killer: Unit) => { + const corpse = player.GetCorpse(); + + if (corpse) { + const x = corpse.GetX(); + const y = corpse.GetY(); + const z = corpse.GetZ(); + const mapId = corpse.GetMapId(); + + // Check if the corpse is in a specific area + if (mapId === 0 && x > 0 && x < 1000 && y > 0 && y < 1000) { + // Perform actions when the corpse is in the desired area + player.SendBroadcastMessage("Your corpse is located in a special area!"); + + // Create a visual effect at the corpse's location + corpse.SummonGameObject(180647, 0, 0, 0, 0, 300); + + // Set a flag on the player to indicate special handling + player.SetFlag(PlayerFlags.PLAYER_FLAGS_CUSTOM_FLAG, 1); + } else { + // Perform actions when the corpse is not in the desired area + player.SendBroadcastMessage("Your corpse is not in a special area."); + } + } else { + player.SendBroadcastMessage("No corpse found for the player."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => OnPlayerDeath(...args)); +``` + +In this example, when a player dies, the script retrieves the player's corpse using the `GetCorpse` method. It then checks the corpse's location using the `GetX`, `GetY`, `GetZ`, and `GetMapId` methods to determine if it is within a specific area. + +If the corpse is in the desired area, the script sends a broadcast message to the player indicating that their corpse is in a special location. It also summons a visual effect (game object) at the corpse's location using the `SummonGameObject` method and sets a custom flag on the player using the `SetFlag` method for further handling. + +If the corpse is not in the desired area, the script sends a different broadcast message to the player. + +If no corpse is found for the player, an appropriate message is sent to the player. + +This example showcases how the `GetCorpse` method can be used in combination with other methods and game events to create custom behaviors and interactions based on the player's corpse. + +## GetDbLocaleIndex +Returns the player's locale index from the database. + +### Parameters +None + +### Returns +localeIndex: number - The locale index of the player from the database. + +### Example Usage +Reward players with different items based on their locale. +```typescript +const LOCALES = { + enUS: 0, + koKR: 1, + frFR: 2, + deDE: 3, + zhCN: 4, + zhTW: 5, + esES: 6, + esMX: 7, + ruRU: 8 +}; + +const LOCALE_REWARDS = { + [LOCALES.enUS]: 1234, + [LOCALES.koKR]: 5678, + [LOCALES.frFR]: 9012, + [LOCALES.deDE]: 3456, + [LOCALES.zhCN]: 7890, + [LOCALES.zhTW]: 2345, + [LOCALES.esES]: 6789, + [LOCALES.esMX]: 1234, + [LOCALES.ruRU]: 5678 +}; + +const RewardPlayerByLocale: player_event_on_login = (event: number, player: Player) => { + const localeIndex = player.GetDbLocaleIndex(); + const rewardItemEntry = LOCALE_REWARDS[localeIndex]; + + if (rewardItemEntry) { + const rewardItem = player.AddItem(rewardItemEntry, 1); + if (rewardItem) { + player.SendBroadcastMessage(`You have been rewarded with ${rewardItem.GetName()} for your locale!`); + } else { + player.SendBroadcastMessage("Failed to reward item. Please contact an administrator."); + } + } else { + player.SendBroadcastMessage("No reward found for your locale."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => RewardPlayerByLocale(...args)); +``` +In this example, we define a mapping of locale indices to reward item entries. When a player logs in, we retrieve their locale index using `GetDbLocaleIndex()` and check if there is a corresponding reward item entry in the `LOCALE_REWARDS` object. If a reward is found, we use the `AddItem()` method to grant the item to the player and send them a broadcast message informing them of the reward. If the item grant fails or if no reward is found for their locale, we send an appropriate message to the player. + +This example demonstrates how `GetDbLocaleIndex()` can be used in combination with other player methods and game data to create a locale-based reward system. + +## GetDbcLocale +Returns the player's game client locale, which represents the language and region settings configured in the game client. + +### Parameters +None + +### Returns +[LocaleConstant](./constants.md#localeconstant) - The locale constant corresponding to the player's game client locale. + +### Example Usage +Sending a localized welcome message based on the player's client locale: +```typescript +const WELCOME_MESSAGES: Record = { + [LocaleConstant.LOCALE_enUS]: "Welcome to the server, adventurer!", + [LocaleConstant.LOCALE_esES]: "¡Bienvenido al servidor, aventurero!", + [LocaleConstant.LOCALE_esMX]: "¡Bienvenido al servidor, aventurero!", + [LocaleConstant.LOCALE_frFR]: "Bienvenue sur le serveur, aventurier !", + [LocaleConstant.LOCALE_deDE]: "Willkommen auf dem Server, Abenteurer!", + [LocaleConstant.LOCALE_itIT]: "Benvenuto nel server, avventuriero!", + [LocaleConstant.LOCALE_ptBR]: "Bem-vindo ao servidor, aventureiro!", + [LocaleConstant.LOCALE_ruRU]: "Добро пожаловать на сервер, искатель приключений!", + [LocaleConstant.LOCALE_zhCN]: "欢迎来到服务器,冒险者!", + [LocaleConstant.LOCALE_zhTW]: "歡迎來到伺服器,冒險者!", + [LocaleConstant.LOCALE_koKR]: "서버에 오신 것을 환영합니다, 모험가 님!", +}; + +const DEFAULT_WELCOME_MESSAGE = "Welcome to the server!"; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const locale = player.GetDbcLocale(); + const welcomeMessage = WELCOME_MESSAGES[locale] || DEFAULT_WELCOME_MESSAGE; + + player.SendBroadcastMessage(welcomeMessage); + + // Apply a localized buff based on the player's locale + switch (locale) { + case LocaleConstant.LOCALE_esES: + case LocaleConstant.LOCALE_esMX: + player.AddAura(1234, player); // Buff ID for Spanish locales + break; + case LocaleConstant.LOCALE_frFR: + player.AddAura(5678, player); // Buff ID for French locale + break; + // Add more cases for other locales as needed + default: + player.AddAura(9012, player); // Default buff ID + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +``` +In this example, the script defines a dictionary (`WELCOME_MESSAGES`) that maps locale constants to localized welcome messages. When a player logs in, the script retrieves the player's game client locale using `GetDbcLocale()` and looks up the corresponding welcome message. If a localized message is found, it is sent to the player using `SendBroadcastMessage()`; otherwise, a default welcome message is used. + +Additionally, the script applies a localized buff to the player based on their locale. The buff IDs are specified using a `switch` statement that matches the locale constant. This allows for providing unique buffs or effects tailored to specific locales, enhancing the player's experience based on their language and region settings. + +## GetDifficulty +Returns the current difficulty level of the instance (raid or dungeon) the player is in. + +### Parameters +* isRaid (optional): boolean - If set to true, it will return the difficulty of the raid instance. If false or not provided, it will return the difficulty of the dungeon instance. + +### Returns +* number - The difficulty level of the instance. Possible return values: + * 0 - Normal + * 1 - Heroic + * 2 - Epic + * 3 - Legendary + * 4 - Mythic + +### Example Usage +Adjust loot based on the difficulty level of the instance. +```typescript +const ITEM_ENTRY_NORMAL = 12345; +const ITEM_ENTRY_HEROIC = 23456; +const ITEM_ENTRY_EPIC = 34567; +const ITEM_ENTRY_LEGENDARY = 45678; +const ITEM_ENTRY_MYTHIC = 56789; + +const onCreatureDeath: creature_event_on_just_died = (event: number, creature: Creature, killer: Unit) => { + const players = creature.GetPlayersInRange(100); + + for (const player of players) { + const difficulty = player.GetDifficulty(creature.IsWorldBoss()); + + switch (difficulty) { + case 0: + player.AddItem(ITEM_ENTRY_NORMAL, 1); + break; + case 1: + player.AddItem(ITEM_ENTRY_HEROIC, 1); + break; + case 2: + player.AddItem(ITEM_ENTRY_EPIC, 1); + break; + case 3: + player.AddItem(ITEM_ENTRY_LEGENDARY, 1); + break; + case 4: + player.AddItem(ITEM_ENTRY_MYTHIC, 1); + break; + } + } +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_JUST_DIED, (...args) => onCreatureDeath(...args)); +``` +In this example, when a creature dies, it retrieves all players within a range of 100 yards. For each player, it checks the difficulty level of the instance using `GetDifficulty()` method. If the creature is a world boss (`IsWorldBoss()`), it passes `true` to get the raid difficulty, otherwise, it gets the dungeon difficulty. + +Based on the difficulty level, it adds a specific item to the player's inventory using `AddItem()` method. The item entry is determined by the predefined constants (`ITEM_ENTRY_NORMAL`, `ITEM_ENTRY_HEROIC`, etc.). + +This script allows for adjusting the loot drops based on the difficulty level of the instance, providing appropriate rewards for each difficulty setting. + +## GetDrunkValue +Returns the player's current level of intoxication, represented as a numeric value. The intoxication level increases when the player consumes alcoholic beverages and decreases over time. The specific effects of intoxication may vary depending on the level. + +### Parameters +This method does not take any parameters. + +### Returns +* number - The current intoxication level of the player. + +### Example Usage +This example demonstrates how to create a custom alcoholic item that increases the player's intoxication level and applies a bonus to their movement speed based on the intoxication level. + +```typescript +const CUSTOM_DRINK_ENTRY = 12345; +const INTOXICATION_INCREASE = 20; +const MOVEMENT_SPEED_BONUS_PER_LEVEL = 5; + +const UseCustomDrink: player_event_on_use_item = (event: number, player: Player, item: Item, target: Unit) => { + if (item.GetEntry() == CUSTOM_DRINK_ENTRY) { + const currentIntoxication = player.GetDrunkValue(); + const newIntoxication = Math.min(currentIntoxication + INTOXICATION_INCREASE, 100); + + player.SetDrunkValue(newIntoxication); + + const movementSpeedBonus = (newIntoxication / 10) * MOVEMENT_SPEED_BONUS_PER_LEVEL; + player.SetSpeed(UnitMoveType.MOVE_RUN, player.GetSpeed(UnitMoveType.MOVE_RUN) * (1 + movementSpeedBonus / 100), true); + + player.SendBroadcastMessage(`You feel the warmth of the drink spreading through your body. Your intoxication level is now ${newIntoxication}.`); + + if (newIntoxication >= 50) { + player.SendBroadcastMessage("You start to feel a bit tipsy and your movements become slightly erratic."); + } + + if (newIntoxication >= 80) { + player.SendBroadcastMessage("The world around you begins to spin and you struggle to maintain your balance."); + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => UseCustomDrink(...args)); +``` + +In this example: +1. We define constants for the custom drink item entry, the amount of intoxication increase per use, and the movement speed bonus per intoxication level. +2. When the player uses the custom drink item, we retrieve their current intoxication level using `player.GetDrunkValue()`. +3. We calculate the new intoxication level by adding the `INTOXICATION_INCREASE` to the current level, capped at a maximum of 100. +4. We update the player's intoxication level using `player.SetDrunkValue(newIntoxication)`. +5. We calculate the movement speed bonus based on the new intoxication level and apply it to the player's running speed using `player.SetSpeed()`. +6. We send a broadcast message to the player indicating their current intoxication level. +7. Depending on the intoxication level, we send additional broadcast messages to the player to describe the effects of intoxication. + +This example showcases how the `GetDrunkValue()` method can be used in combination with other methods to create custom gameplay mechanics related to intoxication. + +## GetEquippedItemBySlot +Returns the [Item](./item.md) object equipped in the specified gear slot of the player. + +### Parameters +* slot: number - The gear slot to retrieve the item from. Valid gear slots are defined in the InventorySlots enum. + +### Returns +[Item](./item.md) - The item equipped in the specified gear slot, or null if no item is equipped in that slot. + +### Example Usage +This example demonstrates how to retrieve the item equipped in the player's main hand slot and check if it is a one-handed weapon. If it is, the script equips a shield in the off-hand slot. + +```typescript +const MAIN_HAND_SLOT = 15; +const OFF_HAND_SLOT = 16; +const SHIELD_ITEM_ENTRY = 12345; + +const equipShield: player_event_on_login = (event: number, player: Player): void => { + const mainHandItem = player.GetEquippedItemBySlot(MAIN_HAND_SLOT); + + if (mainHandItem) { + const itemSubClass = mainHandItem.GetSubClass(); + const itemInventoryType = mainHandItem.GetInventoryType(); + + // Check if the main hand item is a one-handed weapon + if (itemSubClass === 0 && (itemInventoryType === 0 || itemInventoryType === 4)) { + const offHandItem = player.GetEquippedItemBySlot(OFF_HAND_SLOT); + + // Check if the off-hand slot is empty + if (!offHandItem) { + // Equip a shield in the off-hand slot + const shieldItem = player.AddItem(SHIELD_ITEM_ENTRY, 1); + + if (shieldItem) { + player.EquipItem(shieldItem, OFF_HAND_SLOT); + player.SendBroadcastMessage("A shield has been equipped in your off-hand slot."); + } else { + player.SendBroadcastMessage("Failed to equip a shield in your off-hand slot."); + } + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => equipShield(...args)); +``` + +In this example, when the player logs in, the script retrieves the item equipped in the main hand slot using `GetEquippedItemBySlot`. It then checks if the item is a one-handed weapon by examining its item subclass and inventory type. + +If the main hand item is a one-handed weapon and the off-hand slot is empty, the script adds a shield item to the player's inventory using `AddItem` and equips it in the off-hand slot using `EquipItem`. The player receives a broadcast message indicating the result of the shield equipment attempt. + +This script ensures that players with a one-handed weapon in their main hand have a shield equipped in their off-hand slot when they log in, providing additional defense if they meet the specified conditions. + +## GetFreeTalentPoints +Returns the number of free talent points the player currently has available to spend. + +### Parameters +None + +### Returns +- `number` - The number of free talent points the player has. + +### Example Usage +This example demonstrates how to check if a player has enough talent points to learn a specific talent and if so, learn that talent. + +```typescript +// Talent entries can be found in the TalentEntry.dbc file +const WARRIOR_TALENT_SECOND_WIND = 1838; + +const onLevelUp: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + // Get the number of free talent points the player has + const freeTalentPoints = player.GetFreeTalentPoints(); + + // Check if the player is a warrior and has at least 1 free talent point + if (player.GetClass() == Classes.CLASS_WARRIOR && freeTalentPoints > 0) { + // Warrior class specific logic + if (oldLevel < 40 && player.GetLevel() >= 40) { + // Check if the player already has the Second Wind talent + if (!player.HasSpell(WARRIOR_TALENT_SECOND_WIND)) { + // Learn the Second Wind talent + player.LearnTalent(WARRIOR_TALENT_SECOND_WIND); + player.SendBroadcastMessage("You have learned the Second Wind talent!"); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => onLevelUp(...args)); +``` + +In this example: +1. We define a constant `WARRIOR_TALENT_SECOND_WIND` with the talent entry for the warrior's Second Wind talent. +2. In the `PLAYER_EVENT_ON_LEVEL_CHANGE` event, we get the number of free talent points the player has using `player.GetFreeTalentPoints()`. +3. We check if the player is a warrior and has at least 1 free talent point. +4. If the player is a warrior and just reached level 40, we check if they already have the Second Wind talent using `player.HasSpell(WARRIOR_TALENT_SECOND_WIND)`. +5. If the player doesn't have the Second Wind talent, we use `player.LearnTalent(WARRIOR_TALENT_SECOND_WIND)` to automatically learn the talent and send a broadcast message to the player informing them that they have learned the talent. + +This script ensures that when a warrior player reaches level 40 and has an available talent point, they will automatically learn the Second Wind talent if they haven't already learned it. + +You can expand this script to handle other classes and talents based on your specific requirements and the talents available in the TalentEntry.dbc file. + +## GetGMRank +Returns the [Player]'s current GM Rank. GM Ranks determine the level of access and permissions a player has to server commands and features. + +### Parameters +None + +### Returns +rank: number - The current GM Rank of the player. + +GM Ranks: +* 0 - Player +* 1 - Moderator +* 2 - Gamemaster +* 3 - Administrator +* 4 - Console + +### Example Usage: +Restrict access to a special vendor based on GM Rank. +```typescript +const SPECIAL_VENDOR_ENTRY = 123456; +const GM_RANK_REQUIRED = 3; + +const OnGossipHello: gossip_event_on_hello = (event, player, creature) => { + if (creature.GetEntry() === SPECIAL_VENDOR_ENTRY) { + if (player.GetGMRank() >= GM_RANK_REQUIRED) { + // Show special vendor options + player.GossipMenuAddItem(0, "Access Special Vendor", 1, 1); + player.GossipSendMenu(1, creature.GetObjectGuid()); + } else { + // Inform player they do not have access + player.GossipSetText("Sorry, you do not have permission to access this vendor."); + player.GossipSendMenu(1, creature.GetObjectGuid()); + } + } +}; + +const OnGossipSelect: gossip_event_on_select = (event, player, creature, sender, action) => { + if (creature.GetEntry() === SPECIAL_VENDOR_ENTRY && action === 1) { + // Send special vendor window + player.SendListInventory(creature.GetObjectGuid()); + } + player.GossipComplete(); +}; + +RegisterCreatureGossipEvent(SPECIAL_VENDOR_ENTRY, 1, OnGossipHello); +RegisterCreatureGossipEvent(SPECIAL_VENDOR_ENTRY, 2, OnGossipSelect); +``` +In this example, when a player interacts with the special vendor (defined by `SPECIAL_VENDOR_ENTRY`), their GM Rank is checked using `GetGMRank()`. If their rank is equal to or higher than the required rank (`GM_RANK_REQUIRED`), they are presented with the option to access the special vendor. Otherwise, they are informed that they do not have permission. + +When the player selects the special vendor option, the `OnGossipSelect` event is triggered, and the special vendor window is sent to the player using `SendListInventory()`. + +This script ensures that only players with the appropriate GM Rank can access the special vendor, providing an extra layer of control and security for server administrators. + +## GetGossipTextId +Returns the gossip text ID from the database that corresponds to the WorldObject's gossip header text for the specific Player. This is useful when creating gossip menus that may change based on certain conditions. + +### Parameters +None + +### Returns +textId: number - The ID of the gossip text from the `npc_text` table in the world database. + +### Example Usage +In this example, we create a gossip menu for a quest giver NPC that has different text depending on whether the player has completed a certain quest or not. + +```typescript +const QUEST_ENTRY = 1234; +const NPC_TEXT_ID_INCOMPLETE = 100; +const NPC_TEXT_ID_COMPLETE = 101; + +const onGossipHello: npc_event_on_gossip_hello = (event: number, player: Player, object: WorldObject) => { + // Check if the player has completed the quest + if (player.HasQuest(QUEST_ENTRY) && player.GetQuestStatus(QUEST_ENTRY) === QuestStatus.QUEST_STATUS_COMPLETE) { + // Set the gossip header text to the "complete" version + object.SetGossipMenuId(NPC_TEXT_ID_COMPLETE); + } else { + // Set the gossip header text to the "incomplete" version + object.SetGossipMenuId(NPC_TEXT_ID_INCOMPLETE); + } + + // Send the gossip menu to the player + player.GossipSendMenu(player.GetGossipTextId(), object.GetGUID()); +}; + +const onGossipSelect: npc_event_on_gossip_select = (event: number, player: Player, object: WorldObject, sender: number, action: number) => { + // Handle gossip option selection here + // ... + + // Close the gossip menu + player.GossipComplete(); +}; + +RegisterNpcEvent(NPC_ENTRY, NpcEvents.NPC_EVENT_ON_GOSSIP_HELLO, (...args) => onGossipHello(...args)); +RegisterNpcEvent(NPC_ENTRY, NpcEvents.NPC_EVENT_ON_GOSSIP_SELECT, (...args) => onGossipSelect(...args)); +``` + +In this script, we first register the `onGossipHello` function to handle the event when a player opens the gossip menu for the NPC. Inside the function, we check if the player has completed the quest with the entry `QUEST_ENTRY`. If they have, we set the gossip header text to the "complete" version using `SetGossipMenuId(NPC_TEXT_ID_COMPLETE)`, otherwise we set it to the "incomplete" version. + +We then send the gossip menu to the player using `player.GossipSendMenu()`, passing in the gossip text ID obtained from `player.GetGossipTextId()` and the GUID of the WorldObject. + +Finally, we register the `onGossipSelect` function to handle the event when the player selects a gossip option. After handling the selected option, we close the gossip menu using `player.GossipComplete()`. + +This example demonstrates how `GetGossipTextId()` can be used in conjunction with other methods like `SetGossipMenuId()` and `GossipSendMenu()` to create dynamic gossip menus that change based on the player's quest progress or other conditions. + +## GetGroup +Returns the player's current group. If the player is not in a group, this method will return `null`. + +### Parameters +None + +### Returns +group: [Group](./group.md) - The player's current group, or `null` if not in a group. + +### Example Usage +This example demonstrates how to check if a player is in a group and perform actions based on their group membership. + +```typescript +const EMBLEM_OF_VALOR_ENTRY = 40752; +const EMBLEM_OF_HEROISM_ENTRY = 40753; +const EMBLEM_OF_CONQUEST_ENTRY = 45624; + +const CheckGroupStatus: player_event_on_login = (event: number, player: Player) => { + const group = player.GetGroup(); + + if (group) { + const groupMembers = group.GetMembers(); + const groupSize = groupMembers.length; + + switch (groupSize) { + case 5: + // Full group, reward Emblem of Conquest + player.AddItem(EMBLEM_OF_CONQUEST_ENTRY, 1); + break; + case 3: + case 4: + // Partial group, reward Emblem of Valor + player.AddItem(EMBLEM_OF_VALOR_ENTRY, 1); + break; + default: + // Solo or duo, reward Emblem of Heroism + player.AddItem(EMBLEM_OF_HEROISM_ENTRY, 1); + break; + } + + player.SendBroadcastMessage("You have been rewarded based on your group size."); + } else { + // Player is not in a group + player.SendBroadcastMessage("You are not currently in a group. Join a group for additional rewards!"); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => CheckGroupStatus(...args)); +``` + +In this example, when a player logs in, the script checks if they are in a group using the `GetGroup()` method. If the player is in a group, it retrieves the group members and group size using the `GetMembers()` method on the returned `Group` object. + +Based on the group size, the script rewards the player with different emblems: +- If the group has 5 members (full group), the player receives an Emblem of Conquest. +- If the group has 3 or 4 members (partial group), the player receives an Emblem of Valor. +- If the player is solo or in a duo, they receive an Emblem of Heroism. + +The player is then sent a broadcast message informing them of the reward based on their group size. + +If the player is not in a group, they receive a message encouraging them to join a group for additional rewards. + +This example showcases how to use the `GetGroup()` method to retrieve the player's group and perform actions based on the group size and membership status. + +## GetGroupInvite +Returns the [Group](./group.md) invitation for the player. If the player does not have a pending group invitation, this method will return `null`. + +### Parameters +This method does not take any parameters. + +### Returns +group: [Group](./group.md) | null - The group invitation for the player, or `null` if the player does not have a pending group invitation. + +### Example Usage +This example demonstrates how to check if a player has a pending group invitation and, if so, automatically accept the invitation if the group leader is on the player's friends list. + +```typescript +const GROUP_INVITE_INTERVAL = 1000; // Check for group invites every 1 second + +const CheckGroupInvite = (player: Player) => { + const invite = player.GetGroupInvite(); + + if (invite !== null) { + const leader = invite.GetLeader(); + + if (leader !== null && player.HasFriend(leader.GetGUIDLow())) { + player.AcceptGroupInvite(); + player.SendBroadcastMessage("Automatically accepted group invitation from friend."); + } + } +} + +const AutoAcceptGroupInvite: player_event_on_update = (event: number, player: Player) => { + if (player.GetMapId() === 0 && !player.IsInGroup()) { + CheckGroupInvite(player); + } +} + +const AutoAcceptGroupInviteRegister: player_event_on_login = (event, player) => { + player.RegisterEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, AutoAcceptGroupInvite, GROUP_INVITE_INTERVAL); +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => AutoAcceptGroupInviteRegister(...args)); +``` + +In this example: +1. The `CheckGroupInvite` function is defined to check if the player has a pending group invitation. If an invitation exists, it checks if the group leader is on the player's friends list using the `HasFriend` method. If the leader is a friend, the invitation is automatically accepted using `AcceptGroupInvite`, and a message is sent to the player. + +2. The `AutoAcceptGroupInvite` function is registered as an `PLAYER_EVENT_ON_UPDATE` event handler. It checks if the player is in the world (map ID 0) and not already in a group before calling the `CheckGroupInvite` function. + +3. The `AutoAcceptGroupInviteRegister` function is registered as a `PLAYER_EVENT_ON_LOGIN` event handler. It registers the `AutoAcceptGroupInvite` function to be called every `GROUP_INVITE_INTERVAL` milliseconds (1 second in this example). + +This script ensures that the player's pending group invitations are checked periodically, and if an invitation is from a friend, it is automatically accepted. + +## GetGuild +Returns the player's guild object, which contains information about the guild the player belongs to. + +### Parameters +None + +### Returns +guild: [Guild](./guild.md) - The player's guild object + +### Example Usage +This example demonstrates how to retrieve a player's guild information and send a message to the guild channel. + +```typescript +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const guild = player.GetGuild(); + + if (guild) { + const guildName = guild.GetName(); + const guildMembers = guild.GetMembers(); + const guildMemberCount = guildMembers.length; + + let onlineMembers = 0; + for (const member of guildMembers) { + if (member.IsOnline()) { + onlineMembers++; + } + } + + const message = `Welcome back to ${guildName}! There are currently ${onlineMembers} out of ${guildMemberCount} members online.`; + guild.SendPacket(message); + + // Add a custom guild log entry + const logEntry = `[${player.GetName()}] logged in.`; + guild.AddGuildEventLogEntry(GuildEventLogTypes.GUILD_EVENT_LOG_LOGIN, player.GetGUID(), logEntry); + } else { + player.SendBroadcastMessage("You are not currently a member of any guild."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +``` + +In this example: +1. When a player logs in, the `OnLogin` event is triggered. +2. We retrieve the player's guild object using `player.GetGuild()`. +3. If the player belongs to a guild: + - We retrieve the guild name using `guild.GetName()`. + - We retrieve the list of guild members using `guild.GetMembers()`. + - We count the total number of guild members. + - We iterate over the guild members and count the number of online members. + - We construct a welcome message including the guild name and the count of online members. + - We send the welcome message to the guild channel using `guild.SendPacket()`. + - We add a custom guild log entry using `guild.AddGuildEventLogEntry()` to record the player's login event. +4. If the player doesn't belong to a guild, we send them a message indicating that they are not currently a member of any guild. + +This example showcases how to retrieve a player's guild information, access guild properties, iterate over guild members, send messages to the guild channel, and add custom guild log entries. + +## GetGuildId +Retrieves the current guild ID of the player. This method will return 0 if the player is not currently in a guild. + +### Parameters +None + +### Returns +guildId: number - The guild ID of the player's current guild. Returns 0 if the player is not in a guild. + +### Example Usage: +Announce when a player from a specific guild logs in, and grant them a special item if they are the guild master. + +```typescript +const GUILD_ID_TO_CHECK = 42; // Replace with the desired guild ID +const SPECIAL_ITEM_ENTRY = 12345; // Replace with the desired item entry + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const playerGuildId = player.GetGuildId(); + + if (playerGuildId === GUILD_ID_TO_CHECK) { + // Announce the player's login + SendWorldMessage(`A member of the guild with ID ${GUILD_ID_TO_CHECK} has logged in: ${player.GetName()}`); + + // Check if the player is the guild master + const guild = player.GetGuild(); + if (guild) { + const guildLeaderGUID = guild.GetLeaderGUID(); + if (player.GetGUID() === guildLeaderGUID) { + // Grant the special item to the guild master + const specialItem = player.AddItem(SPECIAL_ITEM_ENTRY, 1); + if (specialItem) { + player.SendBroadcastMessage("As the guild master, you have received a special item!"); + } else { + player.SendBroadcastMessage("Failed to add the special item to your inventory."); + } + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. We define the desired guild ID (`GUILD_ID_TO_CHECK`) and the special item entry (`SPECIAL_ITEM_ENTRY`) that we want to grant to the guild master. +2. In the `OnLogin` event handler, we retrieve the player's current guild ID using `player.GetGuildId()`. +3. If the player's guild ID matches the desired guild ID, we announce their login to the world using `SendWorldMessage()`. +4. We then check if the player is the guild master by retrieving the guild object using `player.GetGuild()` and comparing the player's GUID with the guild leader's GUID. +5. If the player is the guild master, we attempt to add the special item to their inventory using `player.AddItem()`. +6. We send a broadcast message to the player indicating whether the item was successfully added or not. +7. Finally, we register the `OnLogin` event handler using `RegisterPlayerEvent()` to execute the script when a player logs in. + +This example demonstrates how to use the `GetGuildId()` method to check a player's guild membership and perform actions based on their guild affiliation, such as granting special items or announcing their presence. + +## GetGuildName +Returns the name of the player's current guild as a string. + +### Parameters +None + +### Returns +string - The name of the player's current guild, or an empty string if the player is not in a guild. + +### Example Usage +This example demonstrates how to retrieve a player's guild name and use it to display a custom message when they enter the world. + +```typescript +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const guildName = player.GetGuildName(); + + if (guildName !== "") { + // Player is in a guild + const message = `Welcome back to the guild, ${player.GetName()}! Your guild, ${guildName}, is happy to have you.`; + player.SendBroadcastMessage(message); + + // Log the player's return to the guild + const logMessage = `[Guild Log] ${player.GetName()} has logged in as a member of ${guildName}.`; + console.log(logMessage); + + // Check if the player has the "Guild Master" rank + if (player.GetGuildRank() === 0) { + // Send a special message to the guild master + const gmMessage = "As the Guild Master, you have access to additional commands and features. Use them wisely!"; + player.SendBroadcastMessage(gmMessage); + } + } else { + // Player is not in a guild + const message = `Welcome back, ${player.GetName()}! You are not currently a member of any guild.`; + player.SendBroadcastMessage(message); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. When a player logs in, their guild name is retrieved using `player.GetGuildName()`. +2. If the player is in a guild (i.e., `guildName` is not an empty string): + - A custom welcome message is sent to the player using `player.SendBroadcastMessage()`, including their name and guild name. + - A log message is generated and logged to the console, indicating the player's return to the guild. + - If the player has the "Guild Master" rank (rank 0), an additional special message is sent to them. +3. If the player is not in a guild, a different welcome message is sent, informing them that they are not currently a member of any guild. + +This example showcases how to retrieve a player's guild name, use it in custom messages, perform logging, and handle different scenarios based on the player's guild membership and rank. + +## GetGuildRank +Returns the player's current guild rank as a number. Guild ranks are defined in the `guild_rank` table in the characters database. The rank value corresponds to the `rid` column in the table. + +### Parameters +None + +### Returns +* number - The player's current guild rank. Returns 0 if the player is not in a guild. + +### Example Usage +This example script grants a bonus to players with a specific guild rank when they turn in a quest. + +```typescript +const QUEST_ENTRY = 1234; // Replace with the desired quest entry +const GUILD_RANK_REQUIRED = 2; // Replace with the required guild rank +const BONUS_GOLD = 100; // Replace with the desired bonus gold amount + +const OnQuestComplete: player_event_on_quest_complete = (event: number, player: Player, quest: number) => { + if (quest === QUEST_ENTRY) { + const guildRank = player.GetGuildRank(); + + if (guildRank === GUILD_RANK_REQUIRED) { + const bonusGold = player.GetCoinage() + BONUS_GOLD * 10000; // Convert bonus gold to copper + player.SetCoinage(bonusGold); + + player.SendBroadcastMessage(`You have been awarded a bonus of ${BONUS_GOLD} gold for your guild rank!`); + } + + // Additional quest completion logic... + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => OnQuestComplete(...args)); +``` + +In this example: +1. We define constants for the desired quest entry (`QUEST_ENTRY`), the required guild rank (`GUILD_RANK_REQUIRED`), and the bonus gold amount (`BONUS_GOLD`). +2. When a player completes a quest, the `OnQuestComplete` event is triggered. +3. Inside the event handler, we check if the completed quest matches the desired quest entry. +4. If the quest matches, we retrieve the player's current guild rank using `player.GetGuildRank()`. +5. If the player's guild rank matches the required rank (`GUILD_RANK_REQUIRED`), we proceed to award the bonus. +6. We calculate the bonus gold amount by converting the `BONUS_GOLD` value to copper (multiplying by 10000) and adding it to the player's current coinage using `player.GetCoinage()`. +7. We update the player's coinage with the new bonus amount using `player.SetCoinage()`. +8. Finally, we send a broadcast message to the player informing them about the bonus gold they received for their guild rank. + +This script demonstrates how to use the `GetGuildRank()` method to retrieve the player's guild rank and perform specific actions based on that rank. You can customize the script by modifying the constants and adding additional logic as needed. + +## GetHealthBonusFromStamina +Returns the bonus health the player receives from their total stamina attribute. + +### Parameters +None + +### Returns +healthBonus: number - The amount of bonus health from stamina + +### Example Usage: +Display bonus health in chat from stamina when a player enters the world, and compare it to another player that just leveled up. +```typescript +const PLAYER_NAME_TO_WATCH = "PlayerName"; + +let healthBonusInitial = 0; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + if (player.GetName() === PLAYER_NAME_TO_WATCH) { + healthBonusInitial = player.GetHealthBonusFromStamina(); + player.SendBroadcastMessage(`Initial health bonus from stamina: ${healthBonusInitial}`); + } +}; + +const OnLevelChanged: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + if (player.GetName() === PLAYER_NAME_TO_WATCH) { + const healthBonusCurrent = player.GetHealthBonusFromStamina(); + const healthBonusDifference = healthBonusCurrent - healthBonusInitial; + player.SendBroadcastMessage(`Health bonus from stamina at level ${player.GetLevel()}: ${healthBonusCurrent}`); + player.SendBroadcastMessage(`Health bonus difference from level ${oldLevel} to ${player.GetLevel()}: ${healthBonusDifference}`); + healthBonusInitial = healthBonusCurrent; + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => OnLevelChanged(...args)); +``` +In this example: +1. We define a constant `PLAYER_NAME_TO_WATCH` to specify the player we want to monitor. +2. We initialize a variable `healthBonusInitial` to store the initial health bonus from stamina. +3. In the `OnLogin` event, we check if the logged-in player's name matches `PLAYER_NAME_TO_WATCH`. + - If it does, we calculate the initial health bonus using `GetHealthBonusFromStamina()` and store it in `healthBonusInitial`. + - We send a broadcast message to the player displaying their initial health bonus from stamina. +4. In the `OnLevelChanged` event, we check if the leveled-up player's name matches `PLAYER_NAME_TO_WATCH`. + - If it does, we calculate the current health bonus using `GetHealthBonusFromStamina()` and store it in `healthBonusCurrent`. + - We calculate the difference between the current and initial health bonus and store it in `healthBonusDifference`. + - We send broadcast messages to the player displaying their current health bonus and the difference from the previous level. + - We update `healthBonusInitial` with the current health bonus for the next level comparison. +5. We register the `OnLogin` and `OnLevelChanged` event handlers using `RegisterPlayerEvent`. + +This script allows us to monitor a specific player's health bonus from stamina when they log in and each time they level up, providing insights into how their stamina affects their health bonus throughout their progression. + +## GetHonorLastWeekStandingPos +Returns the player's standing position from the previous week's honor calculation. + +### Parameters +None + +### Returns +* `number` - The player's standing position from the previous week. + +### Example Usage +This example retrieves the player's honor standing from the previous week and grants them bonus honor points based on their performance. + +```typescript +const HONOR_BONUS_THRESHOLD = 10; // Top 10 players receive bonus +const HONOR_BONUS_AMOUNT = 500; // Bonus honor points + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const lastWeekPosition = player.GetHonorLastWeekStandingPos(); + + if (lastWeekPosition <= HONOR_BONUS_THRESHOLD) { + const bonusHonor = HONOR_BONUS_AMOUNT; + player.ModifyHonorPoints(bonusHonor); + + // Send a message to the player + const message = `Congratulations! Based on your outstanding performance last week, you have been awarded ${bonusHonor} bonus honor points!`; + player.SendBroadcastMessage(message); + + // Log the bonus honor reward + const logMessage = `Player ${player.GetName()} received ${bonusHonor} bonus honor points for placing ${lastWeekPosition} in last week's honor standings.`; + console.log(logMessage); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. We define constants for the bonus honor threshold (top 10 players) and the bonus honor amount (500 points). + +2. Inside the `OnLogin` event handler, we retrieve the player's standing position from the previous week using `GetHonorLastWeekStandingPos()`. + +3. We check if the player's position is within the bonus threshold. If so, we proceed to grant them the bonus honor points. + +4. We modify the player's honor points using `ModifyHonorPoints()` with the bonus amount. + +5. We send a congratulatory message to the player using `SendBroadcastMessage()`, informing them about the bonus honor points they received. + +6. We log the bonus honor reward details, including the player's name, bonus amount, and their standing position from the previous week. + +This script rewards players who performed exceptionally well in the previous week's honor calculations, providing them with bonus honor points as an incentive for their achievements. + +## GetHonorPoints +Retrieves the current total of Honor Points the player has acquired. + +### Parameters +This method does not take any parameters. + +### Returns +number - The amount of honor points the player currently has. + +### Example Usage +This example grants bonus honor points to the player based on their level each time they kill a creature, as long as they are at least level 70. + +```typescript +const BONUS_HONOR_POINTS_PERCENT = 0.05; +const MIN_LEVEL_FOR_BONUS_HONOR = 70; + +const CreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + const playerLevel = player.GetLevel(); + + if (playerLevel >= MIN_LEVEL_FOR_BONUS_HONOR) { + const currentHonorPoints = player.GetHonorPoints(); + const bonusHonorPoints = Math.floor(currentHonorPoints * BONUS_HONOR_POINTS_PERCENT); + + if (bonusHonorPoints > 0) { + player.ModifyHonorPoints(bonusHonorPoints); + player.SendNotification(`You have been awarded ${bonusHonorPoints} bonus honor points!`); + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => CreatureKill(...args)); +``` + +In this script: +1. We define constants for the bonus honor points percentage (5% in this case) and the minimum player level required to receive the bonus. +2. We create a handler function for the `PLAYER_EVENT_ON_KILL_CREATURE` event. +3. Inside the handler, we first retrieve the player's current level using `player.GetLevel()`. +4. We check if the player's level is greater than or equal to the minimum level required for the bonus. +5. If the player meets the level requirement, we retrieve their current honor points using `player.GetHonorPoints()`. +6. We calculate the bonus honor points by multiplying the current honor points by the bonus percentage and rounding down to the nearest integer using `Math.floor()`. +7. If the bonus honor points are greater than 0, we modify the player's honor points using `player.ModifyHonorPoints(bonusHonorPoints)` to add the bonus points. +8. Finally, we send a notification to the player informing them of the bonus honor points they received using `player.SendNotification()`. + +This script encourages higher-level players to engage in creature kills by rewarding them with bonus honor points based on their existing honor points. The `GetHonorPoints()` method is used to retrieve the player's current honor points, which is then used to calculate the bonus honor points. + +## GetHonorStoredKills +Returns the number of honor kills the player has accumulated. Honor kills are earned by killing players of the opposite faction in World PVP zones, Battlegrounds, and Arenas. + +### Parameters +* honorable: boolean (optional) - If set to true, it will only return honorable kills. If set to false or not provided, it will return all kills (honorable and dishonorable). + +### Returns +* number - The number of honor kills the player has accumulated. + +### Example Usage +This script will reward players with bonus honor points based on their total honor kills when they log in. + +```typescript +const HONOR_KILLS_THRESHOLD = 100; +const BONUS_HONOR_POINTS = 500; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const totalKills = player.GetHonorStoredKills(); + const honorableKills = player.GetHonorStoredKills(true); + const dishonorableKills = totalKills - honorableKills; + + player.SendBroadcastMessage(`Welcome back, ${player.GetName()}!`); + player.SendBroadcastMessage(`You have a total of ${totalKills} PVP kills, including ${honorableKills} honorable kills and ${dishonorableKills} dishonorable kills.`); + + if (totalKills >= HONOR_KILLS_THRESHOLD) { + player.ModifyHonorPoints(BONUS_HONOR_POINTS); + player.SendBroadcastMessage(`Congratulations! You have been awarded ${BONUS_HONOR_POINTS} bonus honor points for reaching ${HONOR_KILLS_THRESHOLD} total PVP kills!`); + } else { + const killsRemaining = HONOR_KILLS_THRESHOLD - totalKills; + player.SendBroadcastMessage(`You need ${killsRemaining} more PVP kills to receive ${BONUS_HONOR_POINTS} bonus honor points. Keep up the good work!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example, when a player logs in, the script retrieves their total honor kills and breaks it down into honorable and dishonorable kills. It then sends a welcome message to the player with their kill statistics. + +If the player has reached a certain threshold of total PVP kills (defined by `HONOR_KILLS_THRESHOLD`), they are awarded a bonus amount of honor points (defined by `BONUS_HONOR_POINTS`). If they haven't reached the threshold yet, the script informs the player of how many more kills they need to receive the bonus. + +This script encourages players to participate in PVP activities and rewards them for their achievements, providing an extra incentive to engage in World PVP, Battlegrounds, and Arenas. + +## GetInGameTime +Returns the total time in seconds that the player has spent in-game on this character. + +### Parameters +None + +### Returns +* number - The total in-game time in seconds. + +### Example Usage +This example tracks the amount of time a player spends in a specific map or zone and rewards them with bonus gold and experience if they spend a certain amount of time there. + +```typescript +const ZONE_ELWYNN_FOREST = 12; +const BONUS_GOLD = 100; +const BONUS_XP = 1000; +const REQUIRED_TIME = 3600; // 1 hour in seconds + +const playerZoneTimes: Map = new Map(); + +const UpdateZoneTime = (event: number, player: Player, newZone: number, newArea: number) => { + const playerId = player.GetGUID(); + const currentTime = player.GetInGameTime(); + + if (playerZoneTimes.has(playerId)) { + const previousTime = playerZoneTimes.get(playerId); + const timeSpent = currentTime - previousTime; + + if (newZone === ZONE_ELWYNN_FOREST) { + const totalTimeSpent = player.GetData("ElwynnForestTime", 0) + timeSpent; + player.SetData("ElwynnForestTime", totalTimeSpent); + + if (totalTimeSpent >= REQUIRED_TIME) { + player.ModifyMoney(BONUS_GOLD); + player.GiveXP(BONUS_XP); + player.SendBroadcastMessage(`You have spent ${REQUIRED_TIME / 3600} hour(s) in Elwynn Forest and received a bonus reward!`); + player.SetData("ElwynnForestTime", 0); + } + } + } + + playerZoneTimes.set(playerId, currentTime); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE_ZONE, UpdateZoneTime); +``` + +In this example: +1. We define constants for the zone ID of Elwynn Forest, the bonus gold and experience amounts, and the required time spent in seconds. +2. We create a `playerZoneTimes` map to store the last recorded in-game time for each player. +3. In the `UpdateZoneTime` function, we calculate the time spent in the previous zone by subtracting the last recorded time from the current in-game time using `player.GetInGameTime()`. +4. If the player is in Elwynn Forest, we add the time spent to their total time spent in that zone, which is stored using `player.SetData()`. +5. If the total time spent in Elwynn Forest reaches the required time, we reward the player with bonus gold using `player.ModifyMoney()` and bonus experience using `player.GiveXP()`, and reset their total time spent. +6. Finally, we update the last recorded in-game time for the player in the `playerZoneTimes` map. + +This example demonstrates how `GetInGameTime()` can be used to track and reward player activity based on the time they spend in specific zones or areas of the game world. + +## GetItemByEntry +Retrieves an item from the player's inventory, bank, or currently equipped items by the item's entry ID. + +### Parameters +* entryId: number - The entry ID of the item to retrieve. + +### Returns +* [Item](./item.md) - The first item found with the specified entry ID, or null if no item is found. + +### Example Usage +This example demonstrates how to retrieve an item from the player's inventory by its entry ID and check if the player has a specific item equipped. + +```typescript +const ITEM_HEARTHSTONE = 6948; +const ITEM_FISHING_POLE = 6256; + +function CheckPlayerItems(player: Player) { + // Get the player's hearthstone + const hearthstone = player.GetItemByEntry(ITEM_HEARTHSTONE); + if (hearthstone) { + player.SendBroadcastMessage("You have a hearthstone in your inventory!"); + } else { + player.SendBroadcastMessage("You don't have a hearthstone. You should get one!"); + } + + // Check if the player has a fishing pole equipped + const fishingPole = player.GetItemByEntry(ITEM_FISHING_POLE); + if (fishingPole && fishingPole.IsEquipped()) { + player.SendBroadcastMessage("You have a fishing pole equipped. Ready to catch some fish!"); + } else { + player.SendBroadcastMessage("You don't have a fishing pole equipped. Equip one to start fishing!"); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (event, player) => { + CheckPlayerItems(player); +}); +``` + +In this example: +1. We define constants for the entry IDs of a hearthstone and a fishing pole. +2. The `CheckPlayerItems` function is called when a player logs in. +3. We use `player.GetItemByEntry(ITEM_HEARTHSTONE)` to retrieve the player's hearthstone from their inventory, bank, or equipped items. +4. If the hearthstone is found, we send a message to the player indicating they have one. Otherwise, we suggest they should get one. +5. We use `player.GetItemByEntry(ITEM_FISHING_POLE)` to check if the player has a fishing pole. +6. If a fishing pole is found, we check if it's currently equipped using the `IsEquipped()` method. +7. If the fishing pole is equipped, we send a message to the player indicating they are ready to fish. Otherwise, we suggest they equip a fishing pole to start fishing. + +This example showcases how to use the `GetItemByEntry` method to retrieve items from a player's inventory and perform specific actions based on the presence or state of those items. + +## GetItemByGUID +Retrieves an item from the player's inventory, bank, or currently equipped items using the specified GUID (Globally Unique Identifier). + +### Parameters +* guid: number - The GUID of the item to retrieve. + +### Returns +* [Item](./item.md) - The item matching the specified GUID, or null if no item is found. + +### Example Usage +This example demonstrates how to retrieve an item from a player's inventory using its GUID and check if it's a quest item. If the item is found and it is a quest item, it will be destroyed and the player will receive a message indicating that the quest item was removed. + +```typescript +const QUEST_ITEM_GUID = 123456; // Replace with the actual GUID of the quest item + +const CheckQuestItem: player_event_on_login = (event: number, player: Player) => { + const questItem = player.GetItemByGUID(QUEST_ITEM_GUID); + + if (questItem) { + if (questItem.IsQuestItem()) { + const itemName = questItem.GetName(); + questItem.RemoveFromWorld(); + player.SendNotification(`The quest item '${itemName}' has been removed from your inventory.`); + } + } else { + player.SendNotification("The specified quest item was not found in your inventory."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => CheckQuestItem(...args)); +``` + +In this example, when a player logs in, the script retrieves the item with the specified GUID using `GetItemByGUID()`. If the item is found (`questItem` is not null), it checks if the item is a quest item using the `IsQuestItem()` method. If it is a quest item, the script removes the item from the world using `RemoveFromWorld()` and sends a notification to the player indicating that the quest item has been removed. If the item is not found, the player receives a message stating that the specified quest item was not found in their inventory. + +This example showcases how to use `GetItemByGUID()` to retrieve an item from a player's inventory and perform actions based on the item's properties, such as checking if it's a quest item and removing it if necessary. + +## GetItemByPos +Retrieves an item from the player's inventory based on the specified bag and slot. + +### Parameters +* bag: number - The bag identifier (see below for possible values) +* slot: number - The slot within the specified bag + +### Returns +[Item](./item.md) - The item found at the specified bag and slot, or null if no item is found. + +### Possible Bag and Slot Combinations +```typescript +bag = 255 + slots 0-18: Equipment + slots 19-22: Equipped bag slots + slots 23-38: Backpack + slots 39-66: Bank main slots + slots 67-74: Bank bag slots + slots 86-117: Keyring + +bag = 19-22 + slots 0-35: Equipped bags + +bag = 67-74 + slots 0-35: Bank bags +``` + +### Example Usage +```typescript +const BACKPACK_BAG = 255; +const BACKPACK_SLOT_START = 23; +const BACKPACK_SLOT_END = 38; + +const SearchBackpackForItem: player_event_On_Login = (event: number, player: Player) => { + let itemCount = 0; + + for (let slot = BACKPACK_SLOT_START; slot <= BACKPACK_SLOT_END; slot++) { + const item = player.GetItemByPos(BACKPACK_BAG, slot); + + if (item) { + const [name, entry] = [item.GetName(), item.GetEntry()]; + SendSystemMessage(player, `Found item: ${name} (Entry: ${entry}) in backpack slot ${slot}`); + itemCount++; + } + } + + SendSystemMessage(player, `Total items found in backpack: ${itemCount}`); + + const EQUIPPED_BAG_START = 19; + const EQUIPPED_BAG_END = 22; + + for (let bag = EQUIPPED_BAG_START; bag <= EQUIPPED_BAG_END; bag++) { + for (let slot = 0; slot < 36; slot++) { + const item = player.GetItemByPos(bag, slot); + + if (item) { + const [name, entry] = [item.GetName(), item.GetEntry()]; + SendSystemMessage(player, `Found item: ${name} (Entry: ${entry}) in equipped bag ${bag}, slot ${slot}`); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => SearchBackpackForItem(...args)); +``` + +In this example, when a player logs in, the script searches their backpack (bags 255, slots 23-38) for any items. It sends a message to the player for each item found, including the item's name, entry, and slot number. It also keeps track of the total number of items found in the backpack. + +Additionally, it searches the player's equipped bags (bags 19-22, slots 0-35) for any items and sends a message to the player for each item found, specifying the bag and slot numbers. + +This script demonstrates how to use the `GetItemByPos` method to retrieve items from different bags and slots in a player's inventory, and how to extract information about the found items. + +## GetItemCount +Returns the amount of a specific item that the player has in their inventory or bank. + +### Parameters +* entry: number - The item entry to check for +* checkinBank: boolean (optional) - If set to true, the method will also check the player's bank for the item. Default is false. + +### Returns +* number - The total amount of the specified item that the player has. + +### Example Usage +This example script will check if the player has enough materials to craft an item, and if so, consume the materials and give the player the crafted item. + +```typescript +const MATERIAL_1_ENTRY = 12345; +const MATERIAL_1_COUNT = 5; +const MATERIAL_2_ENTRY = 67890; +const MATERIAL_2_COUNT = 3; +const CRAFTED_ITEM_ENTRY = 54321; + +const CraftItem: player_event_on_gossip_select = (event: number, player: Player, object: WorldObject, sender: number, intid: number, code: string, menu_id: number) => { + const hasMaterial1 = player.GetItemCount(MATERIAL_1_ENTRY) >= MATERIAL_1_COUNT; + const hasMaterial2 = player.GetItemCount(MATERIAL_2_ENTRY) >= MATERIAL_2_COUNT; + + if (hasMaterial1 && hasMaterial2) { + player.RemoveItem(MATERIAL_1_ENTRY, MATERIAL_1_COUNT); + player.RemoveItem(MATERIAL_2_ENTRY, MATERIAL_2_COUNT); + + const craftedItem = player.AddItem(CRAFTED_ITEM_ENTRY, 1); + + if (craftedItem) { + player.SendBroadcastMessage("You have crafted the item successfully!"); + } else { + // If the player's inventory is full, return the materials + player.AddItem(MATERIAL_1_ENTRY, MATERIAL_1_COUNT); + player.AddItem(MATERIAL_2_ENTRY, MATERIAL_2_COUNT); + player.SendBroadcastMessage("Your inventory is full. Unable to craft the item."); + } + } else { + player.SendBroadcastMessage("You don't have enough materials to craft this item."); + } + + player.CloseGossip(); +}; + +RegisterPlayerGossipEvent(12345, 1, (...args) => CraftItem(...args)); +``` + +In this example, when the player selects a specific gossip option (with the menu ID 12345 and option ID 1), the script checks if the player has the required materials in their inventory using `GetItemCount()`. If the player has enough materials, they are consumed using `RemoveItem()`, and the crafted item is added to the player's inventory using `AddItem()`. If the player doesn't have enough space in their inventory, the materials are returned to the player. Finally, appropriate messages are sent to the player using `SendBroadcastMessage()`, and the gossip window is closed with `CloseGossip()`. + +## GetLatency +Returns the current latency of the player in milliseconds. This latency represents the delay between the player's client and the server, indicating the responsiveness of the connection. + +### Parameters +This method does not take any parameters. + +### Returns +* number: The current latency of the player in milliseconds. + +### Example Usage +Here's an example of how to use the `GetLatency` method to monitor player latency and take action based on the latency value: + +```typescript +const LATENCY_THRESHOLD = 300; // Latency threshold in milliseconds + +const CheckPlayerLatency: player_event_on_update = (event: number, player: Player, diff: number) => { + const latency = player.GetLatency(); + + if (latency > LATENCY_THRESHOLD) { + // Player's latency exceeds the threshold + player.SendBroadcastMessage(`Warning: High latency detected (${latency} ms)`); + + // Log the high latency event + const playerName = player.GetName(); + const playerGUID = player.GetGUID(); + const latencyLog = `[Latency Alert] Player: ${playerName} (GUID: ${playerGUID}), Latency: ${latency} ms`; + PrintInfo(latencyLog); + + // Teleport the player to a safe location if the latency is extremely high + if (latency > LATENCY_THRESHOLD * 2) { + const safeLoc = new WorldLocation(0, -8833.37, 628.62, 94.00, 1.06); + player.Teleport(safeLoc); + player.SendBroadcastMessage("You have been teleported to a safe location due to extremely high latency."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => CheckPlayerLatency(...args)); +``` + +In this example: +1. We define a `LATENCY_THRESHOLD` constant to set the maximum acceptable latency value in milliseconds. + +2. We register a player event handler for the `PLAYER_EVENT_ON_UPDATE` event, which is triggered periodically for each player. + +3. Inside the event handler, we retrieve the player's current latency using the `GetLatency` method. + +4. We compare the latency value with the defined threshold. If the latency exceeds the threshold, we take the following actions: + - Send a warning message to the player, informing them about the high latency. + - Log the high latency event, including the player's name, GUID, and the latency value, using `PrintInfo`. + - If the latency is extremely high (e.g., more than double the threshold), we teleport the player to a safe location using the `Teleport` method and send them a message indicating the reason for the teleportation. + +5. The event handler is registered using `RegisterPlayerEvent` to be triggered on each player update. + +This example demonstrates how to monitor player latency, provide warnings, log high latency events, and take preventive actions (such as teleportation) when the latency exceeds certain thresholds. You can customize the latency threshold, safe location, and actions taken based on your specific requirements. + +## GetLevelPlayedTime +Returns the total time in seconds that the player has played at their current level. + +### Parameters +None + +### Returns +seconds: number - The total time played at the current level in seconds. + +### Example Usage +This example tracks the time a player spends at each level and grants bonus gold and experience when they reach certain play time milestones at their current level. + +```typescript +const BONUS_INTERVALS = [3600, 7200, 10800, 14400]; // 1 hour, 2 hours, 3 hours, 4 hours +const BONUS_GOLD = [100, 250, 500, 1000]; +const BONUS_XP = [5000, 10000, 15000, 20000]; + +let playerLevelTimes: Map = new Map(); + +const SaveLevelPlayTime = (event: number, player: Player): void => { + const playerGuid = player.GetGUIDLow(); + const currentLevel = player.GetLevel(); + const playedTime = player.GetLevelPlayedTime(); + + playerLevelTimes.set(playerGuid, playedTime); +}; + +const CheckLevelPlayTime = (event: number, player: Player): void => { + const playerGuid = player.GetGUIDLow(); + const currentLevel = player.GetLevel(); + const playedTime = player.GetLevelPlayedTime(); + + if (!playerLevelTimes.has(playerGuid)) { + playerLevelTimes.set(playerGuid, playedTime); + return; + } + + const lastPlayedTime = playerLevelTimes.get(playerGuid); + const timeDiff = playedTime - lastPlayedTime; + + for (let i = 0; i < BONUS_INTERVALS.length; i++) { + if (timeDiff >= BONUS_INTERVALS[i]) { + player.ModifyMoney(BONUS_GOLD[i]); + player.GiveXP(BONUS_XP[i], null); + player.SendBroadcastMessage(`You have been rewarded for playing ${BONUS_INTERVALS[i] / 3600} hours at level ${currentLevel}!`); + } + } + + playerLevelTimes.set(playerGuid, playedTime); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SAVE, (...args) => SaveLevelPlayTime(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => CheckLevelPlayTime(...args)); +``` + +In this script: +1. We define arrays `BONUS_INTERVALS`, `BONUS_GOLD`, and `BONUS_XP` to store the play time milestones and their corresponding bonus rewards. +2. We create a `Map` called `playerLevelTimes` to store each player's played time at their current level, using the player's GUID as the key. +3. In the `SaveLevelPlayTime` function, we save the player's current level played time whenever their character is saved. +4. In the `CheckLevelPlayTime` function, which is triggered periodically (e.g., on player update), we calculate the difference between the current played time and the last recorded played time. +5. We loop through the `BONUS_INTERVALS` array and check if the time difference exceeds any of the milestone intervals. +6. If a milestone is reached, we grant the player bonus gold and experience using `ModifyMoney` and `GiveXP`, and send them a congratulatory message using `SendBroadcastMessage`. +7. Finally, we update the player's last recorded played time in the `playerLevelTimes` map. + +This script encourages players to spend more time at each level by rewarding them for reaching certain play time milestones, promoting a more immersive and engaging leveling experience. + +## GetLifetimeKills +Returns the total number of lifetime honorable kills the player has acquired. This is a cumulative amount and represents the total number of honorable kills the player has gained throughout their lifetime. + +### Parameters +None + +### Returns +* number - The total lifetime honorable kills of the player. + +### Example Usage +This example will keep track of a player's lifetime kills and grant rewards based on reaching certain milestones. + +```typescript +const KILLS_MILESTONE_1 = 100; +const KILLS_MILESTONE_2 = 500; +const KILLS_MILESTONE_3 = 1000; + +const REWARD_ITEM_1 = 12345; +const REWARD_ITEM_2 = 23456; +const REWARD_ITEM_3 = 34567; + +let playerKills: Map = new Map(); + +const OnPlayerKill: player_event_on_kill_player = (event: number, killer: Player, killed: Player) => { + if (!playerKills.has(killer.GetGUID())) { + playerKills.set(killer.GetGUID(), 0); + } + + playerKills.set(killer.GetGUID(), playerKills.get(killer.GetGUID()) + 1); + const totalKills = killer.GetLifetimeKills(); + + switch (totalKills) { + case KILLS_MILESTONE_1: + killer.AddItem(REWARD_ITEM_1, 1); + killer.SendBroadcastMessage(`Congratulations on reaching ${KILLS_MILESTONE_1} lifetime honorable kills! You have been rewarded with a special item.`); + break; + case KILLS_MILESTONE_2: + killer.AddItem(REWARD_ITEM_2, 1); + killer.SendBroadcastMessage(`Congratulations on reaching ${KILLS_MILESTONE_2} lifetime honorable kills! You have been rewarded with a special item.`); + break; + case KILLS_MILESTONE_3: + killer.AddItem(REWARD_ITEM_3, 1); + killer.SendBroadcastMessage(`Congratulations on reaching ${KILLS_MILESTONE_3} lifetime honorable kills! You have been rewarded with a special item.`); + break; + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_PLAYER, (...args) => OnPlayerKill(...args)); +``` + +This script keeps track of a player's lifetime honorable kills using a Map to store the kill counts. Whenever a player kills another player, their kill count is incremented, and the total lifetime kills are retrieved using `GetLifetimeKills()`. + +The script checks if the total kills have reached certain milestones (100, 500, and 1000 in this example). If a milestone is reached, the player is rewarded with a special item using `AddItem()` and receives a congratulatory broadcast message. + +By using `GetLifetimeKills()`, you can easily track and reward players based on their cumulative honorable kills throughout their entire gameplay experience. + +## GetManaBonusFromIntellect +This method returns the bonus mana points a player receives based on their total intellect attribute. This takes into account any intellect the player receives from base stats, items, buffs, or talents. + +### Parameters +This method does not take any parameters. + +### Returns +number - The total bonus mana points the player receives from their intellect stat. + +### Example Usage +This example demonstrates how to retrieve a player's bonus mana from intellect and display it as a chat message visible only to the player. This also calculates the player's total mana points by adding their base mana and bonus mana together. + +```typescript +function DisplayPlayerManaInfo(player: Player): void { + const bonusMana = player.GetManaBonusFromIntellect(); + const baseMana = player.GetMaxPower(PowerType.POWER_MANA); + const totalMana = baseMana + bonusMana; + + player.SendNotification(`Base Mana: ${baseMana}`); + player.SendNotification(`Bonus Mana from Intellect: ${bonusMana}`); + player.SendNotification(`Total Mana: ${totalMana}`); +} + +function OnLogin(event: PlayerEvents, player: Player): void { + DisplayPlayerManaInfo(player); +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +``` + +In this example: +1. The `DisplayPlayerManaInfo` function is defined, which takes a `Player` object as a parameter. +2. Inside the function, `GetManaBonusFromIntellect()` is called on the player object to retrieve the bonus mana points from intellect. +3. `GetMaxPower(PowerType.POWER_MANA)` is used to retrieve the player's base mana points. +4. The total mana points are calculated by adding the base mana and bonus mana. +5. The base mana, bonus mana from intellect, and total mana are displayed to the player using `SendNotification`. +6. The `OnLogin` function is defined as an event handler for the `PLAYER_EVENT_ON_LOGIN` event. +7. Inside the `OnLogin` function, `DisplayPlayerManaInfo` is called, passing the `player` object. +8. `RegisterPlayerEvent` is used to register the `OnLogin` function as the event handler for the `PLAYER_EVENT_ON_LOGIN` event. + +When a player logs in, the `OnLogin` event handler will be triggered, and the `DisplayPlayerManaInfo` function will be called. This will display the player's base mana, bonus mana from intellect, and total mana as chat messages visible only to the player. + +This example demonstrates how to retrieve and utilize the bonus mana points a player receives from their intellect stat, and how to display this information to the player when they log in. + +## GetMaxSkillValue +Returns the maximum value for a specified skill based on the player's current level, class, and race. + +### Parameters +* skill: number - The ID of the skill to retrieve the maximum value for. + +### Returns +* number - The maximum skill value achievable by the player. + +### Example Usage +Suppose you want to create a script that rewards players with bonus skill points in their primary professions when they reach certain levels. Here's an example of how you can use the `GetMaxSkillValue` method to accomplish this: + +```typescript +const SKILL_HERBALISM = 182; +const SKILL_MINING = 186; +const SKILL_SKINNING = 393; + +const LevelUpReward: player_event_on_level_change = (event: number, player: Player, oldLevel: number): void => { + const newLevel = player.GetLevel(); + const className = player.GetClass(); + + let primarySkill = 0; + + // Determine the player's primary profession skill based on their class + if (className === Classes.CLASS_DRUID || className === Classes.CLASS_ROGUE) { + primarySkill = SKILL_HERBALISM; + } else if (className === Classes.CLASS_WARRIOR || className === Classes.CLASS_PALADIN) { + primarySkill = SKILL_MINING; + } else if (className === Classes.CLASS_HUNTER) { + primarySkill = SKILL_SKINNING; + } + + // Check if the player has reached a milestone level + if (newLevel === 20 || newLevel === 40 || newLevel === 60) { + const currentSkill = player.GetSkillValue(primarySkill); + const maxSkill = player.GetMaxSkillValue(primarySkill); + + // Calculate the bonus skill points to award + const bonusPoints = Math.floor((maxSkill - currentSkill) * 0.1); + + if (bonusPoints > 0) { + player.AdvanceSkill(primarySkill, bonusPoints); + player.SendBroadcastMessage(`Congratulations! You have been awarded ${bonusPoints} bonus skill points in ${GetSkillName(primarySkill)}.`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => LevelUpReward(...args)); +``` + +In this example, the script determines the player's primary profession skill based on their class. When the player reaches levels 20, 40, or 60, it calculates the maximum skill value using `GetMaxSkillValue` and the player's current skill value using `GetSkillValue`. If the player's current skill is below the maximum, the script awards bonus skill points equal to 10% of the difference between the maximum and current skill values. Finally, it informs the player of the bonus points they received using `SendBroadcastMessage`. + +This script encourages players to keep their primary profession skills up to date as they level up, rewarding them with bonus points at key milestones. + +## GetNextRandomRaidMember +Returns a random raid member within the specified radius of the player. This can be useful for mechanics that require selecting a random player in the raid, such as applying a debuff or selecting a player to perform a specific task. + +### Parameters +* radius: number - The maximum distance in yards to search for a random raid member. + +### Returns +* [Player](./player.md) - A random raid member within the specified radius, or nil if no raid member is found. + +### Example Usage +In this example, we create a script for a boss encounter where the boss periodically selects a random raid member within 30 yards to apply a debuff called "Curse of Doom". The selected player must run away from the raid to avoid spreading the curse to other players. + +```typescript +const SPELL_CURSE_OF_DOOM = 12345; +const CURSE_OF_DOOM_RADIUS = 30; +const CURSE_OF_DOOM_DURATION = 10; + +const ApplyCurseOfDoom = (boss: Creature): void => { + const cursedPlayer = boss.GetNextRandomRaidMember(CURSE_OF_DOOM_RADIUS); + if (cursedPlayer) { + boss.CastSpell(cursedPlayer, SPELL_CURSE_OF_DOOM, true); + cursedPlayer.AddAura(SPELL_CURSE_OF_DOOM, CURSE_OF_DOOM_DURATION); + cursedPlayer.SendBroadcastMessage("You have been cursed with the Curse of Doom! Run away from the raid!"); + boss.SendUnitYell("${cursedPlayer.GetName()} has been cursed with the Curse of Doom!", 0); + } +}; + +const OnBossEnterCombat = (event: number, boss: Creature, target: Unit): void => { + boss.RegisterEvent(ApplyCurseOfDoom, 15000, 0); +}; + +const OnBossLeaveCombat = (event: number, boss: Creature): void => { + boss.RemoveEvents(); +}; + +const OnBossDied = (event: number, boss: Creature, killer: Unit): void => { + boss.RemoveEvents(); +}; + +RegisterCreatureEvent(12345, CreatureEvents.CREATURE_EVENT_ON_ENTER_COMBAT, OnBossEnterCombat); +RegisterCreatureEvent(12345, CreatureEvents.CREATURE_EVENT_ON_LEAVE_COMBAT, OnBossLeaveCombat); +RegisterCreatureEvent(12345, CreatureEvents.CREATURE_EVENT_ON_DIED, OnBossDied); +``` + +In this script, we register event handlers for the boss's enter combat, leave combat, and died events. When the boss enters combat, we register a repeating event that calls the `ApplyCurseOfDoom` function every 15 seconds. + +Inside the `ApplyCurseOfDoom` function, we use `GetNextRandomRaidMember` to select a random player within 30 yards of the boss. If a player is found, we cast the "Curse of Doom" spell on them, add an aura to the player with a duration of 10 seconds, send a broadcast message to the affected player, and make the boss yell to announce who has been cursed. + +When the boss leaves combat or dies, we remove all registered events to clean up the script. + +## GetOriginalGroup +Returns the original [Group](./group.md) object that the player was in before entering an instance. This can be useful for returning a player to their original group after completing an instance or a battleground. + +### Parameters +None + +### Returns +[Group](./group.md) - The original group the player was in before entering an instance. + +### Example Usage +Here's an example of how to use `GetOriginalGroup()` to return a player to their original group after completing an instance: + +```typescript +const OnPlayerCompleteInstance: player_event_on_complete_instance = (event: number, player: Player): void => { + const originalGroup = player.GetOriginalGroup(); + + if (originalGroup) { + // Check if the player is currently in a group + const currentGroup = player.GetGroup(); + if (currentGroup) { + // Leave the current group + player.RemoveFromGroup(); + } + + // Invite the player back to their original group + originalGroup.AddMember(player); + + // Send a message to the player + player.SendBroadcastMessage("You have been returned to your original group."); + } else { + // If the player had no original group, send them a message + player.SendBroadcastMessage("You were not in a group before entering the instance."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMPLETE_INSTANCE, (...args) => OnPlayerCompleteInstance(...args)); +``` + +In this example: + +1. When a player completes an instance, the `OnPlayerCompleteInstance` event is triggered. +2. We retrieve the player's original group using `GetOriginalGroup()`. +3. If the player had an original group: + - We check if the player is currently in a group using `GetGroup()`. + - If the player is in a group, we remove them from the current group using `RemoveFromGroup()`. + - We invite the player back to their original group using `AddMember()`. + - We send a message to the player informing them that they have been returned to their original group. +4. If the player had no original group, we send them a message indicating that they were not in a group before entering the instance. + +This script ensures that players are automatically returned to their original groups after completing an instance, providing a seamless experience for players who frequently run instances with different groups. + +## GetOriginalSubGroup +Returns the player's original sub group. This is useful for determining which sub group the player was in before any changes were made to the raid group. + +### Parameters +None + +### Returns +number - The original sub group of the player. + +### Example Usage +This example demonstrates how to use `GetOriginalSubGroup()` to determine if a player has been moved to a different sub group and then move them back to their original sub group. + +```typescript +const HEALER_CLASS_MASK = 2; + +const CheckSubGroup: player_event_on_update = (event: number, player: Player, diff: number) => { + const currentSubGroup = player.GetSubGroup(); + const originalSubGroup = player.GetOriginalSubGroup(); + + if (currentSubGroup !== originalSubGroup) { + const className = player.GetClass(); + const isHealer = (HEALER_CLASS_MASK & (1 << (className - 1))) !== 0; + + if (isHealer) { + // If the player is a healer, move them back to their original sub group + player.SetSubGroup(originalSubGroup); + player.SendBroadcastMessage("You have been moved back to your original sub group."); + } else { + // If the player is not a healer, send a message to the raid leader + const raidLeader = player.GetRaidLeader(); + if (raidLeader) { + raidLeader.SendBroadcastMessage(`${player.GetName()} has been moved to a different sub group.`); + } + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => CheckSubGroup(...args)); +``` + +In this example, we first get the player's current sub group and original sub group using `GetSubGroup()` and `GetOriginalSubGroup()` respectively. We then check if the current sub group is different from the original sub group. + +If the sub groups are different, we determine if the player is a healer by checking their class against a healer class mask. If the player is a healer, we move them back to their original sub group using `SetSubGroup()` and send them a message letting them know they have been moved. + +If the player is not a healer, we get the raid leader using `GetRaidLeader()` and send them a message letting them know that the player has been moved to a different sub group. + +This script can be useful for ensuring that healers stay in their designated sub groups, while also notifying the raid leader if any non-healers have been moved. + +## GetPhaseMaskForSpawn +Returns the normal phase mask of the player, which represents the phases that the player is currently in. This method is useful when you need to know the player's phase without any GM phase modifications. + +### Parameters +This method does not take any parameters. + +### Returns +* number - The normal phase mask of the player. + +### Example Usage +Suppose you want to create a custom NPC that is only visible to players in a specific phase. You can use the `GetPhaseMaskForSpawn` method to check if the player is in the required phase before spawning the NPC. + +```typescript +const CUSTOM_NPC_ENTRY = 123456; +const REQUIRED_PHASE = 2; + +const OnAreaTrigger: player_event_on_area_trigger = (event, player, areaTrigger) => { + const phaseMask = player.GetPhaseMaskForSpawn(); + + if ((phaseMask & REQUIRED_PHASE) !== 0) { + // Player is in the required phase + const npc = player.SummonCreature(CUSTOM_NPC_ENTRY, player.GetX(), player.GetY(), player.GetZ(), player.GetO(), 1, 0); + + if (npc) { + // Set the NPC's phase to match the player's phase + npc.SetPhaseMask(phaseMask, true); + + // Make the NPC follow the player + npc.SetFollow(player, 5.0, 0); + + // Make the NPC despawn after 5 minutes (300000 milliseconds) + npc.DespawnOrUnsummon(300000); + + player.SendBroadcastMessage("A mysterious NPC has appeared and is following you!"); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER, OnAreaTrigger); +``` + +In this example, when a player enters a specific area trigger, the script checks if the player is in the required phase using `GetPhaseMaskForSpawn`. If the player is in the correct phase, a custom NPC is summoned at the player's location. The NPC's phase is set to match the player's phase using `SetPhaseMask`, ensuring that the NPC is only visible to players in the same phase. The NPC is then set to follow the player and despawn after 5 minutes. + +This script demonstrates how `GetPhaseMaskForSpawn` can be used in combination with other methods to create phase-specific interactions and events in your Azeroth Core server. + +## GetPlayerIP +Returns the IP address of the player as a string. + +### Parameters +None + +### Returns +string - The IP address of the player. + +### Example Usage +This example demonstrates how to retrieve a player's IP address and store it in the database when they enter the world. It also checks if the player's IP address matches a list of banned IPs and kicks them from the server if there is a match. + +```typescript +const BANNED_IPS = ["192.168.1.10", "10.0.0.5", "172.16.0.1"]; + +const storePlayerIP: player_event_on_login = (event: number, player: Player) => { + const playerIP = player.GetPlayerIP(); + const playerGUID = player.GetGUIDLow(); + + // Store the player's IP in the database + let query = `INSERT INTO player_ips (guid, ip_address) VALUES (${playerGUID}, '${playerIP}')`; + QueryWorld(WorldDatabaseQueries.QUERY_WORLD_DB_EXECUTE, query); + + // Check if the player's IP is in the banned list + if (BANNED_IPS.includes(playerIP)) { + player.KickPlayer(); + console.log(`Banned player with IP ${playerIP} attempted to log in.`); + + // Log the incident in the database + query = `INSERT INTO banned_logins (guid, ip_address, timestamp) VALUES (${playerGUID}, '${playerIP}', NOW())`; + QueryWorld(WorldDatabaseQueries.QUERY_WORLD_DB_EXECUTE, query); + } else { + console.log(`Player with IP ${playerIP} logged in successfully.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => storePlayerIP(...args)); +``` + +In this example: + +1. We define an array of banned IP addresses called `BANNED_IPS`. + +2. We create a function called `storePlayerIP` that handles the `PLAYER_EVENT_ON_LOGIN` event. + +3. Inside the function, we retrieve the player's IP address using `player.GetPlayerIP()` and their GUID using `player.GetGUIDLow()`. + +4. We construct an SQL query to insert the player's GUID and IP address into a table called `player_ips` in the world database. + +5. We execute the query using `QueryWorld` with the `QUERY_WORLD_DB_EXECUTE` query type. + +6. We check if the player's IP address is included in the `BANNED_IPS` array. + +7. If the IP is banned, we kick the player using `player.KickPlayer()`, log a message indicating that a banned player attempted to log in, and insert a record of the incident into a table called `banned_logins` in the world database. + +8. If the IP is not banned, we log a message indicating that the player logged in successfully. + +9. Finally, we register the `storePlayerIP` function to handle the `PLAYER_EVENT_ON_LOGIN` event using `RegisterPlayerEvent`. + +This example showcases how to retrieve a player's IP address, store it in the database, and perform actions based on whether the IP is banned or not. It demonstrates the usage of the `GetPlayerIP` method, as well as interacting with the world database using `QueryWorld` and handling player events with `RegisterPlayerEvent`. + +## GetPureMaxSkillValue +Returns the maximum value of a specified skill without any bonuses applied. This is useful for determining the base skill level of a player before any bonuses from gear, buffs, or other sources are applied. + +### Parameters +* skill: number - The ID of the skill to retrieve the max value for. Skill IDs can be found in the `SkillLine.dbc` file. + +### Returns +* number - The maximum skill value without any bonuses applied. + +### Example Usage +This example demonstrates how to retrieve the pure max skill value for a player's mining skill and check if they have reached the required skill level to mine a specific ore. + +```typescript +const MINING_SKILL_ID = 186; +const MITHRIL_ORE_REQUIRED_SKILL = 175; + +const OnGossipHello: GossipMenuItems = (event, player, object): void => { + const miningSkillMaxValue = player.GetPureMaxSkillValue(MINING_SKILL_ID); + + if (miningSkillMaxValue >= MITHRIL_ORE_REQUIRED_SKILL) { + player.GossipMenuAddItem(0, "Mine Mithril Ore", 0, 1); + } else { + player.GossipMenuAddItem(0, "You need a mining skill of at least 175 to mine Mithril Ore.", 0, 1); + } + + player.GossipSendMenu(0x7FFFFFFF, object.GetGUID()); +}; + +const OnGossipSelect: GossipSelectMenu = (event, player, object, sender, intid, code): void => { + if (intid === 1) { + player.GossipComplete(); + // Code to handle mining Mithril Ore + // ... + } +}; + +RegisterGameObjectGossipEvent(12345, 1, OnGossipHello); +RegisterGameObjectGossipEvent(12345, 2, OnGossipSelect); +``` + +In this example: +1. We define constants for the mining skill ID and the required skill level to mine Mithril Ore. +2. In the `OnGossipHello` event, we retrieve the player's pure max mining skill value using `GetPureMaxSkillValue`. +3. We compare the player's mining skill level with the required skill level for Mithril Ore. +4. If the player's skill level is sufficient, we add a gossip menu item allowing them to mine Mithril Ore. Otherwise, we display a message indicating the required skill level. +5. We send the gossip menu to the player. +6. In the `OnGossipSelect` event, we handle the player's selection. If they chose to mine Mithril Ore (intid === 1), we complete the gossip interaction and execute the code to handle mining. + +By using `GetPureMaxSkillValue`, we can determine the player's base mining skill level without any bonuses, ensuring that the skill check is based on their actual proficiency in the mining skill. + +## GetPureSkillValue +Returns the player's skill value for a specified skill without any bonus points. + +### Parameters +* skill: number - The ID of the skill to retrieve the value for. + +### Returns +* number - The player's skill value without any bonus points. + +### Example Usage +This example demonstrates how to retrieve a player's pure skill value for a specific skill and use it to determine if they are eligible for a special bonus or reward. + +```typescript +const SKILL_FISHING = 356; +const FISHING_SKILL_THRESHOLD = 300; +const BONUS_ITEM_ENTRY = 12345; + +const OnPlayerLogin: player_event_on_login = (event: number, player: Player) => { + const fishingSkill = player.GetPureSkillValue(SKILL_FISHING); + + if (fishingSkill >= FISHING_SKILL_THRESHOLD) { + // Check if the player already has the bonus item + const hasItem = player.HasItem(BONUS_ITEM_ENTRY); + + if (!hasItem) { + // Award the bonus item for reaching the fishing skill threshold + const bonusItem = player.AddItem(BONUS_ITEM_ENTRY, 1); + + if (bonusItem) { + player.SendNotification("Congratulations! You have been awarded a special fishing bonus item for your exceptional fishing skills."); + } else { + player.SendNotification("You are eligible for a special fishing bonus item, but your inventory is full. Please make some space and log in again."); + } + } + } else { + player.SendNotification(`Improve your fishing skill to ${FISHING_SKILL_THRESHOLD} to be eligible for a special bonus!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnPlayerLogin(...args)); +``` + +In this example: +1. We define constants for the fishing skill ID, the skill threshold for receiving the bonus, and the bonus item entry ID. +2. When a player logs in, we retrieve their pure fishing skill value using `GetPureSkillValue(SKILL_FISHING)`. +3. If the player's fishing skill is greater than or equal to the specified threshold: + - We check if the player already has the bonus item using `HasItem(BONUS_ITEM_ENTRY)`. + - If the player doesn't have the item, we attempt to add the bonus item to their inventory using `AddItem(BONUS_ITEM_ENTRY, 1)`. + - If the item is successfully added, we send a congratulatory message to the player. + - If the item cannot be added (e.g., due to a full inventory), we send a notification to the player to make space and log in again. +4. If the player's fishing skill is below the threshold, we send a message encouraging them to improve their skill to be eligible for the bonus. + +This example showcases how `GetPureSkillValue` can be used in conjunction with other methods and game events to create engaging gameplay mechanics and reward players for their achievements. + +## GetQuestLevel +Returns the quest level of the specified quest for the player. The quest level is determined by the player's level when they first accepted the quest. + +### Parameters +* questId: number - The ID of the quest to get the level for. + +### Returns +* number - The quest level of the specified quest for the player. + +### Example Usage +This example demonstrates how to adjust the rewards given to a player based on the quest level when they complete a quest. + +```typescript +const QUEST_ENTRY = 1234; +const ITEM_REWARD_ENTRY = 5678; + +const onQuestComplete: player_event_on_quest_complete = (event: number, player: Player, quest: Quest): void => { + if (quest.GetEntry() === QUEST_ENTRY) { + const questLevel = player.GetQuestLevel(QUEST_ENTRY); + let itemCount = 1; + + if (questLevel <= 10) { + itemCount = 1; + } else if (questLevel <= 20) { + itemCount = 2; + } else if (questLevel <= 30) { + itemCount = 3; + } else if (questLevel <= 40) { + itemCount = 4; + } else if (questLevel <= 50) { + itemCount = 5; + } else if (questLevel <= 60) { + itemCount = 6; + } else { + itemCount = 7; + } + + const rewardItem = player.AddItem(ITEM_REWARD_ENTRY, itemCount); + if (rewardItem) { + player.SendBroadcastMessage(`You have been rewarded with ${itemCount} x ${rewardItem.GetName()} for completing the quest at level ${questLevel}!`); + } else { + player.SendBroadcastMessage(`Failed to add reward item to your inventory. Please check if you have enough space.`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => onQuestComplete(...args)); +``` + +In this example: +1. We define the quest entry and the item reward entry as constants. +2. In the `onQuestComplete` event handler, we check if the completed quest matches the desired quest entry. +3. If it matches, we get the quest level using `player.GetQuestLevel(questId)`. +4. Based on the quest level, we determine the number of reward items to give to the player. +5. We use `player.AddItem(itemEntry, itemCount)` to add the reward item(s) to the player's inventory. +6. If the reward item(s) are successfully added, we send a broadcast message to the player informing them about the reward and the quest level. +7. If adding the reward item(s) fails (e.g., due to insufficient inventory space), we send an appropriate message to the player. + +This example showcases how the `GetQuestLevel` method can be used in combination with other methods and game events to create a more dynamic and level-based reward system for quests. + +## GetQuestRewardStatus +Determines if the player has completed the quest and received the rewards from the quest giver NPC. + +### Parameters +questId: number - The ID of the quest to check the status of + +### Returns +boolean - Returns true if the player has been rewarded for the quest, false otherwise + +### Example Usage +This method can be useful to check if the player has completed a quest chain before offering them +a new quest that is a follow up, or to see if the player has received a special item or reward from a quest +in order to unlock an event or special dialogue option. + +```typescript +// Constants for the quest IDs +const QUEST_DISCOVER_KALIMDOR = 1001; +const QUEST_RETURN_TO_ORGRIMMAR = 1002; +const QUEST_REPORT_TO_WARCHIEF = 1003; + +// Constants for the NPC ID +const NPC_WARCHIEF_THRALL = 4949; + +// Function to handle gossip hello event for the Warchief +const OnGossipHello: creature_event_on_gossip_hello = (event, player, creature) => { + // Check if the player has completed the quest chain + if (player.GetQuestRewardStatus(QUEST_DISCOVER_KALIMDOR) && + player.GetQuestRewardStatus(QUEST_RETURN_TO_ORGRIMMAR) && + player.GetQuestRewardStatus(QUEST_REPORT_TO_WARCHIEF)) { + + // Player has completed the quest chain, offer them a special dialogue option + player.GossipMenuAddItem(0, "I have completed your tasks, Warchief. What would you have me do next?", 1, 0); + } + else { + // Player has not completed the quest chain, offer them the standard dialogue options + player.GossipMenuAddItem(0, "I am ready to serve the Horde, Warchief!", 2, 0); + player.GossipMenuAddItem(0, "Lok'tar ogar! Victory or death!", 2, 0); + } + + // Send the gossip menu to the player + player.GossipSendMenu(1, creature.GetGUID()); +}; + +// Register the gossip hello event for the Warchief NPC +RegisterCreatureGossipEvent(NPC_WARCHIEF_THRALL, 1, OnGossipHello); +``` + +In this example, when the player interacts with Warchief Thrall, the script checks if they have completed a series of quests by checking the reward status of each quest ID. If the player has completed all the quests in the chain, they are offered a special dialogue option. Otherwise, they are offered the standard dialogue options. + +## GetQuestStatus +Returns the current status of the specified quest for the player. The status is represented by a number value indicating the quest state. + +### Parameters +* questId: number - The entry ID of the quest to check the status for. + +### Returns +* number - The current status of the quest for the player. Possible values are: + * 0 - Quest not found or not completed + * 1 - Quest completed + * 2 - Quest not completed but still in progress + * 3 - Quest failed + +### Example Usage +This example demonstrates how to check the status of a specific quest and perform actions based on the quest status. + +```typescript +const QUEST_ENTRY = 1234; // Replace with the desired quest entry ID + +const OnGossipHello: GossipEvents.OnGossipHello = (event, player, object) => { + const questStatus = player.GetQuestStatus(QUEST_ENTRY); + + if (questStatus === 0) { + // Quest not found or not completed + player.GossipMenuAddItem(0, "I haven't started that quest yet.", 0, 1); + } else if (questStatus === 1) { + // Quest completed + player.GossipMenuAddItem(0, "I have already completed that quest!", 0, 2); + } else if (questStatus === 2) { + // Quest not completed but still in progress + player.GossipMenuAddItem(0, "I am still working on that quest.", 0, 3); + } else if (questStatus === 3) { + // Quest failed + player.GossipMenuAddItem(0, "I have failed that quest.", 0, 4); + } + + player.GossipSendMenu(1, object, MenuId); +}; + +const OnGossipSelect: GossipEvents.OnGossipSelect = (event, player, object, sender, intid, code) => { + if (sender === 0) { + if (intid === 1) { + // Handle action for quest not started + player.GossipClearMenu(); + player.GossipMenuAddItem(0, "I will start that quest now!", 0, 5); + player.GossipSendMenu(2, object, MenuId); + } else if (intid === 2) { + // Handle action for quest completed + player.SendBroadcastMessage("Congratulations on completing the quest!"); + player.GossipComplete(); + } else if (intid === 3) { + // Handle action for quest in progress + player.SendBroadcastMessage("Keep up the good work on that quest!"); + player.GossipComplete(); + } else if (intid === 4) { + // Handle action for quest failed + player.SendBroadcastMessage("Don't worry, you can always try the quest again!"); + player.GossipComplete(); + } + } +}; + +RegisterGossipEvent(GossipEvents.GOSSIP_EVENT_ON_HELLO, OnGossipHello); +RegisterGossipEvent(GossipEvents.GOSSIP_EVENT_ON_SELECT, OnGossipSelect); +``` + +In this example, when the player interacts with an object (e.g., an NPC), the script checks the status of a specific quest using `player.GetQuestStatus(QUEST_ENTRY)`. Based on the quest status, different gossip options are added to the menu. When the player selects an option, the corresponding action is performed based on the quest status. This allows for dynamic interactions and dialogue based on the player's progress in the quest. + +## GetRankPoints +Returns the current rank points of the player. Rank points are used in PvP ranking systems, such as Honor or Arena, to determine the player's standing and progress. + +### Parameters +None + +### Returns +- `number` - The current rank points of the player. + +### Example Usage +```typescript +// Event handler for player login +const OnLogin: player_event_on_login = (event: number, player: Player) => { + // Get the player's current rank points + const rankPoints = player.GetRankPoints(); + + // Define the ranks and their corresponding rank point thresholds + const ranks = [ + { name: 'Private', points: 0 }, + { name: 'Corporal', points: 500 }, + { name: 'Sergeant', points: 1000 }, + { name: 'Master Sergeant', points: 1500 }, + { name: 'Sergeant Major', points: 2000 }, + { name: 'Knight', points: 2500 }, + { name: 'Knight-Lieutenant', points: 3000 }, + { name: 'Knight-Captain', points: 3500 }, + { name: 'Knight-Champion', points: 4000 }, + { name: 'Lieutenant Commander', points: 4500 }, + { name: 'Commander', points: 5000 }, + { name: 'Marshal', points: 5500 }, + { name: 'Field Marshal', points: 6000 }, + { name: 'Grand Marshal', points: 6500 }, + ]; + + // Find the player's current rank based on their rank points + let currentRank = ''; + for (let i = ranks.length - 1; i >= 0; i--) { + if (rankPoints >= ranks[i].points) { + currentRank = ranks[i].name; + break; + } + } + + // Send a message to the player indicating their current rank and rank points + player.SendBroadcastMessage(`Welcome, ${player.GetName()}! Your current rank is ${currentRank} with ${rankPoints} rank points.`); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example, when a player logs in, their current rank points are retrieved using the `GetRankPoints()` method. The script defines an array of ranks with their corresponding rank point thresholds. It then iterates through the ranks array in reverse order to find the player's current rank based on their rank points. Finally, it sends a broadcast message to the player, informing them of their current rank and rank points. + +This script demonstrates how the `GetRankPoints()` method can be used in conjunction with a custom ranking system to provide players with information about their progress and standing in PvP activities. + +## GetReputation +Returns the current reputation level the player has with the specified faction. + +### Parameters +* faction: number - The ID of the faction to check reputation for. Faction IDs can be found in the `Faction.dbc` file. + +### Returns +* reputation: number - The current reputation level the player has with the specified faction. + +### Example Usage +This example checks if the player has reached exalted status with the Darkspear Trolls faction (ID 530) and rewards them with a special item if they have. + +```typescript +const DARKSPEAR_TROLLS_FACTION_ID = 530; +const EXALTED_REPUTATION = 42000; +const REWARD_ITEM_ENTRY = 12345; + +function CheckDarkspearReputation(player: Player): void { + const reputation = player.GetReputation(DARKSPEAR_TROLLS_FACTION_ID); + + if (reputation >= EXALTED_REPUTATION) { + const hasRewardItem = player.HasItem(REWARD_ITEM_ENTRY); + + if (!hasRewardItem) { + const rewardItem = player.AddItem(REWARD_ITEM_ENTRY, 1); + + if (rewardItem) { + player.SendBroadcastMessage("Congratulations on reaching Exalted status with the Darkspear Trolls! Here's a special reward for your dedication."); + } else { + player.SendBroadcastMessage("You have reached Exalted status with the Darkspear Trolls, but your inventory is full. Please make room and speak to me again."); + } + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (event, player, msg, Type, lang) => { + if (msg === "!darkspearrep") { + CheckDarkspearReputation(player); + } +}); +``` + +In this example: +1. We define constants for the Darkspear Trolls faction ID, the minimum reputation level required for exalted status, and the reward item entry. +2. We create a function `CheckDarkspearReputation` that takes a `Player` object as a parameter. +3. Inside the function, we use `player.GetReputation()` to get the player's current reputation level with the Darkspear Trolls faction. +4. We check if the reputation level is greater than or equal to the exalted reputation level. +5. If the player has reached exalted status, we check if they already have the reward item using `player.HasItem()`. +6. If the player doesn't have the reward item, we attempt to add it to their inventory using `player.AddItem()`. +7. If the item is successfully added, we send a congratulatory message to the player using `player.SendBroadcastMessage()`. +8. If the player's inventory is full, we send a message informing them to make room and speak to the NPC again. +9. Finally, we register a player event for the `PLAYER_EVENT_ON_CHAT` event, which listens for the "!darkspearrep" command and triggers the `CheckDarkspearReputation` function when the command is detected. + +## GetReputationRank +Returns the player's reputation rank with the specified faction. The rank is determined by the player's current standing with the faction and the thresholds defined in the database for each rank. + +### Parameters +* faction: number - The ID of the faction to check the player's reputation rank for. + +### Returns +* number - The player's reputation rank with the specified faction. The rank is returned as an integer value: + * 0 - Hated + * 1 - Hostile + * 2 - Unfriendly + * 3 - Neutral + * 4 - Friendly + * 5 - Honored + * 6 - Revered + * 7 - Exalted + +### Example Usage +This example demonstrates how to check a player's reputation rank with a specific faction and grant them rewards based on their rank. + +```typescript +const FACTION_KARAZHAN_CHESS = 1690; +const ITEM_CONJURED_MANA_CAKE = 22895; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const reputationRank = player.GetReputationRank(FACTION_KARAZHAN_CHESS); + + switch (reputationRank) { + case 4: // Friendly + player.AddItem(ITEM_CONJURED_MANA_CAKE, 1); + break; + case 5: // Honored + player.AddItem(ITEM_CONJURED_MANA_CAKE, 2); + break; + case 6: // Revered + player.AddItem(ITEM_CONJURED_MANA_CAKE, 3); + player.CastSpell(player, 33077, true); // Cast "Blessing of the Silver Crescent" + break; + case 7: // Exalted + player.AddItem(ITEM_CONJURED_MANA_CAKE, 5); + player.CastSpell(player, 33078, true); // Cast "Blessing of the Silver Crescent" + player.CastSpell(player, 33079, true); // Cast "Summon Chest of Spoils" + break; + } + + if (reputationRank >= 4) { + player.SendBroadcastMessage(`Your reputation with the Karazhan Chess Event is ${GetReputationRankName(reputationRank)}!`); + } +}; + +function GetReputationRankName(rank: number): string { + switch (rank) { + case 0: return "Hated"; + case 1: return "Hostile"; + case 2: return "Unfriendly"; + case 3: return "Neutral"; + case 4: return "Friendly"; + case 5: return "Honored"; + case 6: return "Revered"; + case 7: return "Exalted"; + default: return "Unknown"; + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. When a player logs in, their reputation rank with the "Karazhan Chess Event" faction is checked using `GetReputationRank()`. +2. Based on the player's reputation rank, they receive different rewards: + * Friendly: 1 Conjured Mana Cake + * Honored: 2 Conjured Mana Cakes + * Revered: 3 Conjured Mana Cakes and the "Blessing of the Silver Crescent" spell + * Exalted: 5 Conjured Mana Cakes, the "Blessing of the Silver Crescent" spell, and a "Summon Chest of Spoils" spell +3. If the player's reputation rank is Friendly or higher, they receive a broadcast message informing them of their current rank. +4. The `GetReputationRankName()` function is used to convert the numeric reputation rank to a readable string for the broadcast message. + +This script provides a way to reward players based on their reputation rank with a specific faction, encouraging them to improve their standing with that faction to receive better rewards. + +## GetReqKillOrCastCurrentCount +Retrieves the current progress count for a required creature kill or gameobject cast quest objective. + +### Parameters +* quest: number - The ID of the quest to check progress for +* entry: number - The ID of the required creature or gameobject + +### Returns +* number - The current progress count for the specified quest objective + +### Example Usage +This example script listens for the `PLAYER_EVENT_ON_KILL_CREATURE` event and checks if the killed creature is a quest objective for any of the player's active quests. If it is, the script checks the player's progress and sends them a message if they have completed the objective. + +```typescript +const checkQuestProgress: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + const activeQuests = player.GetActiveQuests(); + + for (const questId of activeQuests) { + const quest = player.GetQuest(questId); + const requiredCount = quest.GetRequiredCreatureOrGOCount(creature.GetEntry()); + + if (requiredCount > 0) { + const currentCount = player.GetReqKillOrCastCurrentCount(questId, creature.GetEntry()); + + if (currentCount >= requiredCount) { + player.SendBroadcastMessage(`You have completed the objective for quest ${quest.GetTitle()}!`); + } else { + player.SendBroadcastMessage(`You have killed ${currentCount}/${requiredCount} ${creature.GetName()} for quest ${quest.GetTitle()}.`); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => checkQuestProgress(...args)); +``` + +In this example: +1. We define a function `checkQuestProgress` that takes the event ID, the player, and the killed creature as arguments. +2. We retrieve the player's active quests using `GetActiveQuests()`. +3. For each active quest, we: + - Get the quest object using `GetQuest(questId)`. + - Check if the killed creature is a required objective for the quest using `GetRequiredCreatureOrGOCount(creature.GetEntry())`. + - If the creature is required: + - Get the player's current progress count for the objective using `GetReqKillOrCastCurrentCount(questId, creature.GetEntry())`. + - Compare the current count with the required count. + - Send a message to the player indicating their progress or completion of the objective. +4. Finally, we register the `checkQuestProgress` function to be called whenever the `PLAYER_EVENT_ON_KILL_CREATURE` event is triggered for any player. + +This script helps players keep track of their quest progress by sending them informative messages when they kill creatures that are required for their active quests. + +## GetRestBonus +Returns the player's current resting bonus as a number. The resting bonus is an experience multiplier that is applied when a player is resting in an inn or a city. + +### Parameters +None + +### Returns +* number - The current resting bonus multiplier + +### Example Usage +This example demonstrates how to reward players with bonus experience when they are resting in a city or an inn. + +```typescript +const KILL_XP_MULTIPLIER = 2; +const QUEST_XP_MULTIPLIER = 1.5; + +const OnGiveXP: player_event_on_give_xp = (event: number, player: Player, amount: number, victim: Unit) => { + const restBonus = player.GetRestBonus(); + let bonusMultiplier = 1; + + if (restBonus > 0) { + if (victim) { + bonusMultiplier = KILL_XP_MULTIPLIER; + } else { + bonusMultiplier = QUEST_XP_MULTIPLIER; + } + } + + const bonusXP = amount * (bonusMultiplier - 1); + const totalXP = amount + bonusXP; + + player.SendBroadcastMessage(`You gained ${totalXP} experience points (${bonusXP} bonus XP from resting).`); + + return totalXP; +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GIVE_XP, (...args) => OnGiveXP(...args)); +``` + +In this example: +1. We define constants for the bonus multipliers: `KILL_XP_MULTIPLIER` for experience gained from killing creatures and `QUEST_XP_MULTIPLIER` for experience gained from completing quests. + +2. We register the `OnGiveXP` event handler using `RegisterPlayerEvent` and the `PLAYER_EVENT_ON_GIVE_XP` event. + +3. Inside the event handler, we retrieve the player's current resting bonus using `player.GetRestBonus()`. + +4. We initialize a `bonusMultiplier` variable to 1, which represents no bonus. + +5. If the player has a resting bonus greater than 0, we set the `bonusMultiplier` based on the source of the experience: + - If the experience is gained from killing a creature (`victim` is provided), we use the `KILL_XP_MULTIPLIER`. + - Otherwise, we assume the experience is from completing a quest and use the `QUEST_XP_MULTIPLIER`. + +6. We calculate the bonus experience points by multiplying the base experience amount (`amount`) by the difference between the `bonusMultiplier` and 1. + +7. We calculate the total experience points by adding the base experience and the bonus experience. + +8. We send a broadcast message to the player informing them about the total experience gained and the bonus experience from resting. + +9. Finally, we return the total experience points, which will be awarded to the player. + +This example showcases how to utilize the `GetRestBonus` method to provide additional rewards to players who are resting, encouraging them to spend time in inns and cities to gain bonus experience. + +## GetSelection +Returns the [Unit](./unit.md) that the player currently has selected. This could be a creature, another player, or any other entity derived from [Unit](./unit.md). + +### Parameters +This method does not take any parameters. + +### Returns +[Unit](./unit.md) - The currently selected unit by the player. + +### Example Usage +This example demonstrates how to use `GetSelection` to implement a basic mind control spell that can be cast on the currently selected unit. + +```typescript +// Define the spell ID for the mind control spell +const SPELL_MIND_CONTROL = 605; + +// Handler for the PLAYER_EVENT_ON_CAST_SPELL event +const OnPlayerCastSpell: player_event_on_cast_spell = (event: number, player: Player, spell: number, skipCheck: boolean) => { + // Check if the cast spell is the mind control spell + if (spell === SPELL_MIND_CONTROL) { + // Get the currently selected unit + const target = player.GetSelection(); + + // Ensure the selected unit exists and is a player + if (target && target.IsPlayer()) { + // Get the selected player + const targetPlayer = target.ToPlayer(); + + // Check if the target player is in the same group as the caster + if (player.IsInGroup() && targetPlayer.IsInGroup() && player.GetGroup() === targetPlayer.GetGroup()) { + // Players in the same group cannot mind control each other + player.SendBroadcastMessage("You cannot mind control players in your own group!"); + } else { + // Apply the mind control aura to the target player + targetPlayer.AddAura(SPELL_MIND_CONTROL, player); + player.SendBroadcastMessage(`You have mind controlled ${targetPlayer.GetName()}!`); + } + } else { + // If no valid player is selected, inform the caster + player.SendBroadcastMessage("You must select a player to mind control."); + } + } +}; + +// Register the PLAYER_EVENT_ON_CAST_SPELL event handler +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CAST_SPELL, (...args) => OnPlayerCastSpell(...args)); +``` + +In this example: + +1. We define the spell ID for the mind control spell as `SPELL_MIND_CONTROL`. + +2. We create an event handler for the `PLAYER_EVENT_ON_CAST_SPELL` event, which is triggered whenever a player casts a spell. + +3. Inside the event handler, we check if the cast spell is the mind control spell using the spell ID. + +4. If the mind control spell is cast, we use `GetSelection` to get the currently selected unit by the player. + +5. We ensure that the selected unit exists and is a player using `IsPlayer` and `ToPlayer`. + +6. If the selected player is in the same group as the caster, we prevent the mind control and inform the caster. + +7. If the selected player is valid and not in the same group, we apply the mind control aura to the target player using `AddAura` and inform the caster. + +8. If no valid player is selected, we inform the caster that they must select a player to mind control. + +9. Finally, we register the event handler for the `PLAYER_EVENT_ON_CAST_SPELL` event using `RegisterPlayerEvent`. + +This example showcases how `GetSelection` can be used in conjunction with other methods and events to implement a mind control spell mechanic in the game. + +## GetShieldBlockValue +Returns the player's current shield block value, which represents the amount of damage that can be blocked by the player's shield. + +### Parameters +None + +### Returns +number - The player's current shield block value. + +### Example Usage +This example demonstrates how to retrieve the player's shield block value and use it to calculate the damage reduction when the player is attacked by an enemy. + +```typescript +const SHIELD_BLOCK_MULTIPLIER = 0.5; + +const onPlayerDamaged: player_event_on_damage = (event: number, player: Player, attacker: Unit, damage: number): void => { + const shieldBlockValue = player.GetShieldBlockValue(); + + if (shieldBlockValue > 0) { + const damageBlocked = Math.min(damage, shieldBlockValue); + const damageReduced = damageBlocked * SHIELD_BLOCK_MULTIPLIER; + + player.SetHealth(player.GetHealth() + damageReduced); + + player.SendBroadcastMessage(`Your shield blocked ${damageBlocked} damage and reduced the incoming damage by ${damageReduced}.`); + + if (attacker instanceof Player) { + attacker.SendBroadcastMessage(`${player.GetName()}'s shield blocked ${damageBlocked} damage and reduced your damage by ${damageReduced}.`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DAMAGE, (...args) => onPlayerDamaged(...args)); +``` + +In this example: +1. We define a constant `SHIELD_BLOCK_MULTIPLIER` to represent the percentage of damage reduction when a shield blocks an attack. +2. We register a player event handler for the `PLAYER_EVENT_ON_DAMAGE` event using `RegisterPlayerEvent`. +3. Inside the event handler, we retrieve the player's current shield block value using `player.GetShieldBlockValue()`. +4. If the shield block value is greater than 0, it means the player has a shield equipped and can potentially block damage. +5. We calculate the actual damage blocked by taking the minimum value between the incoming damage and the shield block value. +6. We then calculate the damage reduced by multiplying the blocked damage with the `SHIELD_BLOCK_MULTIPLIER`. +7. We update the player's health by adding the reduced damage using `player.SetHealth()`. +8. We send a broadcast message to the player informing them about the amount of damage blocked and reduced. +9. If the attacker is another player, we send a broadcast message to the attacker as well, informing them about the damage reduction caused by the shield block. + +This example showcases how the `GetShieldBlockValue` method can be used in a practical scenario to calculate and apply damage reduction based on the player's shield block value when they are attacked by an enemy. + +## GetSkillPermBonusValue +Returns the permanent bonus value for a specific skill. + +### Parameters +* skill: number - The ID of the skill to retrieve the bonus value for. +* bonusVal: number - The bonus value to be returned by reference. + +### Example Usage +```typescript +// Retrieve the permanent bonus value for a player's mining skill +const SKILL_MINING = 186; +let player = new Player(); +let miningBonus = 0; + +player.GetSkillPermBonusValue(SKILL_MINING, miningBonus); + +// Apply the mining bonus when calculating the chance to gather extra ores +const MINING_BONUS_CHANCE_PER_POINT = 0.5; +const BASE_EXTRA_ORE_CHANCE = 10; + +let totalChance = BASE_EXTRA_ORE_CHANCE + (miningBonus * MINING_BONUS_CHANCE_PER_POINT); + +const OnPlayerMine: player_event_on_loot_item = (event: number, player: Player, item: Item) => { + if (item.GetEntry() == COPPER_ORE_ENTRY || item.GetEntry() == TIN_ORE_ENTRY) { + let chance = Math.random() * 100; + if (chance <= totalChance) { + player.AddItem(item.GetEntry(), 1); + player.SendBroadcastMessage("Your mining skill grants you an extra ore!"); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, (...args) => OnPlayerMine(...args)); +``` + +In this example, we first retrieve the player's permanent bonus value for the mining skill using `GetSkillPermBonusValue`. We then calculate the total chance of gathering an extra ore based on the mining bonus and a predefined base chance. + +When the player loots an item, we check if it is a copper or tin ore. If it is, we generate a random number between 0 and 100 and compare it to the total chance. If the random number is less than or equal to the total chance, we grant the player an extra ore using `AddItem` and send them a message using `SendBroadcastMessage`. + +This script demonstrates how the permanent skill bonus can be used to enhance gameplay mechanics and provide additional benefits to players who have invested in certain skills. + +## GetSkillTempBonusValue +Returns the temporary bonus value for a specific skill. + +### Parameters +* skill: number - The ID of the skill to retrieve the temporary bonus value for. +* bonusVal: number - The temporary bonus value for the specified skill. + +### Example Usage +In this example, we'll create a script that grants players a temporary bonus to their mining skill when they consume a specific item. + +```typescript +const MINING_SKILL_ID = 186; +const BUFF_ITEM_ENTRY = 12345; +const BUFF_DURATION = 1800; // 30 minutes in seconds +const BUFF_VALUE = 10; + +const UseItem: player_event_on_use_item = (event: number, player: Player, item: Item) => { + if (item.GetEntry() === BUFF_ITEM_ENTRY) { + const currentSkillValue = player.GetSkillValue(MINING_SKILL_ID); + const currentTempBonus = player.GetSkillTempBonusValue(MINING_SKILL_ID); + + player.SendBroadcastMessage(`Your current Mining skill is ${currentSkillValue} with a temporary bonus of ${currentTempBonus}.`); + + player.SetSkillTempBonusValue(MINING_SKILL_ID, currentTempBonus + BUFF_VALUE); + player.SendBroadcastMessage(`You have consumed the item and gained a temporary bonus of ${BUFF_VALUE} to your Mining skill!`); + + player.ScheduleEvent(BUFF_DURATION * 1000, (eventId: number, delay: number, repeats: number, player: Player) => { + const newTempBonus = player.GetSkillTempBonusValue(MINING_SKILL_ID) - BUFF_VALUE; + player.SetSkillTempBonusValue(MINING_SKILL_ID, newTempBonus); + player.SendBroadcastMessage(`The temporary bonus to your Mining skill has expired. Your current temporary bonus is now ${newTempBonus}.`); + }); + + item.SetCount(item.GetCount() - 1); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => UseItem(...args)); +``` + +In this script: +1. We define constants for the mining skill ID, the buff item entry, the buff duration, and the buff value. +2. When a player uses an item, we check if the item's entry matches the specified buff item entry. +3. If the item matches, we retrieve the player's current skill value and temporary bonus value for the mining skill. +4. We send a message to the player displaying their current mining skill value and temporary bonus. +5. We increase the player's temporary bonus value for the mining skill by the specified buff value. +6. We send a message to the player informing them about the temporary bonus they have gained. +7. We schedule an event to remove the temporary bonus after the specified duration. +8. When the scheduled event is triggered, we reduce the player's temporary bonus value for the mining skill by the buff value. +9. We send a message to the player informing them that the temporary bonus has expired and display their current temporary bonus value. +10. Finally, we reduce the count of the consumed item by 1. + +This script demonstrates how to retrieve and modify the temporary bonus value for a specific skill, and how to create a temporary buff that expires after a certain duration. + +## GetSkillValue +Returns the current value of a player's skill based on the skill ID provided. + +### Parameters +* skill: number - The ID of the skill to retrieve the value for. Skill IDs can be found in the SkillLine.dbc file. + +### Returns +* number - The current value of the player's skill. + +### Example Usage +This example script will check a player's skill level in Herbalism (skill ID 182) and provide a bonus to the amount of herbs they can gather based on their skill level. + +```typescript +const SKILL_HERBALISM = 182; +const ITEM_PEACEBLOOM = 2447; +const ITEM_SILVERLEAF = 765; +const ITEM_EARTHROOT = 2449; + +const GatherHerb: player_event_on_loot_item = (event: number, player: Player, item: Item) => { + const herbalismSkill = player.GetSkillValue(SKILL_HERBALISM); + let bonusAmount = 0; + + if (herbalismSkill >= 300) { + bonusAmount = 3; + } else if (herbalismSkill >= 200) { + bonusAmount = 2; + } else if (herbalismSkill >= 100) { + bonusAmount = 1; + } + + if (bonusAmount > 0) { + switch (item.GetEntry()) { + case ITEM_PEACEBLOOM: + case ITEM_SILVERLEAF: + case ITEM_EARTHROOT: + const amountToAdd = item.GetCount() + bonusAmount; + player.AddItem(item.GetEntry(), amountToAdd); + break; + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, (...args) => GatherHerb(...args)); +``` + +In this example: +1. We define constants for the Herbalism skill ID and the item IDs of some common herbs. +2. In the `GatherHerb` function, we first retrieve the player's current Herbalism skill level using `player.GetSkillValue(SKILL_HERBALISM)`. +3. We then determine the bonus amount of herbs to grant based on the player's skill level using a series of if statements. +4. If the bonus amount is greater than 0 and the looted item is one of the specified herbs, we add the bonus amount to the quantity of herbs the player receives using `player.AddItem()`. +5. Finally, we register the `GatherHerb` function to be called whenever the `PLAYER_EVENT_ON_LOOT_ITEM` event is triggered. + +This script encourages players to level up their Herbalism skill by rewarding them with bonus herbs for higher skill levels, making the gathering process more efficient and rewarding. + +## GetSpecsCount +Returns the number of talent specs the player has available to them. This is based on the player's class and level. + +### Parameters +None + +### Returns +number - The number of specs the player has available. + +### Example Usage +In this example, we will grant the player a bonus to their primary stat (Strength, Agility, or Intellect) based on how many specs they have available. The bonus will increase for each spec they have access to. + +```typescript +const BONUS_STATS_SPELL_ID = 12345; +const BONUS_STATS_PER_SPEC = 10; + +const ApplyBonusStats = (player: Player) => { + const specs = player.GetSpecsCount(); + const bonus = specs * BONUS_STATS_PER_SPEC; + + // Remove the old aura if it exists + player.RemoveAura(BONUS_STATS_SPELL_ID); + + // Apply the new aura with the updated bonus + player.AddAura(BONUS_STATS_SPELL_ID, player); + const aura = player.GetAura(BONUS_STATS_SPELL_ID); + if (aura) { + aura.SetStackAmount(bonus); + } + + // Notify the player + player.SendNotification(`You have been granted a bonus of ${bonus} to your primary stat for having ${specs} spec(s) available.`); +} + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + ApplyBonusStats(player); +} + +const OnLevelChange: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + ApplyBonusStats(player); +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, OnLevelChange); +``` + +In this script: + +1. We define constants for the spell ID of the bonus stats aura and the amount of bonus stats to apply per available spec. + +2. We create an `ApplyBonusStats` function that: + - Gets the number of available specs using `GetSpecsCount()`. + - Calculates the total bonus based on the number of specs. + - Removes the old aura if it exists to ensure we don't stack multiple instances. + - Applies the new aura to the player. + - Sets the stack amount of the aura to the calculated bonus. + - Sends a notification to the player informing them of their bonus. + +3. We register event handlers for `PLAYER_EVENT_ON_LOGIN` and `PLAYER_EVENT_ON_LEVEL_CHANGE` to apply the bonus stats whenever the player logs in or gains a level, as these events may change the number of available specs. + +This script showcases a practical usage of `GetSpecsCount()` to provide a scaling bonus based on the player's class progression and spec availability. + +## GetSpellCooldownDelay +Returns the remaining cooldown in milliseconds for a specific spell based on the spell ID. + +### Parameters +* spellId: number - The ID of the spell to check the cooldown for. + +### Returns +* number - The remaining cooldown time in milliseconds. If the spell is not on cooldown, it will return 0. + +### Example Usage +In this example, we'll create a script that checks if the player's Lay on Hands spell (spell ID: 633) is on cooldown. If it is, we'll print the remaining cooldown time. If not, we'll cast the spell on the player. + +```typescript +const LAY_ON_HANDS_SPELL_ID = 633; + +const CheckLayOnHandsCooldown: player_event_on_gossip_hello = (event: number, player: Player, object: WorldObject) => { + const cooldownDelay = player.GetSpellCooldownDelay(LAY_ON_HANDS_SPELL_ID); + + if (cooldownDelay > 0) { + const remainingCooldownSec = Math.ceil(cooldownDelay / 1000); + player.SendBroadcastMessage(`Lay on Hands is on cooldown. Remaining time: ${remainingCooldownSec} seconds.`); + } else { + const layOnHandsSpell = player.GetSpellInfo(LAY_ON_HANDS_SPELL_ID); + + if (layOnHandsSpell) { + player.CastSpell(player, layOnHandsSpell, true); + player.SendBroadcastMessage("Lay on Hands has been cast on you."); + } else { + player.SendBroadcastMessage("Error: Lay on Hands spell not found."); + } + } + + object.GossipComplete(); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, (...args) => CheckLayOnHandsCooldown(...args)); +``` + +In this script, when the player interacts with an NPC (triggering the `PLAYER_EVENT_ON_GOSSIP_HELLO` event), we first check the cooldown of the Lay on Hands spell using `GetSpellCooldownDelay()`. If the cooldown is greater than 0, we calculate the remaining cooldown time in seconds and send a message to the player informing them of the remaining cooldown. + +If the spell is not on cooldown, we retrieve the spell information using `GetSpellInfo()`. If the spell is found, we cast it on the player using `CastSpell()` and send a confirmation message. If the spell is not found, we send an error message to the player. + +Finally, we complete the gossip interaction using `GossipComplete()` to close the gossip window. + +## GetSubGroup +Returns the player's current subgroup number. Raid groups are split into subgroups (or parties). This method allows you to know which subgroup a player belongs to. Subgroups in a raid are numbered starting from 0. + +### Parameters +This method does not take any parameters. + +### Returns +subGroup: number - The subgroup number the player belongs to. Returns 0 for the first subgroup, 1 for the second, and so on. + +### Example Usage +This example demonstrates how to reward bonus loot to a specific subgroup that downs a boss first. + +```typescript +const BOSS_ENTRY = 12345; +const BONUS_ITEM_ENTRY = 6789; +const BONUS_ITEM_COUNT = 1; + +let firstSubgroupToKillBoss: number | null = null; + +const OnCreatureKill: creature_event_on_killed = (event: number, creature: Creature, killer: Unit) => { + if (creature.GetEntry() === BOSS_ENTRY && killer instanceof Player) { + const player = killer as Player; + const subGroup = player.GetSubGroup(); + + if (firstSubgroupToKillBoss === null) { + // This is the first subgroup to kill the boss + firstSubgroupToKillBoss = subGroup; + SendWorldMessage(`Subgroup ${subGroup + 1} has downed the boss first! They will receive bonus loot.`); + } + + if (subGroup === firstSubgroupToKillBoss) { + // Reward bonus loot to all players in the first subgroup to kill the boss + const group = player.GetGroup(); + if (group) { + group.ForEachMember((member) => { + if (member instanceof Player && member.GetSubGroup() === subGroup) { + member.AddItem(BONUS_ITEM_ENTRY, BONUS_ITEM_COUNT); + } + }); + } + } + } +}; + +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_KILLED, OnCreatureKill); +``` + +In this example: +1. We define constants for the boss entry, bonus item entry, and bonus item count. +2. We initialize a variable `firstSubgroupToKillBoss` to keep track of the first subgroup that kills the boss. +3. In the `OnCreatureKill` event handler, we check if the killed creature is the boss and if the killer is a player. +4. If it's the first subgroup to kill the boss, we store the subgroup number in `firstSubgroupToKillBoss` and announce it to the world. +5. If the player belongs to the first subgroup that killed the boss, we reward bonus loot to all players in that subgroup. + - We get the player's group using `GetGroup()`. + - We iterate over each group member using `ForEachMember()`. + - For each member, we check if they are a player and belong to the same subgroup as the killer. + - If so, we add the bonus item to their inventory using `AddItem()`. +6. Finally, we register the `OnCreatureKill` event handler for the specific boss entry. + +This example showcases how to use `GetSubGroup()` to identify the subgroup a player belongs to and reward them accordingly based on their subgroup's performance in a raid encounter. + +## GetTeam +Returns the player's team as a [TeamId](./teamid.md) enum value. + +### Parameters +None + +### Returns +[TeamId](./teamid.md) - The player's team (ALLIANCE, HORDE, or NEUTRAL) + +### Example Usage +Reward players with an item based on their team: +```typescript +const ALLIANCE_ITEM_ENTRY = 12345; +const HORDE_ITEM_ENTRY = 67890; + +const RewardPlayerByTeam = (player: Player): void => { + const teamId = player.GetTeam(); + + switch (teamId) { + case TeamId.ALLIANCE: + player.AddItem(ALLIANCE_ITEM_ENTRY, 1); + SendSystemMessage(player, "You have been rewarded with an Alliance-exclusive item!"); + break; + case TeamId.HORDE: + player.AddItem(HORDE_ITEM_ENTRY, 1); + SendSystemMessage(player, "You have been rewarded with a Horde-exclusive item!"); + break; + case TeamId.NEUTRAL: + SendSystemMessage(player, "Neutral players do not receive a reward."); + break; + default: + SendSystemMessage(player, "An error occurred while trying to reward you based on your team."); + break; + } +} + +const OnPlayerLogin: player_event_on_login = (event: number, player: Player): void => { + if (!player.HasAura(REWARD_AURA_ENTRY)) { + RewardPlayerByTeam(player); + player.AddAura(REWARD_AURA_ENTRY, player); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnPlayerLogin(...args)); +``` +In this example, when a player logs in, the script checks if the player already has a specific aura (identified by `REWARD_AURA_ENTRY`). If the player does not have the aura, the script calls the `RewardPlayerByTeam` function, which determines the player's team using `GetTeam()` and rewards them with a team-specific item. The aura is then applied to the player to prevent multiple rewards. The script also sends a message to the player informing them of their reward or lack thereof. + +## GetTotalPlayedTime +Returns the total time the player has spent playing the character in seconds. + +### Parameters +None + +### Returns +* number - The total played time in seconds. + +### Example Usage +This example script awards players with bonus gold and experience points based on their total played time when they log in. + +```typescript +const BONUS_GOLD_PER_HOUR = 100; +const BONUS_EXP_PER_HOUR = 1000; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const totalPlayedTime = player.GetTotalPlayedTime(); + const totalPlayedHours = Math.floor(totalPlayedTime / 3600); // Convert seconds to hours + + // Calculate bonus gold and experience points based on played time + const bonusGold = totalPlayedHours * BONUS_GOLD_PER_HOUR; + const bonusExp = totalPlayedHours * BONUS_EXP_PER_HOUR; + + // Add bonus gold to the player's inventory + const coinage = player.GetCoinage(); + player.SetCoinage(coinage + bonusGold * 10000); // Convert gold to copper + + // Add bonus experience points to the player + player.GiveXP(bonusExp, null, false); + + // Send a message to the player informing them about the bonus rewards + player.SendBroadcastMessage(`Welcome back! As a reward for your dedication, you have been granted ${bonusGold} bonus gold and ${bonusExp} bonus experience points based on your total played time of ${totalPlayedHours} hours.`); + + // You can also store the total played time in the player's cache for future reference + player.SetCacheValue("totalPlayedTime", totalPlayedTime); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. When a player logs in, the script retrieves their total played time using `GetTotalPlayedTime()`. +2. The total played time is converted from seconds to hours. +3. Bonus gold and experience points are calculated based on the total played hours and predefined constants (`BONUS_GOLD_PER_HOUR` and `BONUS_EXP_PER_HOUR`). +4. The bonus gold is added to the player's inventory using `GetCoinage()` and `SetCoinage()`. Note that the gold amount is converted to copper before adding it to the player's coinage. +5. The bonus experience points are granted to the player using `GiveXP()`. +6. A broadcast message is sent to the player informing them about the bonus rewards and their total played time. +7. The total played time is stored in the player's cache using `SetCacheValue()` for future reference. + +This script demonstrates how `GetTotalPlayedTime()` can be used to implement a reward system based on player engagement and loyalty. You can customize the bonus amounts and additional rewards based on your server's requirements. + +## GetXPRestBonus +This method returns the amount of bonus experience the player will receive based on their current rested experience bonus. The amount of bonus experience is calculated as a percentage of the base experience passed into the method. + +### Parameters +* xp: number - The base experience amount to calculate the bonus for + +### Returns +* number - The amount of bonus experience the player will receive + +### Example Usage +This example script awards players with bonus experience when they complete a daily quest, based on their current rested bonus. + +```typescript +const DAILY_QUEST_COMPLETE_EVENT = 1; // Custom event ID +const DAILY_QUEST_XP_REWARD = 1000; // Base XP reward for daily quests + +// Handler for the custom daily quest completion event +const OnDailyQuestComplete: player_event_handler = (event: number, player: Player): void => { + // Calculate the bonus XP based on the player's rested bonus + const bonusXP = player.GetXPRestBonus(DAILY_QUEST_XP_REWARD); + + // Award the base XP and the bonus XP to the player + player.GiveXP(DAILY_QUEST_XP_REWARD, null); + player.GiveXP(bonusXP, null); + + // Send a message to the player informing them of the bonus XP + player.SendNotification(`You received ${bonusXP} bonus experience from your rested bonus!`); + + // If the player has reached the maximum level, reset their rested bonus + if (player.GetLevel() == player.GetMaxLevel()) { + player.SetRestBonus(0); + player.SendNotification("You have reached the maximum level and your rested bonus has been reset."); + } +}; + +// Register the event handler for the custom daily quest completion event +RegisterPlayerEvent(DAILY_QUEST_COMPLETE_EVENT, OnDailyQuestComplete); +``` + +In this example, when a player completes a daily quest (triggering the custom `DAILY_QUEST_COMPLETE_EVENT` event), the script calculates the bonus experience the player will receive based on their current rested bonus using `GetXPRestBonus()`. The base quest experience and the bonus experience are then awarded to the player using `GiveXP()`. + +The script also sends a notification to the player informing them of the amount of bonus experience they received. If the player has reached the maximum level, their rested bonus is reset to 0 using `SetRestBonus()`, and they are notified of this as well. + +This example demonstrates how `GetXPRestBonus()` can be used in combination with other methods and custom events to create more complex behaviors and reward systems in a mod. + +## GiveXP +This method grants experience points to the player. Optionally, you can specify a victim unit to credit for the experience gain. If no victim is provided, the experience will be granted without any source attribution. + +### Parameters +* xp: number - The amount of experience points to grant to the player. +* victim?: [Unit](./unit.md) - (Optional) The unit to credit for the experience gain. + +### Example Usage +In this example, we'll create a script that grants bonus experience to the player when they kill a creature based on its level difference. + +```typescript +const BONUS_XP_MULTIPLIER = 1.5; + +const OnCreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + const playerLevel = player.GetLevel(); + const creatureLevel = creature.GetLevel(); + const levelDifference = creatureLevel - playerLevel; + + if (levelDifference >= 5) { + const baseXP = creature.GetBaseXP(); + const bonusXP = Math.floor(baseXP * BONUS_XP_MULTIPLIER); + + player.SendBroadcastMessage(`You have slain a powerful creature and gained bonus experience!`); + player.GiveXP(bonusXP, creature); + + // Apply an additional 10% experience bonus for each level difference above 5 + const additionalBonusMultiplier = 1 + (levelDifference - 5) * 0.1; + const additionalBonusXP = Math.floor(bonusXP * additionalBonusMultiplier); + player.GiveXP(additionalBonusXP, creature); + + player.SendBroadcastMessage(`Total bonus experience gained: ${bonusXP + additionalBonusXP}`); + } else { + // Grant normal experience if the level difference is less than 5 + player.GiveXP(creature.GetBaseXP(), creature); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => OnCreatureKill(...args)); +``` + +In this script: +1. We define a constant `BONUS_XP_MULTIPLIER` to determine the bonus experience multiplier. +2. Inside the `OnCreatureKill` event handler, we calculate the level difference between the player and the slain creature. +3. If the level difference is 5 or greater, we grant bonus experience to the player: + - We retrieve the base experience points of the creature using `creature.GetBaseXP()`. + - We calculate the bonus experience by multiplying the base experience with the `BONUS_XP_MULTIPLIER`. + - We send a broadcast message to the player indicating they have gained bonus experience. + - We grant the bonus experience to the player using `player.GiveXP()`, specifying the bonus experience amount and the creature as the victim. + - We calculate an additional bonus based on the level difference above 5, multiplying the bonus experience by an additional multiplier of 10% for each level above 5. + - We grant the additional bonus experience to the player using `player.GiveXP()`. + - We send a broadcast message to the player with the total bonus experience gained. +4. If the level difference is less than 5, we grant the normal base experience to the player using `player.GiveXP()`, specifying the creature's base experience and the creature as the victim. + +This script enhances the gameplay experience by rewarding players with bonus experience when they defeat powerful creatures, providing an incentive to take on challenging encounters. + +## GossipAddQuests +This method adds the available quests that the specified `WorldObject` can offer to the player's gossip menu. It allows the player to interact with the `WorldObject` and view the quests they can accept or turn in. + +### Parameters +- `source`: [WorldObject](./worldobject.md) - The `WorldObject` that offers the quests to the player. This can be a creature, gameobject, or any other entity that extends the `WorldObject` class. + +### Example Usage +Here's an example of how to use the `GossipAddQuests` method in a script that handles the gossip interaction between a player and a quest giver: + +```typescript +const QUEST_GIVER_ENTRY = 1234; // The entry ID of the quest giver creature + +const OnGossipHello: player_event_on_gossip_hello = (event: number, player: Player, source: WorldObject) => { + if (source.GetEntry() === QUEST_GIVER_ENTRY) { + // Add the available quests to the player's gossip menu + player.GossipAddQuests(source); + + // Add custom gossip options + player.GossipMenuAddItem(0, "Tell me more about the available quests", 1, 0); + player.GossipMenuAddItem(0, "I have a question about a quest", 2, 0); + player.GossipMenuAddItem(0, "Goodbye", 3, 0); + + // Send the gossip menu to the player + player.GossipSendMenu(player.GetGossipTextId(source), source.GetGUID()); + } +}; + +const OnGossipSelect: player_event_on_gossip_select = (event: number, player: Player, source: WorldObject, sender: number, action: number) => { + if (sender === QUEST_GIVER_ENTRY) { + if (action === 1) { + // Handle the "Tell me more about the available quests" option + player.GossipMenuAddItem(0, "Quest 1 description", 4, 0); + player.GossipMenuAddItem(0, "Quest 2 description", 5, 0); + player.GossipMenuAddItem(0, "Back", 0, 0); + player.GossipSendMenu(player.GetGossipTextId(source), source.GetGUID()); + } else if (action === 2) { + // Handle the "I have a question about a quest" option + player.GossipMenuAddItem(0, "What are the objectives of Quest 1?", 6, 0); + player.GossipMenuAddItem(0, "Where can I find the items for Quest 2?", 7, 0); + player.GossipMenuAddItem(0, "Back", 0, 0); + player.GossipSendMenu(player.GetGossipTextId(source), source.GetGUID()); + } else if (action === 3) { + // Handle the "Goodbye" option + player.GossipComplete(); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, OnGossipHello); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_SELECT, OnGossipSelect); +``` + +In this example, when the player interacts with the quest giver creature (identified by `QUEST_GIVER_ENTRY`), the `GossipAddQuests` method is called to add the available quests to the player's gossip menu. Additional custom gossip options are added to provide more information about the quests. + +The `OnGossipSelect` event handler is used to handle the player's selection from the gossip menu. Depending on the selected option, different actions are taken, such as providing more details about the quests or answering specific questions. + +This script demonstrates how the `GossipAddQuests` method can be used in conjunction with other gossip-related methods to create an interactive quest giver experience for the player. + +## GossipClearMenu +Clears the [Player]'s current gossip item list. This method is used to clear the gossip menu before adding new items to it. It's important to note that this method is needed when you show a gossip menu without using gossip hello or select hooks, which do this automatically. Usually, this is needed when the [Player] is the sender of a Gossip Menu. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return anything. + +### Example Usage +Let's say you want to create a custom gossip menu for a player when they talk to an NPC. You can use the `GossipClearMenu` method to clear any existing gossip items before adding your custom ones. + +```typescript +const GOSSIP_ICON_CHAT = 0; +const GOSSIP_ICON_VENDOR = 1; +const GOSSIP_ICON_TAXI = 2; +const GOSSIP_ICON_TRAINER = 3; +const GOSSIP_ICON_INTERACT_1 = 4; +const GOSSIP_ICON_INTERACT_2 = 5; +const GOSSIP_ICON_MONEY_BAG = 6; +const GOSSIP_ICON_TALK = 7; +const GOSSIP_ICON_TABARD = 8; +const GOSSIP_ICON_BATTLE = 9; + +const MyCustomGossip: npc_event_on_gossip_hello = (event: number, player: Player, object: GameObject) => { + player.GossipClearMenu(); + + player.GossipMenuAddItem(GOSSIP_ICON_CHAT, "Tell me about this place.", 1); + player.GossipMenuAddItem(GOSSIP_ICON_VENDOR, "I want to browse your goods.", 2); + player.GossipMenuAddItem(GOSSIP_ICON_INTERACT_1, "I have a question.", 3); + + player.GossipSendMenu(1, object, 0); +}; + +RegisterGameObjectEvent(1234, GameObjectEvents.GAMEOBJECT_EVENT_ON_GOSSIP_HELLO, (...args) => MyCustomGossip(...args)); +``` + +In this example, we define a custom gossip event for a specific GameObject with entry ID 1234. When the player interacts with this GameObject, the `MyCustomGossip` function will be called. + +Inside the function, we first clear the player's gossip menu using `GossipClearMenu()`. Then, we add three gossip items using `GossipMenuAddItem()`. Each item has an icon, a text, and a unique identifier. + +Finally, we send the gossip menu to the player using `GossipSendMenu()`, passing the GameObject as the sender and 0 as the text ID (since we're not using any predefined text). + +With this script, when the player interacts with the GameObject, they will see a custom gossip menu with three options to choose from. + +See also: [Player:GossipMenuAddItem], [Player:GossipSendMenu], [Player:GossipAddQuests], [Player:GossipComplete] + +## GossipComplete + +Closes the currently open Gossip Menu for the player. This method is typically used after the player has made a selection from the Gossip Menu, and the script has processed the player's choice. + +### Parameters + +This method does not take any parameters. + +### Returns + +This method does not return any value. + +### Example Usage + +Here's an example of how to use the `GossipComplete` method in a script that handles a Gossip Menu interaction: + +```typescript +const GOSSIP_MENU_OPTION_1 = 0; +const GOSSIP_MENU_OPTION_2 = 1; + +const MyGossipMenu: gossip_select = (event: number, player: Player, creature: Creature, sender: GossipSender, action: number, code: string): void => { + switch (action) { + case GOSSIP_MENU_OPTION_1: + // Handle option 1 + player.AddItem(12345, 1); // Give the player an item + player.SendBroadcastMessage("You have chosen option 1 and received an item!"); + player.GossipComplete(); // Close the Gossip Menu + break; + + case GOSSIP_MENU_OPTION_2: + // Handle option 2 + const questId = 1234; + if (player.CanCompleteQuest(questId)) { + player.CompleteQuest(questId); // Complete a quest + player.SendBroadcastMessage("You have chosen option 2 and completed a quest!"); + } else { + player.SendBroadcastMessage("You do not meet the requirements to complete the quest."); + } + player.GossipComplete(); // Close the Gossip Menu + break; + + default: + player.SendBroadcastMessage("Invalid option selected."); + player.GossipComplete(); // Close the Gossip Menu + break; + } +}; + +RegisterCreatureGossipEvent(12345, MyGossipMenu); +``` + +In this example, the script registers a Gossip Menu event for a specific creature (with entry ID 12345). When the player interacts with the creature and selects an option from the Gossip Menu, the corresponding case block is executed. + +If the player selects option 1, they receive an item and a broadcast message is sent to them. After processing the option, the `GossipComplete` method is called to close the Gossip Menu. + +If the player selects option 2, the script checks if the player meets the requirements to complete a specific quest. If the requirements are met, the quest is completed, and a broadcast message is sent to the player. Otherwise, a message is sent indicating that the player does not meet the requirements. Regardless of the outcome, the `GossipComplete` method is called to close the Gossip Menu. + +If an invalid option is selected, a default message is sent to the player, and the `GossipComplete` method is called to close the Gossip Menu. + +By calling `GossipComplete`, the script ensures that the Gossip Menu is properly closed after processing the player's selection, preventing the menu from remaining open unintentionally. + +See also: [Player:GossipMenuAddItem](./player-gossip-menu-add-item.md), [Player:GossipAddQuests](./player-gossip-add-quests.md), [Player:GossipSendMenu](./player-gossip-send-menu.md), [Player:GossipClearMenu](./player-gossip-clear-menu.md) + +## GossipMenuAddItem + +Adds a new item to the gossip menu shown to the [Player] on the next call to [Player:GossipSendMenu]. + +### Parameters + +- `icon`: number - The icon ID to display next to the gossip item. +- `msg`: string - The text to display for the gossip item. +- `sender`: number - A number passed directly to the gossip selection handler. Internally used for database gossip handling. +- `intid`: number - A number passed directly to the gossip selection handler. Internally used for database gossip handling. +- `code`: boolean (optional) - Specifies whether to show a box to insert text. The player-inserted text is passed to the gossip selection handler. +- `popup`: string (optional) - The text to display in the popup box when `code` is set to true. +- `money`: number (optional) - The amount of money the player needs to have to click the option. An error message is shown if the player doesn't have enough money. Note that the money amount is only checked client-side and is not removed from the player. You will need to check again in your code before taking action. + +### Example Usage + +```typescript +const GOSSIP_ICON_CHAT = 0; +const GOSSIP_ICON_VENDOR = 1; +const GOSSIP_ICON_TAXI = 2; +const GOSSIP_ICON_TRAINER = 3; +const GOSSIP_ICON_INTERACT_1 = 4; +const GOSSIP_ICON_INTERACT_2 = 5; +const GOSSIP_ICON_MONEY_BAG = 6; +const GOSSIP_ICON_TALK = 7; +const GOSSIP_ICON_TABARD = 8; +const GOSSIP_ICON_BATTLE = 9; + +const GOSSIP_SENDER_MAIN = 1; +const INTID_PLAYER_GOLD = 1; +const INTID_PLAYER_ITEMS = 2; +const REQ_MONEY = 1000; + +function onGossipHello(event: PlayerGossipHello, player: Player, object: GameObject): boolean { + player.GossipMenuAddItem(GOSSIP_ICON_CHAT, "Tell me about yourself", GOSSIP_SENDER_MAIN, INTID_PLAYER_GOLD); + player.GossipMenuAddItem(GOSSIP_ICON_VENDOR, "Show me your wares", GOSSIP_SENDER_MAIN, INTID_PLAYER_ITEMS); + player.GossipMenuAddItem(GOSSIP_ICON_MONEY_BAG, "I have items to sell", GOSSIP_SENDER_MAIN, INTID_PLAYER_ITEMS, true, "Enter the item IDs (comma-separated):"); + player.GossipMenuAddItem(GOSSIP_ICON_INTERACT_1, "Special service", GOSSIP_SENDER_MAIN, 0, false, "", REQ_MONEY); + player.GossipSendMenu(1, object, 1); + return true; +} + +function onGossipSelect(event: PlayerGossipSelect, player: Player, object: GameObject, sender: number, action: number, code: string): boolean { + if (sender === GOSSIP_SENDER_MAIN) { + if (action === INTID_PLAYER_GOLD) { + player.SendBroadcastMessage("I am a humble merchant."); + } else if (action === INTID_PLAYER_ITEMS) { + if (code) { + const itemIds = code.split(",").map((id) => parseInt(id.trim(), 10)); + // Process the entered item IDs + // ... + } else { + // Show the vendor's items + // ... + } + } else if (action === 0) { + if (player.GetCoinage() >= REQ_MONEY) { + player.ModifyMoney(-REQ_MONEY); + // Perform the special service + // ... + } else { + player.SendBroadcastMessage("You don't have enough money for the special service."); + } + } + } + player.GossipComplete(); + return true; +} + +RegisterPlayerGossipEvent(1234, 1, GOSSIP_EVENT_ON_HELLO, (event, player, object) => onGossipHello(event, player, object)); +RegisterPlayerGossipEvent(1234, 1, GOSSIP_EVENT_ON_SELECT, (event, player, object, sender, action, code) => onGossipSelect(event, player, object, sender, action, code)); +``` + +In this example, the `onGossipHello` function is called when the player interacts with the gossip NPC. It adds several gossip items to the menu using `GossipMenuAddItem`: + +1. A chat option with no additional functionality. +2. A vendor option to show the NPC's items for sale. +3. An option to sell items to the NPC, which prompts the player to enter item IDs. +4. A special service option that requires a certain amount of money. + +When the player selects a gossip option, the `onGossipSelect` function is called. It handles the different actions based on the `sender` and `action` values. If the player selects the option to sell items, it parses the entered item IDs from the `code` parameter and processes them accordingly. + +Note that the money requirement for the special service is checked both in the gossip menu (client-side) and in the `onGossipSelect` function (server-side) to ensure the player has enough money before performing the action. + +## GossipSendMenu +Sends the current gossip items of the player to him as a gossip menu with header text from the given textId. +If sender is a [Player](./Player.md) then menu_id is mandatory, otherwise it is not used for anything. +menu_id is the ID used to trigger the OnGossipSelect registered for players. See [Global:RegisterPlayerGossipEvent](./Global.md#registerplayergossipevent) +See also: [Player:GossipMenuAddItem](./Player.md#gossipmenadditem), [Player:GossipAddQuests](./Player.md#gossipaddquests), [Player:GossipComplete](./Player.md#gossipcomplete), [Player:GossipClearMenu](./Player.md#gossipmenuclearmenu) + +### Parameters +- npc_text: number - The ID of the npc_text in the database to use as the header text for the gossip menu. +- sender: [Object](./Object.md) - The object sending the gossip menu. If it's a player, menu_id is required. +- menu_id: number - The ID used to trigger the OnGossipSelect event for players. Required if sender is a player. + +### Example Usage +Here's an example of how to create a custom gossip menu for a creature that offers players a choice between two rewards: + +```typescript +const GOSSIP_TEXTID_REWARD_CHOICE = 100; +const GOSSIP_OPTION_REWARD1 = 0; +const GOSSIP_OPTION_REWARD2 = 1; +const ITEM_REWARD1 = 12345; +const ITEM_REWARD2 = 67890; + +const OnGossipHello: creature_event_on_gossip_hello = (event: number, player: Player, creature: Creature) => { + player.GossipClearMenu(); + player.GossipMenuAddItem(0, "I choose reward 1", GOSSIP_OPTION_REWARD1, 0); + player.GossipMenuAddItem(0, "I choose reward 2", GOSSIP_OPTION_REWARD2, 0); + player.GossipSendMenu(GOSSIP_TEXTID_REWARD_CHOICE, creature, 1); +}; + +const OnGossipSelect: player_event_on_gossip_select = (event: number, player: Player, menu: number, sender: Object, intid: number, code: string) => { + if (menu != 1) { + return; + } + + player.GossipClearMenu(); + + switch(intid) { + case GOSSIP_OPTION_REWARD1: + player.AddItem(ITEM_REWARD1, 1); + break; + case GOSSIP_OPTION_REWARD2: + player.AddItem(ITEM_REWARD2, 1); + break; + } + + player.GossipComplete(); +}; + +RegisterCreatureEvent(12345, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, (...args) => OnGossipHello(...args)); +RegisterPlayerGossipEvent(1, (...args) => OnGossipSelect(...args)); +``` + +In this example: +1. When the player interacts with the creature, the OnGossipHello event is triggered. +2. The existing gossip menu is cleared and two new options are added using GossipMenuAddItem. +3. The gossip menu is sent to the player using GossipSendMenu, specifying the header text ID and menu ID. +4. When the player selects an option, the OnGossipSelect event is triggered with the corresponding menu ID. +5. The menu ID is checked to ensure it matches the expected value. +6. Based on the option selected (intid), the appropriate reward item is given to the player. +7. Finally, GossipComplete is called to close the gossip menu. + +## GossipSendPOI +Sends a POI (Point of Interest) to the location on the player's map. This can be used to guide players to a specific location or highlight important areas. + +### Parameters +* x: number - The X coordinate of the POI on the map. +* y: number - The Y coordinate of the POI on the map. +* icon: number - The icon ID to use for the POI. You can find a list of icon IDs in the `POI_ICON_` constants. +* flags: number - The flags for the POI. Use the `GOSSIP_POI_` constants to set the desired flags. +* data: number - Additional data for the POI, such as the ID of a creature or gameobject at the POI's location. +* iconText: string - The text to display when the player hovers over the POI icon on the map. + +### Example Usage +In this example, we create a script that sends a POI to the location of a rare creature when the player talks to a specific NPC. The POI will have a unique icon, be flagged as important, and display the name of the rare creature when hovered over. + +```typescript +const RARE_CREATURE_ENTRY = 12345; +const RARE_CREATURE_NAME = "Elusive Rare Creature"; +const NPC_ENTRY = 54321; +const POI_ICON_SKULL = 0; // Customize the icon as needed +const POI_FLAG_IMPORTANT = 1; // Customize the flags as needed + +const OnGossipHello: npc_event_on_gossip_hello = (event: number, player: Player, object: GameObject) => { + if (object.GetEntry() === NPC_ENTRY) { + const creature = player.GetNearestCreature(RARE_CREATURE_ENTRY, 100); // Check if the rare creature is nearby + if (creature) { + const x = creature.GetX(); + const y = creature.GetY(); + player.GossipSendPOI(x, y, POI_ICON_SKULL, POI_FLAG_IMPORTANT, RARE_CREATURE_ENTRY, RARE_CREATURE_NAME); + player.GossipSendMenu("I've marked the location of the rare creature on your map. Good luck!", object); + } else { + player.GossipSendMenu("Sorry, I couldn't find the rare creature nearby. Please try again later.", object); + } + } +}; + +RegisterGameObjectEvent(GameObjectEvents.GAMEOBJECT_EVENT_ON_GOSSIP_HELLO, NPC_ENTRY, (...args) => OnGossipHello(...args)); +``` + +In this script: +1. We define constants for the rare creature's entry ID, name, the NPC's entry ID, and the desired POI icon and flags. +2. When the player interacts with the specified NPC (`NPC_ENTRY`), the script checks if the rare creature (`RARE_CREATURE_ENTRY`) is nearby using `GetNearestCreature`. +3. If the rare creature is found, we get its coordinates using `GetX` and `GetY`. +4. We send a POI to the player's map using `GossipSendPOI`, passing the coordinates, icon, flags, creature entry, and name. +5. We send a gossip message to the player indicating that the rare creature's location has been marked on their map. +6. If the rare creature is not found, we send a different gossip message informing the player that the creature couldn't be located. + +This script enhances the player's experience by guiding them to the location of a rare creature when they interact with a specific NPC, making it easier for them to find and engage with the creature. + +## GroupCreate +Creates a new [Group](./group.md) with the [Player] as the group leader and the invited [Player] as the initial member. + +### Parameters +* invited: [Player](./player.md) - The player to invite to the newly created group. + +### Returns +[Group](./group.md) - The newly created group with the [Player] as the leader. + +### Example Usage +This example demonstrates how to create a new group when a player whispers "creategroup" to another player. The invited player will automatically join the group if they are not already in one. + +```typescript +const OnWhisper: player_event_on_whisper = (event: number, player: Player, msg: string, type: ChatMsg, lang: Language, playerGuid: number): void => { + if (msg === "creategroup") { + const invitedPlayer = GetPlayerByGUID(playerGuid); + if (invitedPlayer) { + if (!invitedPlayer.IsInGroup()) { + const newGroup = player.GroupCreate(invitedPlayer); + if (newGroup) { + player.SendBroadcastMessage(`You have created a new group with ${invitedPlayer.GetName()}.`); + invitedPlayer.SendBroadcastMessage(`You have been invited to a new group by ${player.GetName()}.`); + } else { + player.SendBroadcastMessage("Failed to create a new group."); + } + } else { + player.SendBroadcastMessage(`${invitedPlayer.GetName()} is already in a group.`); + } + } else { + player.SendBroadcastMessage("Invalid player specified for group creation."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_WHISPER, (...args) => OnWhisper(...args)); +``` + +In this example: +1. When a player whispers "creategroup" to another player, the `OnWhisper` event is triggered. +2. The script retrieves the invited player using `GetPlayerByGUID` based on the `playerGuid` provided in the event. +3. It checks if the invited player is not already in a group using `IsInGroup()`. +4. If the invited player is not in a group, the script calls `GroupCreate(invitedPlayer)` on the whispering player to create a new group with the invited player. +5. If the group is successfully created, both players receive a broadcast message confirming the group creation. +6. If the invited player is already in a group or if the group creation fails, appropriate messages are sent to the whispering player. + +This script allows players to easily create a new group by whispering a specific command to another player, automating the group creation process. + +## GroupEventHappens +This method allows a player to complete a quest if they are in a group and the specified game object or creature is the quest credit marker. + +### Parameters +* quest: number - The quest entry ID from the quest_template table. +* obj: [WorldObject](./worldobject.md) - The WorldObject that gives the quest credit. This can be a `[Creature]` or `[GameObject]` + +### Example Usage +This example will complete a group quest when a player interacts with a specific game object, but only if the player is in a group. +```typescript +const QUEST_ENTRY = 1234; +const QUEST_CREDIT_GO_ENTRY = 5678; + +const GOHello : gob_event_on_hello = (event: number, obj: GameObject, player: Player) => { + const group = player.GetGroup(); + + if (obj.GetEntry() === QUEST_CREDIT_GO_ENTRY && group) { + const members = group.GetMembers(); + + members.forEach((member) => { + if (member.IsInWorld() && member.IsInRange(obj, 10) && member.HasQuest(QUEST_ENTRY)) { + member.GroupEventHappens(QUEST_ENTRY, obj); + } + }); + } +}; + +RegisterGameObjectEvent(GameObjectEvents.GAMEOBJECT_EVENT_ON_HELLO, (...args) => GOHello(...args)); +``` + +In this example: +1. We define constants for the quest entry and the game object that gives quest credit. +2. In the `GAMEOBJECT_EVENT_ON_HELLO` event (triggered when a player interacts with a game object), we first check if the game object interacted with matches our defined entry and if the player is in a group. +3. If the player is in a group, we get all group members. +4. We iterate over each group member and check if they are: + - In the world (online) + - Within 10 yards of the game object + - Currently on the quest +5. If a group member satisfies all these conditions, we call `GroupEventHappens` on them, passing the quest entry and the game object. This will give them credit for the quest. +6. Finally, we register this function to the `GAMEOBJECT_EVENT_ON_HELLO` event. + +This script ensures that when a player in a group interacts with the specified game object, all eligible group members within range will receive quest credit, allowing the group to complete the quest together. + +## GroupInvite +Invites another player to join the inviting player's group. + +### Parameters +* invited: [Player](./player.md) - The player to invite to the group. + +### Returns +* boolean - Returns `true` if the invitation was successful, `false` otherwise. + +### Example Usage +This example demonstrates how to create a custom command that allows a player to invite another player to their group by targeting them and using the command `.invitetogroup`. If the invitation is successful, a message is sent to both players confirming the invitation. + +```typescript +const TARGET_FLAG_UNIT = 0x002; + +function isValidTarget(player: Player) { + const target = player.GetSelection(); + return target && target.IsPlayer() && target.GetGUID() !== player.GetGUID(); +} + +function OnCommand(player: Player, command: string, args: string[]): boolean { + if (command === 'invitetogroup') { + if (!isValidTarget(player)) { + player.SendBroadcastMessage('You must target another player to invite them to your group.'); + return false; + } + + const invitedPlayer = player.GetSelection() as Player; + + if (player.IsInGroup()) { + if (!player.IsGroupLeader()) { + player.SendBroadcastMessage('You must be the group leader to invite players.'); + return false; + } + } else { + player.GroupCreate(); + } + + if (player.GroupInvite(invitedPlayer)) { + player.SendBroadcastMessage(`You have invited ${invitedPlayer.GetName()} to join your group.`); + invitedPlayer.SendBroadcastMessage(`${player.GetName()} has invited you to join their group.`); + } else { + player.SendBroadcastMessage(`Failed to invite ${invitedPlayer.GetName()} to your group.`); + } + + return true; + } + + return false; +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (event, player, command, args) => OnCommand(player, command, args)); +``` + +In this example: +1. We define a helper function `isValidTarget` to check if the player's target is a valid player to invite (not themselves and an actual player). +2. In the `OnCommand` function, we first check if the command is `invitetogroup`. +3. We then check if the player has a valid target using the `isValidTarget` function. If not, we send a message to the player and return. +4. We get the targeted player using `GetSelection` and cast it to a `Player`. +5. If the inviting player is not in a group, we create a new group for them using `GroupCreate`. If they are in a group but not the leader, we send a message and return. +6. We call `GroupInvite` with the targeted player and check the result. +7. If the invitation was successful, we send confirmation messages to both players. Otherwise, we send a failure message to the inviting player. +8. Finally, we register the `OnCommand` function to handle the `PLAYER_EVENT_ON_COMMAND` event. + +This example showcases how to use the `GroupInvite` method, along with other related methods and events, to create a custom command for inviting players to a group. + +## HasAchieved +Check if a player has completed a specific achievement by providing the achievement ID. + +### Parameters +* achievementId: number - The ID of the achievement to check. You can find achievement IDs in the `achievement` table in the world database. + +### Returns +* boolean - Returns `true` if the player has completed the specified achievement, `false` otherwise. + +### Example Usage +Let's say we want to grant a special item to players who have completed the "Explore Eastern Kingdoms" achievement (ID: 42). + +```typescript +const EASTERN_KINGDOMS_ACHIEVEMENT_ID = 42; +const SPECIAL_ITEM_ENTRY = 12345; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + if (player.HasAchieved(EASTERN_KINGDOMS_ACHIEVEMENT_ID)) { + const itemCount = player.GetItemCount(SPECIAL_ITEM_ENTRY); + + if (itemCount === 0) { + const item = player.AddItem(SPECIAL_ITEM_ENTRY, 1); + + if (item) { + player.SendBroadcastMessage("Congratulations on exploring the Eastern Kingdoms! Here's a special item for you."); + } else { + player.SendBroadcastMessage("You have explored the Eastern Kingdoms, but your inventory is full. Please make space and relog to receive your special item."); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: + +1. We define the achievement ID for "Explore Eastern Kingdoms" and the entry for the special item we want to grant. + +2. In the `OnLogin` event, we check if the player has completed the achievement using `player.HasAchieved(EASTERN_KINGDOMS_ACHIEVEMENT_ID)`. + +3. If the player has completed the achievement, we check if they already have the special item in their inventory using `player.GetItemCount(SPECIAL_ITEM_ENTRY)`. + +4. If the player doesn't have the item, we attempt to add it to their inventory using `player.AddItem(SPECIAL_ITEM_ENTRY, 1)`. + +5. If the item is successfully added, we send a congratulatory message to the player. If the item cannot be added (e.g., due to a full inventory), we inform the player to make space and relog to receive the item. + +This example demonstrates how to use the `HasAchieved` method to check if a player has completed a specific achievement and grant a reward based on that completion. + +## HasAtLoginFlag +Checks if the player has a specific login flag set. Login flags are used to perform certain actions when a player logs in, such as showing a cinematic, resetting talents, or renaming the character. + +### Parameters +- flag: number - The login flag to check. Possible values: + - 0x01 (1): AT_LOGIN_RENAME + - 0x02 (2): AT_LOGIN_RESET_SPELLS + - 0x04 (4): AT_LOGIN_RESET_TALENTS + - 0x08 (8): AT_LOGIN_CUSTOMIZE + - 0x10 (16): AT_LOGIN_RESET_PET_TALENTS + - 0x20 (32): AT_LOGIN_FIRST + - 0x40 (64): AT_LOGIN_CHANGE_FACTION + - 0x80 (128): AT_LOGIN_CHANGE_RACE + - 0x100 (256): AT_LOGIN_RESURRECT + - 0x200 (512): AT_LOGIN_RESTORE_DEL_ITEMS + +### Returns +- boolean: Returns true if the player has the specified login flag set, false otherwise. + +### Example Usage +This example checks if a player needs to rename their character upon login and performs the necessary actions. + +```typescript +const AT_LOGIN_RENAME = 0x01; + +function OnLogin(event: PlayerEvents, player: Player) { + if (player.HasAtLoginFlag(AT_LOGIN_RENAME)) { + player.SendAddonMessage("You need to rename your character."); + player.SetAtLoginFlag(AT_LOGIN_RENAME, true); + + // Prevent the player from moving until they rename their character + player.SetMovement(MOVE_ROOT); + + // Start a rename request + player.SetRename(true); + + // Set a timer to check if the player has renamed their character after 1 minute + player.RegisterEvent(CheckRename, 1000 * 60, 1, player); + } +} + +function CheckRename(player: Player) { + if (player.HasAtLoginFlag(AT_LOGIN_RENAME)) { + player.SendAddonMessage("You have been disconnected for not renaming your character."); + player.KickPlayer(); + } else { + // Player has renamed their character, remove the movement restriction + player.SetMovement(MOVE_UNROOT); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +``` + +In this example: +1. When a player logs in, the script checks if they have the `AT_LOGIN_RENAME` flag set. +2. If the flag is set, the player is informed that they need to rename their character. +3. The `AT_LOGIN_RENAME` flag is set again to ensure it persists after the rename. +4. The player is rooted in place to prevent them from moving until they rename their character. +5. A rename request is started for the player. +6. A timer is set to check if the player has renamed their character after 1 minute. +7. If the player hasn't renamed their character within 1 minute, they are disconnected. +8. If the player renames their character, the movement restriction is removed, allowing them to play normally. + +## HasItem +Checks if the player has a specific item in their inventory or bank. + +### Parameters +* itemId: number - The entry of the item to check for. +* count?: number - (Optional) The minimum amount of the item required. Defaults to 1. +* check_bank?: boolean - (Optional) If true, the bank will also be checked. Defaults to false. + +### Returns +* boolean - Returns true if the player has the specified amount of the item, false otherwise. + +### Example Usage +Check if the player has the required items to complete a quest: +```typescript +const QUEST_ITEM_1 = 12345; +const QUEST_ITEM_2 = 67890; +const QUEST_ITEM_1_COUNT = 5; +const QUEST_ITEM_2_COUNT = 1; + +const CompleteQuestScript: player_event_on_quest_complete = (event: number, player: Player, quest: Quest) => { + const hasRequiredItems = player.HasItem(QUEST_ITEM_1, QUEST_ITEM_1_COUNT) && player.HasItem(QUEST_ITEM_2, QUEST_ITEM_2_COUNT); + + if (!hasRequiredItems) { + player.SendBroadcastMessage("You do not have the required items to complete this quest."); + quest.FailQuest(); + return; + } + + player.RemoveItem(QUEST_ITEM_1, QUEST_ITEM_1_COUNT); + player.RemoveItem(QUEST_ITEM_2, QUEST_ITEM_2_COUNT); + + // Reward the player with experience and gold + player.GiveXP(1000); + player.ModifyMoney(100 * 10000); // 100 gold + + quest.CompleteQuest(); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => CompleteQuestScript(...args)); +``` + +In this example, when a player completes a quest, the script checks if the player has the required quest items (QUEST_ITEM_1 and QUEST_ITEM_2) in the specified amounts. If the player does not have the required items, the quest is failed, and the player is informed via a broadcast message. If the player has the required items, the items are removed from the player's inventory, and the player is rewarded with experience and gold. Finally, the quest is marked as completed. + +## HasQuest +Checks if the player has an active quest by the provided quest ID. + +### Parameters +* questId: number - The ID of the quest to check. + +### Returns +* boolean - Returns 'true' if the player has the specified quest active, 'false' otherwise. + +### Example Usage +In this example, we'll create a script that checks if the player has a specific quest active. If the player has the quest, they will receive a special item and a notification. If they don't have the quest, they will receive a message encouraging them to accept the quest. + +```typescript +const SPECIAL_QUEST_ID = 1234; +const SPECIAL_ITEM_ENTRY = 5678; +const SPECIAL_ITEM_COUNT = 1; + +const SpecialQuestCheck: player_event_on_login = (event: number, player: Player) => { + if (player.HasQuest(SPECIAL_QUEST_ID)) { + const item = player.AddItem(SPECIAL_ITEM_ENTRY, SPECIAL_ITEM_COUNT); + if (item) { + player.SendBroadcastMessage(`You have received a special item for having the quest ${SPECIAL_QUEST_ID} active!`); + } else { + player.SendBroadcastMessage(`You have the quest ${SPECIAL_QUEST_ID} active, but your inventory is full. Make space and log in again to receive your special item!`); + } + } else { + player.SendBroadcastMessage(`You don't have the special quest ${SPECIAL_QUEST_ID} active. Accept the quest to receive a special item!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => SpecialQuestCheck(...args)); +``` + +In this script, we define the `SPECIAL_QUEST_ID`, `SPECIAL_ITEM_ENTRY`, and `SPECIAL_ITEM_COUNT` constants for the quest ID, item entry, and item count, respectively. + +When a player logs in, the `SpecialQuestCheck` function is called. It checks if the player has the `SPECIAL_QUEST_ID` active using the `HasQuest` method. If the player has the quest active, it attempts to add the `SPECIAL_ITEM_ENTRY` to the player's inventory using the `AddItem` method. If the item is successfully added, the player receives a broadcast message confirming they received the special item. If the player's inventory is full, they receive a message asking them to make space and log in again. + +If the player doesn't have the special quest active, they receive a message encouraging them to accept the quest to receive the special item. + +This example demonstrates how the `HasQuest` method can be used in combination with other methods to create engaging and interactive scripts for players based on their quest progress. + +## HasQuestForGO +This method checks if the player has a quest that involves a specific game object. It is useful when creating custom game object scripts that require the player to have a specific quest before interacting with the object. + +### Parameters +* entry: number - The entry ID of the game object to check for associated quests. + +### Returns +* boolean - Returns true if the player has a quest associated with the specified game object, false otherwise. + +### Example Usage +In this example, we create a custom script for a game object that requires the player to have a specific quest before they can interact with it. If the player has the required quest, they will be able to use the game object and receive a reward. If they don't have the quest, they will receive a message indicating that they need to obtain the quest first. + +```typescript +const GAME_OBJECT_ENTRY = 12345; +const REQUIRED_QUEST_ENTRY = 67890; +const REWARD_ITEM_ENTRY = 54321; +const REWARD_ITEM_COUNT = 1; + +const GameObjectUse = (event: GameObjectEvents, player: Player, gameObject: GameObject) => { + if (gameObject.GetEntry() === GAME_OBJECT_ENTRY) { + if (player.HasQuestForGO(GAME_OBJECT_ENTRY)) { + player.SendBroadcastMessage("You have the required quest. Here's your reward!"); + const rewardItem = player.AddItem(REWARD_ITEM_ENTRY, REWARD_ITEM_COUNT); + if (rewardItem) { + player.SendBroadcastMessage(`You received ${rewardItem.GetName()}`); + } else { + player.SendBroadcastMessage("Failed to add reward item to your inventory."); + } + } else { + player.SendBroadcastMessage("You don't have the required quest to use this object. Please obtain the quest first!"); + } + } +}; + +RegisterGameObjectEvent(GameObjectEvents.GAMEOBJECT_EVENT_ON_USE, GameObjectUse); +``` + +In this script: +1. We define constants for the game object entry, required quest entry, reward item entry, and reward item count. +2. We register a game object event handler for the `GAMEOBJECT_EVENT_ON_USE` event. +3. When a player uses the game object, we check if the game object's entry matches the specified entry. +4. If the entry matches, we use the `HasQuestForGO` method to check if the player has the required quest. +5. If the player has the quest, we send them a message indicating that they have the required quest and reward them with an item using the `AddItem` method. +6. If the item is successfully added to the player's inventory, we send a message with the item's name. Otherwise, we send a message indicating that the item couldn't be added. +7. If the player doesn't have the required quest, we send them a message indicating that they need to obtain the quest first. + +This example demonstrates how the `HasQuestForGO` method can be used in conjunction with other player methods and game events to create custom game object interactions based on quest requirements. + +## HasQuestForItem +This method checks if the player has a quest that requires the specified item. + +### Parameters +* entry: number - The item entry to check for. + +### Returns +* boolean - Returns 'true' if the player has a quest that requires the specified item, 'false' otherwise. + +### Example Usage +This example script will check if the player has a quest that requires the item they are trying to sell to a vendor. If they do, it will prevent the sale and send a message to the player. + +```typescript +const ItemEntry = 12345; // Replace with the desired item entry + +const OnSellItem: player_event_on_sell_item = (event: number, player: Player, vendor: Creature, item: Item, count: number) => { + if (player.HasQuestForItem(item.GetEntry())) { + player.SendBroadcastMessage(`You cannot sell this item as it is required for a quest.`); + player.SendAreaTriggerMessage(`You cannot sell this item as it is required for a quest.`); + return 1; // Prevent the sale + } + return 0; // Allow the sale +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SELL_ITEM, (...args) => OnSellItem(...args)); +``` + +In this example: +1. We define the item entry we want to check for in the `ItemEntry` constant. Replace it with the desired item entry. +2. We register the `OnSellItem` event handler using `RegisterPlayerEvent` and the `PlayerEvents.PLAYER_EVENT_ON_SELL_ITEM` event. +3. Inside the event handler, we use the `HasQuestForItem` method to check if the player has a quest that requires the item they are trying to sell. +4. If the player has a quest for the item: + - We send a broadcast message and an area trigger message to the player, informing them that they cannot sell the item because it is required for a quest. + - We return 1 to prevent the sale of the item. +5. If the player does not have a quest for the item, we return 0 to allow the sale. + +This script ensures that players cannot accidentally sell items that are required for their active quests. It provides a helpful message to the player and prevents the sale of the quest item. + +## HasSkill +Checks if the player has a specific skill by the skill ID. + +### Parameters +* skill: number - The ID of the skill to check. + +### Returns +* boolean - Returns 'true' if the player has the specified skill, 'false' otherwise. + +### Example Usage +This example demonstrates how to check if a player has the required skill to perform a specific action, such as mining a node or skinning a creature. + +```typescript +const MINING_SKILL_ID = 186; +const REQUIRED_MINING_SKILL = 250; + +const onGameObjectUse: on_gameobject_use = (event: number, player: Player, gameObject: GameObject) => { + const COPPER_VEIN_ENTRY = 1731; + const TIN_VEIN_ENTRY = 1732; + const IRON_VEIN_ENTRY = 1735; + + if (gameObject.GetEntry() === COPPER_VEIN_ENTRY || gameObject.GetEntry() === TIN_VEIN_ENTRY || gameObject.GetEntry() === IRON_VEIN_ENTRY) { + if (player.HasSkill(MINING_SKILL_ID)) { + const playerMiningSkill = player.GetSkillValue(MINING_SKILL_ID); + + if (playerMiningSkill >= REQUIRED_MINING_SKILL) { + // Player has the required mining skill, allow them to mine the node + player.SendBroadcastMessage("You successfully mined the node!"); + // Add your mining logic here, such as giving the player ore items or experience + } else { + player.SendBroadcastMessage("Your mining skill is too low to mine this node."); + } + } else { + player.SendBroadcastMessage("You do not have the mining skill."); + } + } +}; + +RegisterGameObjectEvent(0, GameObjectEvents.GAMEOBJECT_EVENT_ON_USE, (...args) => onGameObjectUse(...args)); +``` + +In this example, when a player interacts with a specific mining node (copper, tin, or iron vein), the script checks if the player has the mining skill using the `HasSkill()` method. If the player has the mining skill, it further checks if their skill level is high enough to mine the node. If the player meets the skill requirements, they are allowed to mine the node, and a success message is sent to the player. Otherwise, appropriate messages are sent to inform the player that their mining skill is too low or they do not have the mining skill at all. + +This example showcases how the `HasSkill()` method can be used in combination with other methods and game events to create more complex and interactive gameplay mechanics based on a player's skills and proficiencies. + +## HasSpell +Checks if the player has a specific spell by the spell ID. + +### Parameters +* spellId: number - The ID of the spell to check for. + +### Returns +* boolean - Returns 'true' if the player has the specified spell, 'false' otherwise. + +### Example Usage +In this example, we'll create a script that checks if a player has a specific spell when they enter the world. If they don't have the spell, it will be taught to them. + +```typescript +const SPELL_ID = 12345; // Replace with the desired spell ID + +const OnPlayerEnterWorld: player_event_on_enter_world = (event: number, player: Player) => { + if (!player.HasSpell(SPELL_ID)) { + // Player doesn't have the spell, teach it to them + player.LearnSpell(SPELL_ID); + player.SendBroadcastMessage(`You have been taught the spell with ID ${SPELL_ID}.`); + } else { + // Player already has the spell + player.SendBroadcastMessage(`You already know the spell with ID ${SPELL_ID}.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_WORLD, (...args) => OnPlayerEnterWorld(...args)); +``` + +In this script: +1. We define the desired spell ID in the `SPELL_ID` constant. +2. We register the `OnPlayerEnterWorld` event handler using `RegisterPlayerEvent` and the `PLAYER_EVENT_ON_ENTER_WORLD` event. +3. Inside the event handler, we use the `HasSpell` method to check if the player has the specified spell. +4. If the player doesn't have the spell, we use the `LearnSpell` method to teach the spell to the player and send them a broadcast message informing them about it. +5. If the player already has the spell, we send them a broadcast message indicating that they already know the spell. + +This script ensures that the player always has the specified spell when they enter the world. If they don't have it, the script will teach it to them automatically. + +## HasSpellCooldown +Check if a spell is currently on cooldown for the player. + +### Parameters +* spellId: number - The ID of the spell to check the cooldown for. + +### Returns +* boolean - Returns 'true' if the spell is currently on cooldown, 'false' otherwise. + +### Example Usage +Script to check if a player has a specific spell on cooldown and perform actions based on the result. +```typescript +const SPELL_ID = 12345; // Replace with the desired spell ID +const COOLDOWN_MESSAGE = "The spell is currently on cooldown. Please wait before using it again."; +const READY_MESSAGE = "The spell is ready to be used!"; + +const onSpellCast: player_event_on_cast_spell = (event: number, player: Player, spell: Spell) => { + if (spell.GetEntry() === SPELL_ID) { + if (player.HasSpellCooldown(SPELL_ID)) { + player.SendBroadcastMessage(COOLDOWN_MESSAGE); + player.InterruptSpell(); // Interrupt the spell cast if it's on cooldown + } else { + player.SendBroadcastMessage(READY_MESSAGE); + // Perform additional actions when the spell is ready to be used + // For example, apply a buff or grant a temporary power-up + const BUFF_SPELL_ID = 54321; // Replace with the desired buff spell ID + player.CastSpell(player, BUFF_SPELL_ID, true); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CAST_SPELL, (...args) => onSpellCast(...args)); +``` + +In this example: +1. We define the specific spell ID (`SPELL_ID`) that we want to check the cooldown for. +2. We define messages to send to the player based on whether the spell is on cooldown or ready to be used. +3. In the `onSpellCast` event callback, we check if the cast spell matches the desired spell ID. +4. If the spell is on cooldown (`player.HasSpellCooldown(SPELL_ID)` returns `true`), we send the `COOLDOWN_MESSAGE` to the player and interrupt the spell cast using `player.InterruptSpell()`. +5. If the spell is not on cooldown (`player.HasSpellCooldown(SPELL_ID)` returns `false`), we send the `READY_MESSAGE` to the player. +6. We can perform additional actions when the spell is ready to be used, such as applying a buff or granting a temporary power-up to the player. In this example, we cast a buff spell (`BUFF_SPELL_ID`) on the player using `player.CastSpell(player, BUFF_SPELL_ID, true)`. +7. Finally, we register the `onSpellCast` callback function to the `PLAYER_EVENT_ON_CAST_SPELL` event using `RegisterPlayerEvent()`. + +This script demonstrates how to use the `HasSpellCooldown` method to check if a specific spell is on cooldown for the player and perform different actions based on the result. It provides a practical example of managing spell cooldowns and enhancing gameplay by applying buffs or power-ups when the spell is ready to be used. + +## HasTalent +Checks if the player has a specific talent in a given talent specialization. + +### Parameters +* spellId: number - The spell ID of the talent to check for. +* spec: number - The talent specialization to check in (0-2). + +### Returns +* boolean - Returns 'true' if the player has the specified talent in the given spec, 'false' otherwise. + +### Example Usage +Check if the player has a specific talent before granting bonus loot. +```typescript +const JUDGEMENT_OF_LIGHT_TALENT = 20185; +const EXTRA_LOOT_ITEM_ENTRY = 123456; +const EXTRA_LOOT_ITEM_COUNT = 1; + +const BonusLootWithTalent: player_event_on_loot_item = (event: number, player: Player, item: Item) => { + const PROTECTION_PALADIN_SPEC = 2; + + if (player.GetClass() == Classes.CLASS_PALADIN) { + if (player.HasTalent(JUDGEMENT_OF_LIGHT_TALENT, PROTECTION_PALADIN_SPEC)) { + const lootedItem = player.GetItemByEntry(item.GetEntry()); + if (lootedItem) { + const lootedItemCount = lootedItem.GetCount(); + if (lootedItemCount >= 5) { + player.AddItem(EXTRA_LOOT_ITEM_ENTRY, EXTRA_LOOT_ITEM_COUNT); + player.SendBroadcastMessage("You received bonus loot for having the Judgement of Light talent!"); + } + } + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, (...args) => BonusLootWithTalent(...args)); +``` + +In this example, whenever a player loots an item, the script checks if the player is a Paladin and has the Judgement of Light talent in the Protection specialization. If the player has the talent and has looted at least 5 of the same item, they are granted an extra item as a bonus reward. + +This script demonstrates how to use the `HasTalent` method to check for a specific talent in a given specialization, and how to combine it with other methods like `GetClass`, `GetItemByEntry`, and `GetCount` to create more complex loot bonus conditions based on the player's talents and looted items. + +## HasTitle +Checks if the player has a specific title by the title ID. + +### Parameters +* titleId: number - The ID of the title to check. + +### Returns +* boolean - Returns 'true' if the player has the title, 'false' otherwise. + +### Example Usage +Check if the player has the "Jenkins" title and grant a special item if they do. + +```typescript +const JENKINS_TITLE_ID = 143; +const SPECIAL_ITEM_ENTRY = 12345; + +const OnPlayerLogin: player_event_on_login = (event: PlayerEvents, player: Player) => { + if (player.HasTitle(JENKINS_TITLE_ID)) { + const item = player.AddItem(SPECIAL_ITEM_ENTRY, 1); + if (item) { + player.SendBroadcastMessage("You have been granted a special item for having the 'Jenkins' title!"); + } else { + player.SendBroadcastMessage("You have the 'Jenkins' title, but your inventory is full. Please make space and log in again to receive your special item."); + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnPlayerLogin); +``` + +In this example: +1. We define constants for the "Jenkins" title ID and the special item entry. +2. We register a player event handler for the `PLAYER_EVENT_ON_LOGIN` event. +3. When a player logs in, we check if they have the "Jenkins" title using the `HasTitle()` method. +4. If the player has the title, we attempt to add the special item to their inventory using `AddItem()`. +5. If the item is successfully added, we send a broadcast message to the player informing them about the special item. +6. If the player's inventory is full and the item cannot be added, we send a different message asking them to make space and log in again to receive the item. + +This example demonstrates how the `HasTitle()` method can be used in combination with other methods and events to create a custom script that rewards players for having a specific title. + +## HasMeleeSpec +Determines if the player's current talent specialization is a melee specialization. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player's current talent specialization is a melee spec (e.g., Warrior, Rogue, Paladin, Death Knight, Shaman Enhancement, Druid Feral), otherwise returns `false`. + +### Example Usage +In this example, we create a script that adjusts the player's melee damage based on their specialization and the type of weapon they have equipped. + +```typescript +const MELEE_DAMAGE_BONUS = 0.1; // 10% bonus damage +const MELEE_WEAPON_SUBCLASSES = [0, 1, 4, 5, 6, 7, 8, 10, 13, 15]; // Melee weapon subclasses + +const onPlayerDamage: player_event_on_deal_melee_damage = (event: number, player: Player, enemy: Unit, damage: number, spellInfo: SpellInfo) => { + if (player.HasMeleeSpec()) { + const mainHandItem = player.GetItemByPos(InventorySlots.INVENTORY_SLOT_BAG_0, InventorySlots.EQUIPMENT_SLOT_MAINHAND); + const offHandItem = player.GetItemByPos(InventorySlots.INVENTORY_SLOT_BAG_0, InventorySlots.EQUIPMENT_SLOT_OFFHAND); + + if (mainHandItem && MELEE_WEAPON_SUBCLASSES.includes(mainHandItem.GetSubClass())) { + damage = damage * (1 + MELEE_DAMAGE_BONUS); + } + + if (offHandItem && MELEE_WEAPON_SUBCLASSES.includes(offHandItem.GetSubClass())) { + damage = damage * (1 + MELEE_DAMAGE_BONUS); + } + + player.DealDamage(enemy, damage, true, 0, spellInfo); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEAL_MELEE_DAMAGE, (...args) => onPlayerDamage(...args)); +``` + +In this script: +1. We define constants for the melee damage bonus percentage and an array of melee weapon subclasses. +2. We register the `PLAYER_EVENT_ON_DEAL_MELEE_DAMAGE` event and provide a callback function. +3. Inside the callback, we first check if the player has a melee specialization using the `HasMeleeSpec()` method. +4. If the player has a melee spec, we retrieve their main-hand and off-hand items using `GetItemByPos()`. +5. For each item (main-hand and off-hand), we check if it belongs to one of the melee weapon subclasses. +6. If an item is a melee weapon, we multiply the original damage by `(1 + MELEE_DAMAGE_BONUS)` to apply the bonus damage. +7. Finally, we use `DealDamage()` to apply the adjusted damage to the enemy unit. + +This script enhances the player's melee damage output if they have a melee specialization and are using melee weapons, providing an incentive for players to choose melee specializations and use appropriate weapons. + +## HasTankSpec +Determines if the player's talent specialization is a tanking spec. + +### Parameters +None + +### Returns +boolean - Returns true if the player has a tanking specialization, otherwise returns false. + +### Example Usage +This example demonstrates how to use the `HasTankSpec()` method to identify if a player is a tank and grant them a bonus item. + +```typescript +const TANK_BONUS_ITEM = 12345; // Replace with the actual item entry ID + +function OnLootItem(event: PlayerEvents, player: Player, item: Item, count: number): void { + if (player.HasTankSpec()) { + // Check if the player already has the tank bonus item + if (!player.HasItem(TANK_BONUS_ITEM)) { + // Add the tank bonus item to the player's inventory + const bonusItem = player.AddItem(TANK_BONUS_ITEM, 1); + if (bonusItem) { + player.SendBroadcastMessage("As a tank, you have been granted a bonus item!"); + } else { + player.SendBroadcastMessage("Your inventory is full. Unable to receive the tank bonus item."); + } + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, OnLootItem); +``` + +In this example: +1. We define a constant `TANK_BONUS_ITEM` to represent the entry ID of the bonus item we want to grant to tank players. +2. We create a function `OnLootItem` that is triggered when a player loots an item. +3. Inside the function, we use the `HasTankSpec()` method to check if the player has a tanking specialization. +4. If the player is a tank and doesn't already have the bonus item (checked using `HasItem()`), we proceed to add the bonus item to their inventory using `AddItem()`. +5. If the item is successfully added to the player's inventory (`bonusItem` is truthy), we send a broadcast message to the player informing them that they have received the bonus item. +6. If the player's inventory is full and the item cannot be added, we send a different broadcast message to notify the player. +7. Finally, we register the `OnLootItem` function to the `PLAYER_EVENT_ON_LOOT_ITEM` event using `RegisterPlayerEvent()`. + +This example showcases how the `HasTankSpec()` method can be used in combination with other methods like `HasItem()` and `AddItem()` to create a script that rewards tank players with a bonus item when they loot any item, ensuring that they only receive the bonus item once. + +## HasHealSpec +This method will return true if the player's current talent specialization is a healing specialization. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player has a healing specialization, `false` otherwise. + +### Example Usage +This example will check if the player has a healing specialization when they enter combat. If they do, it will cast Power Word: Shield on the player. + +```typescript +const POWER_WORD_SHIELD_SPELL_ID = 17; + +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + if (player.HasHealSpec()) { + const shield = player.GetSpellInfo(POWER_WORD_SHIELD_SPELL_ID); + if (shield) { + if (player.Mana >= shield.ManaCost) { + if (!player.HasAura(POWER_WORD_SHIELD_SPELL_ID)) { + player.CastSpell(player, POWER_WORD_SHIELD_SPELL_ID, true); + player.SendBroadcastMessage("You have been shielded by the Light!"); + } + } else { + player.SendBroadcastMessage("Not enough mana to cast Power Word: Shield!"); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this example: +1. We define the spell ID for Power Word: Shield. +2. When the player enters combat, we check if they have a healing specialization using `HasHealSpec()`. +3. If they do, we get the spell information for Power Word: Shield using `GetSpellInfo()`. +4. We check if the player has enough mana to cast the spell by comparing their current mana to the spell's mana cost. +5. If they have enough mana, we check if the player already has the aura for Power Word: Shield using `HasAura()`. +6. If they don't have the aura, we cast Power Word: Shield on the player using `CastSpell()` and send them a message using `SendBroadcastMessage()`. +7. If they don't have enough mana, we send them a message letting them know. + +This script ensures that healers entering combat will always have Power Word: Shield active on them, as long as they have the mana to cast it. It's a simple way to give healers a little extra protection when they enter combat. + +## HasCasterSpec +Determines if the player's current talent specialization is a caster spec (such as mage, warlock, priest, etc). This method is useful for adjusting gameplay mechanics, rewards, or challenges based on the player's chosen specialization. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player has a caster spec, `false` otherwise. + +### Example Usage +Adjust the rewards given to a player based on their specialization upon completing a quest. +```typescript +const questCompleteHandler: player_event_on_quest_complete = (event: number, player: Player, quest: Quest): void => { + const QUEST_ENTRY = 1234; + const CASTER_REWARD_ITEM = 5678; + const MELEE_REWARD_ITEM = 9012; + const HEALER_REWARD_ITEM = 3456; + + if (quest.GetEntry() === QUEST_ENTRY) { + if (player.HasCasterSpec()) { + player.AddItem(CASTER_REWARD_ITEM, 1); + player.SendBroadcastMessage("You have been rewarded with a caster item for completing the quest!"); + } else if (player.GetClass() === Classes.CLASS_PRIEST || player.GetClass() === Classes.CLASS_DRUID) { + player.AddItem(HEALER_REWARD_ITEM, 1); + player.SendBroadcastMessage("You have been rewarded with a healer item for completing the quest!"); + } else { + player.AddItem(MELEE_REWARD_ITEM, 1); + player.SendBroadcastMessage("You have been rewarded with a melee item for completing the quest!"); + } + + player.SendAreaTriggerMessage("Congratulations on completing the quest! Your reward has been added to your inventory."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => questCompleteHandler(...args)); +``` + +In this example, when a player completes a specific quest (identified by `QUEST_ENTRY`), the script checks if the player has a caster specialization using the `HasCasterSpec()` method. If true, the player is rewarded with a caster-specific item (`CASTER_REWARD_ITEM`). If the player is a priest or druid (assuming they are healing specs), they receive a healer-specific item (`HEALER_REWARD_ITEM`). Otherwise, the player is given a melee-specific item (`MELEE_REWARD_ITEM`). + +The script also sends a broadcast message to the player, informing them of the specific reward they received, and an area trigger message congratulating them on completing the quest and notifying them that the reward has been added to their inventory. + +This example demonstrates how the `HasCasterSpec()` method can be used in conjunction with other player-related methods and game events to create a more dynamic and tailored experience for players based on their chosen specialization. + +## InArena +This method checks if the player is currently in an arena. It is useful to check if the player is in an arena before applying certain mechanics or rewards that should only work inside or outside of arenas. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is in an arena, `false` otherwise. + +### Example Usage +This example script rewards players with bonus honor when they kill a player in a battleground, but not in an arena: + +```typescript +const BONUS_HONOR = 100; + +const OnPVPKill: player_event_on_pvp_kill = (event: number, killer: Player, killed: Player) => { + if (killer.InBattleground()) { + if (!killer.InArena()) { + killer.ModifyHonorPoints(BONUS_HONOR); + killer.SendBroadcastMessage(`You have been awarded ${BONUS_HONOR} bonus honor for your battleground kill!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_PVP_KILL, (...args) => OnPVPKill(...args)); +``` + +In this example: +1. We define a constant `BONUS_HONOR` with the amount of bonus honor to award. +2. We register a `player_event_on_pvp_kill` event that triggers the `OnPVPKill` function whenever a player kills another player. +3. In the `OnPVPKill` function, we first check if the killer is in a battleground using `InBattleground()`. +4. If the killer is in a battleground, we then use `InArena()` to ensure they are not in an arena. +5. If the killer is in a battleground but not an arena, we award them the `BONUS_HONOR` using `ModifyHonorPoints()`. +6. Finally, we send a broadcast message to the killer informing them of their bonus honor reward. + +This script ensures that players only receive the bonus honor for PVP kills in battlegrounds and not in arenas, using the `InArena()` method to differentiate between the two PVP environments. + +## InBattleground +This method returns a boolean value indicating whether the player is currently in a battleground or not. + +### Parameters +None + +### Returns +* boolean - Returns `true` if the player is in a battleground, `false` otherwise. + +### Example Usage +This example demonstrates how to reward players with additional honor points for killing a player while in a battleground. + +```typescript +const EXTRA_HONOR_POINTS = 10; + +const OnPVPKill: player_event_on_pvp_kill = (event: number, killer: Player, killed: Player) => { + if (killer.InBattleground()) { + killer.ModifyHonorPoints(EXTRA_HONOR_POINTS); + killer.SendBroadcastMessage(`You have been awarded ${EXTRA_HONOR_POINTS} extra honor points for a battleground kill!`); + + // Notify the victim about the extra honor points + killed.SendBroadcastMessage(`Your opponent was awarded ${EXTRA_HONOR_POINTS} extra honor points for killing you in a battleground.`); + + // Log the event to the server console + console.log(`Player ${killer.GetName()} awarded ${EXTRA_HONOR_POINTS} extra honor points for a battleground kill against ${killed.GetName()}.`); + + // Optionally, you can also broadcast the message to all players in the battleground + const bgPlayers = killer.GetBattleground().GetPlayers(); + for (const player of bgPlayers) { + player.SendBroadcastMessage(`${killer.GetName()} was awarded ${EXTRA_HONOR_POINTS} extra honor points for a kill against ${killed.GetName()}!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_PVP_KILL, (...args) => OnPVPKill(...args)); +``` + +In this example: +1. We define a constant `EXTRA_HONOR_POINTS` to specify the number of additional honor points to be awarded for a battleground kill. +2. We register a callback function `OnPVPKill` for the `PLAYER_EVENT_ON_PVP_KILL` event. +3. Inside the callback function, we first check if the killer is in a battleground using the `InBattleground()` method. +4. If the killer is in a battleground, we award them the extra honor points using `ModifyHonorPoints()` and send them a broadcast message informing them about the reward. +5. We also send a broadcast message to the killed player, notifying them that their opponent received extra honor points for killing them in a battleground. +6. We log the event to the server console for tracking and debugging purposes. +7. Optionally, we can also broadcast a message to all players in the battleground using `GetBattleground().GetPlayers()` to inform them about the extra honor points awarded to the killer. + +This example showcases how the `InBattleground()` method can be used in combination with other methods and events to create custom battleground-specific mechanics and rewards. + +## InBattlegroundQueue +This method checks if the player is currently in a Battleground queue. It's useful to prevent certain actions or provide specific functionality when a player is waiting to enter a Battleground. + +### Parameters +None + +### Returns +- `true` if the player is in a Battleground queue +- `false` if the player is not in a Battleground queue + +### Example Usage +In this example, we'll create a script that prevents players from using a specific item while they are in a Battleground queue. The item will be replaced with a temporary "Queue Pass" item, which will be removed and the original item restored when the player leaves the queue or enters the Battleground. The script will use a custom Player variable to store the original item's entry ID. + +```typescript +const RESTRICTED_ITEM_ENTRY = 1234; // Replace with the actual item entry ID +const QUEUE_PASS_ITEM_ENTRY = 5678; // Replace with the actual queue pass item entry ID + +const HandleItemUse: player_event_on_item_use = (event: number, player: Player, item: Item) => { + if (item.GetEntry() === RESTRICTED_ITEM_ENTRY && player.InBattlegroundQueue()) { + // Store the original item entry in a custom Player variable + player.SetCustomData('OriginalItemEntry', item.GetEntry().toString()); + + // Remove the restricted item from the player's inventory + player.RemoveItem(item.GetEntry(), 1); + + // Add the temporary queue pass item to the player's inventory + player.AddItem(QUEUE_PASS_ITEM_ENTRY, 1); + + // Inform the player about the item replacement + player.SendBroadcastMessage('Your item has been temporarily replaced with a Queue Pass while you are in the Battleground queue.'); + } +}; + +const RestoreOriginalItem: player_event_on_bg_leave = (event: number, player: Player) => { + const originalItemEntry = player.GetCustomData('OriginalItemEntry'); + + if (originalItemEntry) { + // Remove the temporary queue pass item from the player's inventory + player.RemoveItem(QUEUE_PASS_ITEM_ENTRY, 1); + + // Restore the original item to the player's inventory + player.AddItem(parseInt(originalItemEntry), 1); + + // Remove the custom Player variable + player.SetCustomData('OriginalItemEntry', ''); + + // Inform the player about the item restoration + player.SendBroadcastMessage('Your original item has been restored.'); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ITEM_USE, (...args) => HandleItemUse(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_BG_LEAVE, (...args) => RestoreOriginalItem(...args)); +``` + +This script showcases the usage of the `InBattlegroundQueue()` method to check if a player is in a Battleground queue and perform specific actions accordingly. It also demonstrates how to store and retrieve custom Player variables to preserve information across different events. + +## IncompleteQuest +This method sets a quest as incomplete for the player based on the quest entry ID. This can be useful in cases where you want to reset a player's progress on a specific quest, allowing them to start the quest over again. + +### Parameters +* entry: number - The entry ID of the quest to set as incomplete. + +### Example Usage +Here's an example of how you might use the `IncompleteQuest` method in a script that allows a player to reset a daily quest: + +```typescript +const DAILY_QUEST_ENTRY = 12345; + +const OnGossipHello: player_event_on_gossip_hello = (event: number, player: Player, object: WorldObject) => { + if (player.GetQuestStatus(DAILY_QUEST_ENTRY) == QuestStatus.QUEST_STATUS_COMPLETE) { + player.GossipMenuAddItem(0, "Reset Daily Quest", 1, 0); + } + player.GossipSendMenu(1, object, 0); +}; + +const OnGossipSelect: player_event_on_gossip_select = (event: number, player: Player, object: WorldObject, sender: number, action: number) => { + if (sender == 1 && action == 0) { + player.IncompleteQuest(DAILY_QUEST_ENTRY); + player.SendNotification("Your daily quest has been reset!"); + player.GossipComplete(); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, (...args) => OnGossipHello(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_SELECT, (...args) => OnGossipSelect(...args)); +``` + +In this example, when a player interacts with an NPC (triggering the `PLAYER_EVENT_ON_GOSSIP_HELLO` event), the script checks if the player has already completed the daily quest (with entry ID `12345`). If the player has completed the quest, a gossip option is added to allow the player to reset the quest. + +When the player selects the gossip option (triggering the `PLAYER_EVENT_ON_GOSSIP_SELECT` event), the script calls the `IncompleteQuest` method with the entry ID of the daily quest. This sets the quest status to incomplete for the player, effectively resetting their progress on the quest. The player is then sent a notification informing them that their daily quest has been reset. + +This example demonstrates how the `IncompleteQuest` method can be used in combination with other mod-eluna methods and events to create a script that provides additional functionality to players, such as the ability to reset daily quests. + +## IsAFK +Returns whether the player is marked as "Away From Keyboard" (AFK). Players are considered AFK if they have been inactive for a certain period of time or if they have manually set their status to AFK. + +### Parameters +None + +### Returns +- `boolean` - True if the player is AFK, false otherwise. + +### Example Usage +This example demonstrates how to check if a player is AFK and perform actions accordingly. + +```typescript +const OnPlayerChat: player_event_on_chat = (event: number, player: Player, msg: string, Type: number, lang: Language): void => { + // Check if the player is AFK + if (player.IsAFK()) { + // Send a whisper to the player + player.SendBroadcastMessage("You are currently AFK. Your message will not be sent."); + + // Notify other players in the same group + const group = player.GetGroup(); + if (group) { + group.BroadcastGroupMessage(`${player.GetName()} is AFK and cannot respond to messages.`); + } + + // Log the AFK status + console.log(`Player ${player.GetName()} is AFK and attempted to send a message.`); + + // Prevent the message from being sent + return; + } + + // If the player is not AFK, process the chat message as usual + // ... +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => OnPlayerChat(...args)); +``` + +In this example: +1. When a player sends a chat message, the `OnPlayerChat` event is triggered. +2. The script checks if the player is AFK using the `IsAFK()` method. +3. If the player is AFK: + - A whisper is sent to the player informing them that their message will not be sent due to their AFK status. + - If the player is in a group, a message is broadcasted to the group notifying them that the player is AFK and cannot respond. + - The AFK status is logged for reference. + - The chat message is prevented from being sent by returning from the event handler. +4. If the player is not AFK, the chat message is processed as usual. + +This example demonstrates how the `IsAFK()` method can be used to handle AFK players in a chat event, providing appropriate feedback and notifications based on their AFK status. + +## IsAcceptingWhispers +This method returns a boolean value indicating whether the player is currently accepting whispers from other players. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is accepting whispers, `false` otherwise. + +### Example Usage +This example demonstrates how to check if a player is accepting whispers and send a message accordingly. + +```typescript +const SendWhisperToPlayer: player_event_on_whisper = (event: number, player: Player, msg: string, type: ChatMsg, lang: Language, receiver: Player): void => { + if (receiver.IsAcceptingWhispers()) { + // Player is accepting whispers, send the message + receiver.SendBroadcastMessage(`[Whisper] ${player.GetName()}: ${msg}`); + } else { + // Player is not accepting whispers, inform the sender + player.SendBroadcastMessage(`${receiver.GetName()} is not accepting whispers at the moment.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_WHISPER, (...args) => SendWhisperToPlayer(...args)); +``` + +In this example, when a player sends a whisper to another player, the `SendWhisperToPlayer` function is triggered. It checks if the receiving player is accepting whispers using the `IsAcceptingWhispers()` method. + +If the receiving player is accepting whispers, the whisper message is sent to them using `SendBroadcastMessage()`, prefixed with "[Whisper]" and the sender's name. + +If the receiving player is not accepting whispers, a message is sent back to the sender informing them that the player is not accepting whispers at the moment. + +This script allows players to control whether they want to receive whispers and provides feedback to the sender if the whisper cannot be delivered due to the recipient's settings. + +Note: Make sure to register the event handler using `RegisterPlayerEvent()` with the appropriate event type (`PlayerEvents.PLAYER_EVENT_ON_WHISPER`) to ensure that the function is called when a player sends a whisper. + +## IsAlliance +Returns whether the player is a member of the Alliance faction or not. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is a member of the Alliance faction, `false` otherwise. + +### Example Usage +In this example, we will create a script that will reward Alliance players with extra gold when they complete a quest, while Horde players will receive the standard gold reward. + +```typescript +const QUEST_ENTRY = 1234; +const EXTRA_GOLD_REWARD = 10; + +const OnQuestComplete: player_event_on_quest_complete = (event: number, player: Player, quest: number): void => { + if (quest === QUEST_ENTRY) { + const questReward = player.GetQuestRewardGold(); + + if (player.IsAlliance()) { + player.ModifyMoney(questReward + EXTRA_GOLD_REWARD * 10000); + player.SendBroadcastMessage(`You have been rewarded with an extra ${EXTRA_GOLD_REWARD} gold for your service to the Alliance!`); + } else { + player.ModifyMoney(questReward); + player.SendBroadcastMessage(`You have completed the quest and received ${questReward / 10000} gold.`); + } + + player.CompleteQuest(QUEST_ENTRY); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => OnQuestComplete(...args)); +``` + +In this script, we first define the `QUEST_ENTRY` constant to specify the ID of the quest we want to modify the rewards for, and the `EXTRA_GOLD_REWARD` constant to determine the amount of extra gold Alliance players will receive. + +When a player completes a quest, the `OnQuestComplete` event is triggered. We check if the completed quest ID matches the `QUEST_ENTRY` we defined earlier. If it does, we proceed with the reward logic. + +We retrieve the standard quest gold reward using the `GetQuestRewardGold()` method. Then, we use the `IsAlliance()` method to determine if the player is a member of the Alliance faction. + +If the player is an Alliance member, we modify their money using the `ModifyMoney()` method, adding the standard quest reward and the extra gold reward multiplied by 10,000 (since copper is the base unit in World of Warcraft). We also send a broadcast message to the player informing them of the extra reward they received for their service to the Alliance. + +If the player is not an Alliance member (i.e., they are a member of the Horde), we simply modify their money with the standard quest reward and send a broadcast message informing them of the gold they received for completing the quest. + +Finally, we mark the quest as completed for the player using the `CompleteQuest()` method. + +This example demonstrates how the `IsAlliance()` method can be used to create faction-specific rewards or experiences for players, enhancing the immersion and providing a sense of belonging to their chosen faction. + +## IsDND +Returns whether the player has the "Do Not Disturb" flag set. When a player has this flag set, they will not receive whispers or other non-essential communications. + +### Parameters +None + +### Returns +boolean - 'true' if the player has the "Do Not Disturb" flag set, 'false' otherwise. + +### Example Usage +A script that checks if a player has the "Do Not Disturb" flag set before sending them a message about an ongoing world event. +```typescript +const EVENT_MESSAGE = "A special world event is happening now! Come join the festivities!"; + +const WorldEventNotification: WorldEvents = (event: number, player: Player) => { + // Check if the player has the "Do Not Disturb" flag set + if (!player.IsDND()) { + // If the player does not have the flag set, send them the event message + player.SendBroadcastMessage(EVENT_MESSAGE); + } else { + // If the player has the flag set, log a message indicating that they were not notified + console.log(`Player ${player.GetName()} has the "Do Not Disturb" flag set and was not notified of the world event.`); + } +} + +// Register the WorldEventNotification function to be called every hour +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_UPDATE, (event) => { + // Check if the current time is at the top of the hour + const currentTime = new Date(); + if (currentTime.getMinutes() === 0) { + // If it is the top of the hour, iterate through all online players and call the WorldEventNotification function for each one + for (const [accountId, player] of world.GetAllPlayers()) { + WorldEventNotification(event, player); + } + } +}); +``` +In this example, the script registers a server event that is triggered every hour. When the event is triggered, the script iterates through all online players and calls the `WorldEventNotification` function for each one. The `WorldEventNotification` function checks if the player has the "Do Not Disturb" flag set using the `IsDND()` method. If the player does not have the flag set, the script sends them a message about an ongoing world event. If the player does have the flag set, the script logs a message indicating that the player was not notified due to their "Do Not Disturb" status. + +## IsFalling +Returns a boolean value indicating whether the player is currently falling or not. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is currently falling, `false` otherwise. + +### Example Usage +This example demonstrates how to check if a player is falling and apply fall damage based on the fall time. + +```typescript +const FALL_DAMAGE_THRESHOLD = 5; // Minimum fall time in seconds to apply damage +const FALL_DAMAGE_MULTIPLIER = 10; // Damage multiplier per second of falling + +let playerFallStartTime: number | null = null; + +const onPlayerFallStart: player_event_on_start_fall = (event: number, player: Player): void => { + playerFallStartTime = os.time(); // Record the start time of the fall +}; + +const onPlayerFallEnd: player_event_on_end_fall = (event: number, player: Player): void => { + if (playerFallStartTime !== null) { + const fallDuration = os.time() - playerFallStartTime; // Calculate the fall duration + + if (fallDuration >= FALL_DAMAGE_THRESHOLD) { + const fallDamage = (fallDuration - FALL_DAMAGE_THRESHOLD) * FALL_DAMAGE_MULTIPLIER; + player.DealDamage(player, fallDamage, DamageType.DAMAGE_TYPE_NORMAL); // Apply fall damage to the player + player.SendBroadcastMessage(`You took ${fallDamage} fall damage!`); + } + + playerFallStartTime = null; // Reset the fall start time + } +}; + +const onPlayerFallCheck: player_event_on_update_zone = (event: number, player: Player, newZone: number, newArea: number): void => { + if (player.IsFalling()) { + if (playerFallStartTime === null) { + // Player started falling + onPlayerFallStart(event, player); + } + } else { + if (playerFallStartTime !== null) { + // Player stopped falling + onPlayerFallEnd(event, player); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE_ZONE, (...args) => onPlayerFallCheck(...args)); +``` + +In this example: + +1. We define constants for the fall damage threshold and multiplier. +2. We initialize a variable `playerFallStartTime` to keep track of when the player started falling. +3. In the `onPlayerFallStart` event handler, we record the start time of the fall when the player starts falling. +4. In the `onPlayerFallEnd` event handler, we calculate the fall duration and apply fall damage to the player if the fall duration exceeds the threshold. We also send a message to the player indicating the amount of fall damage taken. +5. In the `onPlayerFallCheck` event handler, which is triggered whenever the player's zone is updated, we check if the player is currently falling using the `IsFalling()` method. + - If the player is falling and `playerFallStartTime` is null, it means the player started falling, so we call the `onPlayerFallStart` event handler. + - If the player is not falling and `playerFallStartTime` is not null, it means the player stopped falling, so we call the `onPlayerFallEnd` event handler. +6. Finally, we register the `onPlayerFallCheck` event handler for the `PLAYER_EVENT_ON_UPDATE_ZONE` event using `RegisterPlayerEvent`. + +This script allows you to detect when a player starts and stops falling, calculate the fall duration, and apply fall damage accordingly. You can customize the fall damage threshold and multiplier based on your desired gameplay mechanics. + +## IsFlying +Determines if the player is currently flying. This can be useful to check if the player is mounted on a flying mount or in a flying form. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is currently flying, `false` otherwise. + +### Example Usage +This example will dismount a player if they are flying in a specific zone. + +```typescript +const ORGRIMMAR_ZONE_ID = 1637; + +const OnUpdateZone: player_event_on_update_zone = (event: number, player: Player, newZone: number, newArea: number) => { + // Check if the player has entered Orgrimmar + if (newZone === ORGRIMMAR_ZONE_ID) { + // Check if the player is currently flying + if (player.IsFlying()) { + // Dismount the player + player.Dismount(); + + // Send a message to the player + player.SendBroadcastMessage("Flying is not allowed in Orgrimmar. You have been dismounted."); + + // Play a sound to the player + player.PlayDirectSound(8192, player); + + // Add a cooldown to the player's flying mount + const SWIFT_PURPLE_WINDRIDER_ENTRY = 32345; + player.AddSpellCooldown(SWIFT_PURPLE_WINDRIDER_ENTRY, 0, 60000); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE_ZONE, OnUpdateZone); +``` + +In this example, when a player enters the Orgrimmar zone (zone ID 1637), the script checks if the player is currently flying using the `IsFlying()` method. If the player is flying, the script does the following: + +1. Dismounts the player using the `Dismount()` method. +2. Sends a message to the player using the `SendBroadcastMessage()` method to inform them that flying is not allowed in Orgrimmar. +3. Plays a sound to the player using the `PlayDirectSound()` method with the sound ID 8192. +4. Adds a cooldown to the player's flying mount (in this case, Swift Purple Windrider with entry ID 32345) using the `AddSpellCooldown()` method. The cooldown is set to 60000 milliseconds (1 minute). + +This script ensures that players are not flying within Orgrimmar and provides feedback to the player when they are dismounted. + +## IsGM +Returns 'true' if the [Player] is a Game Master, 'false' otherwise. + +Note: This is only true when the GM tag is activated! For an alternative, see [Player:GetGMRank](./player.md#getgmrank). + +### Returns +boolean - 'true' if the player is a GM, 'false' otherwise. + +### Example Usage +This example demonstrates how to use the `IsGM()` method to grant additional rewards to non-GM players who participate in a special event. + +```typescript +const EVENT_ITEM_ENTRY = 12345; +const NORMAL_REWARD_COUNT = 1; +const BONUS_REWARD_COUNT = 2; + +const OnLootItem: player_event_on_loot_item = (event: number, player: Player, item: Item) => { + if (item.GetEntry() === EVENT_ITEM_ENTRY) { + if (!player.IsGM()) { + // Non-GM players receive bonus rewards + player.AddItem(EVENT_ITEM_ENTRY, BONUS_REWARD_COUNT); + player.SendBroadcastMessage("Congratulations! You've received bonus rewards for participating in the event."); + } else { + // GM players receive the normal amount of rewards + player.AddItem(EVENT_ITEM_ENTRY, NORMAL_REWARD_COUNT); + player.SendBroadcastMessage("Thank you for testing the event! You've received the standard reward."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, (...args) => OnLootItem(...args)); +``` + +In this example: +1. When a player loots an item with the entry `EVENT_ITEM_ENTRY`, the script checks if the player is a GM using the `IsGM()` method. +2. If the player is not a GM, they receive bonus rewards (`BONUS_REWARD_COUNT`) for participating in the event, and a broadcast message is sent to inform them. +3. If the player is a GM, they receive the normal amount of rewards (`NORMAL_REWARD_COUNT`), and a different broadcast message is sent to thank them for testing the event. + +This script encourages non-GM players to participate in the event by offering bonus rewards while ensuring that GM players who are testing the event receive the standard rewards. + +## IsGMChat +Determines if the [Player] has GM chat enabled. + +### Parameters +None + +### Returns +boolean - 'true' if the [Player] has GM chat enabled, 'false' otherwise. + +### Example Usage +This example demonstrates how to check if a player has GM chat enabled and perform different actions based on the result. + +```typescript +const SPECIAL_ITEM_ENTRY = 12345; + +const onPlayerChat: player_event_on_chat = (event: number, player: Player, msg: string, Type: ChatMsg, lang: Language): void => { + if (player.IsGMChat()) { + // Player has GM chat enabled + if (msg.toLowerCase() === '!special') { + // Give the player a special item + const item = player.AddItem(SPECIAL_ITEM_ENTRY, 1); + if (item) { + player.SendBroadcastMessage('You have received a special item!'); + } else { + player.SendBroadcastMessage('Failed to add the special item to your inventory.'); + } + } else { + player.SendBroadcastMessage('Unknown GM command. Available commands: !special'); + } + } else { + // Player does not have GM chat enabled + if (msg.toLowerCase() === '!gm') { + player.SendBroadcastMessage('You do not have permission to use GM commands.'); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => onPlayerChat(...args)); +``` + +In this example, when a player sends a chat message, the script checks if the player has GM chat enabled using the `IsGMChat()` method. If GM chat is enabled and the player types '!special', the script attempts to give the player a special item using `AddItem()`. If the item is successfully added to the player's inventory, a success message is sent to the player. Otherwise, an error message is sent. + +If the player does not have GM chat enabled and types '!gm', a message is sent to the player indicating that they do not have permission to use GM commands. + +This example showcases how the `IsGMChat()` method can be used in conjunction with other methods and game events to create custom functionality based on the player's GM chat status. + +## IsGMVisible +This method checks if the player has GM visibility enabled. When a player has GM visibility enabled, they will be visible to other players even if they have GM mode enabled. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns true if the player has GM visibility enabled, false otherwise. + +### Example Usage +This example demonstrates how to check if a player has GM visibility enabled and perform actions based on the result. + +```typescript +const onPlayerChat: player_event_on_chat = (event: number, player: Player, msg: string, type: number, lang: Language) => { + if (player.IsGMVisible()) { + // Player has GM visibility enabled + if (msg === "!hidegm") { + player.SetGMVisible(false); + player.SendBroadcastMessage("You are now hidden from other players."); + } + } else { + // Player has GM visibility disabled + if (msg === "!showgm") { + player.SetGMVisible(true); + player.SendBroadcastMessage("You are now visible to other players."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => onPlayerChat(...args)); +``` + +In this example: +1. We register a player event handler for the `PLAYER_EVENT_ON_CHAT` event. +2. Inside the event handler, we check if the player has GM visibility enabled using `player.IsGMVisible()`. +3. If the player has GM visibility enabled and they type the command "!hidegm", we disable their GM visibility using `player.SetGMVisible(false)` and send them a message indicating that they are now hidden from other players. +4. If the player has GM visibility disabled and they type the command "!showgm", we enable their GM visibility using `player.SetGMVisible(true)` and send them a message indicating that they are now visible to other players. + +This script allows players with GM mode to toggle their visibility to other players by using the "!hidegm" and "!showgm" commands. It provides a convenient way for GMs to control their visibility without having to manually adjust their GM mode settings. + +## IsGroupVisibleFor +This method checks if the player is visible to their group members. It does not take any parameters. + +### Returns +This method does not return any value. + +### Example Usage +In this example, we will create a script that will hide a player from their group when they enter a specific area, and make them visible again when they leave that area. + +```typescript +const HIDE_AREA_ID = 1234; // Replace with the actual area ID + +const onAreaTrigger: player_event_on_area_trigger = (event: number, player: Player, areaTrigger: AreaTrigger): void => { + if (areaTrigger.GetEntry() === HIDE_AREA_ID) { + player.SetPhaseMask(2, true); // Set the player's phase to 2 + player.IsGroupVisibleFor(); // Check if the player is visible to their group + + // Inform the player that they are now hidden from their group + player.SendBroadcastMessage("You have entered a hidden area and are now invisible to your group members."); + } +}; + +const onUpdateZone: player_event_on_update_zone = (event: number, player: Player, newZone: number, newArea: number): void => { + if (player.GetPhaseMask() === 2 && newArea !== HIDE_AREA_ID) { + player.SetPhaseMask(1, true); // Set the player's phase back to 1 + player.IsGroupVisibleFor(); // Check if the player is visible to their group + + // Inform the player that they are now visible to their group + player.SendBroadcastMessage("You have left the hidden area and are now visible to your group members."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER, (...args) => onAreaTrigger(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE_ZONE, (...args) => onUpdateZone(...args)); +``` + +In this script, we define a constant `HIDE_AREA_ID` which represents the ID of the area where players should be hidden from their group. You should replace this with the actual area ID you want to use. + +When a player enters the area with the specified ID (triggered by the `PLAYER_EVENT_ON_AREA_TRIGGER` event), we set their phase to 2 using `SetPhaseMask(2, true)`. This effectively hides the player from their group members who are not in the same phase. We then call `IsGroupVisibleFor()` to check if the player is still visible to their group (which should return false after setting the phase to 2). + +When the player leaves the hidden area (triggered by the `PLAYER_EVENT_ON_UPDATE_ZONE` event), we check if their current phase is 2 and if the new area they entered is not the hidden area. If these conditions are met, we set the player's phase back to 1 using `SetPhaseMask(1, true)`, making them visible to their group again. We then call `IsGroupVisibleFor()` to check if the player is now visible to their group (which should return true after setting the phase back to 1). + +We also send broadcast messages to the player to inform them when they enter and leave the hidden area, letting them know their visibility status to their group members. + +## IsHonorOrXPTarget +This method checks if the player is eligible to gain honor or experience from the specified unit. + +### Parameters +* unit: [Unit](./unit.md) - The unit to check if the player can gain honor or experience from. + +### Returns +* boolean - Returns 'true' if the player is eligible for honor or experience gain from the specified unit, 'false' otherwise. + +### Example Usage +In this example, we will create a script that rewards players with extra honor and experience when they kill a creature with a specific entry ID. + +```typescript +const CREATURE_ENTRY_ID = 123; // Replace with the desired creature entry ID +const EXTRA_HONOR = 100; // Amount of extra honor to award +const EXTRA_XP = 1000; // Amount of extra experience to award + +const OnCreatureKill: creature_event_on_killed = (event: number, creature: Creature, killer: Unit) => { + if (creature.GetEntry() === CREATURE_ENTRY_ID && killer.IsPlayer()) { + const player = killer.ToPlayer(); + if (player.IsHonorOrXPTarget(creature)) { + player.GiveHonor(EXTRA_HONOR); + player.GiveXP(EXTRA_XP); + player.SendBroadcastMessage(`You have been awarded an extra ${EXTRA_HONOR} honor and ${EXTRA_XP} experience for killing the special creature!`); + } else { + player.SendBroadcastMessage("You are not eligible for extra rewards from this creature."); + } + } +}; + +RegisterCreatureEvent(CREATURE_ENTRY_ID, CreatureEvents.CREATURE_EVENT_ON_KILLED, (...args) => OnCreatureKill(...args)); +``` + +In this script: +1. We define the specific creature entry ID (`CREATURE_ENTRY_ID`) for which we want to provide extra rewards. +2. We specify the amount of extra honor (`EXTRA_HONOR`) and experience (`EXTRA_XP`) to award. +3. We register a creature event handler for the `CREATURE_EVENT_ON_KILLED` event. +4. Inside the event handler, we check if the killed creature matches the desired entry ID and if the killer is a player. +5. If the conditions are met, we use the `IsHonorOrXPTarget` method to check if the player is eligible for honor or experience gain from the killed creature. +6. If the player is eligible, we award the extra honor using `GiveHonor` and extra experience using `GiveXP` methods. We also send a broadcast message to the player informing them about the extra rewards. +7. If the player is not eligible, we send a different broadcast message indicating that they cannot receive extra rewards from this creature. + +This script ensures that players are rewarded with extra honor and experience only when they kill the specified creature and are eligible for those rewards based on the `IsHonorOrXPTarget` method. + +## IsHorde +Returns 'true' if the [Player] is a part of the Horde faction, 'false' otherwise. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - 'true' if the player is part of the Horde faction, 'false' otherwise. + +### Example Usage +This example demonstrates how to use the `IsHorde` method to determine a player's faction and apply different actions based on the result. + +```typescript +const HORDE_MOUNT_ENTRY = 12345; +const ALLIANCE_MOUNT_ENTRY = 67890; + +const onPlayerLogin: player_event_on_login = (event: number, player: Player) => { + let mountEntry: number; + + if (player.IsHorde()) { + mountEntry = HORDE_MOUNT_ENTRY; + player.SendBroadcastMessage("For the Horde! Here's your faction-specific mount."); + } else { + mountEntry = ALLIANCE_MOUNT_ENTRY; + player.SendBroadcastMessage("For the Alliance! Here's your faction-specific mount."); + } + + const mount = player.AddItem(mountEntry, 1); + + if (mount) { + player.SendBroadcastMessage(`You have received a ${mount.GetName()}!`); + } else { + player.SendBroadcastMessage("Error: Could not add the faction-specific mount to your inventory."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => onPlayerLogin(...args)); +``` + +In this example: +1. We define constants for the Horde and Alliance mount entry IDs. +2. In the `onPlayerLogin` event, we use the `IsHorde` method to determine the player's faction. +3. Based on the faction, we set the appropriate mount entry ID and send a faction-specific welcome message to the player. +4. We attempt to add the faction-specific mount to the player's inventory using the `AddItem` method. +5. If the mount is successfully added, we send a message to the player informing them of the received mount. If there's an error adding the mount, we send an error message instead. +6. Finally, we register the `onPlayerLogin` event to be triggered whenever a player logs in. + +This example showcases how the `IsHorde` method can be used in combination with other methods and game events to create a more immersive and faction-specific experience for players. + +## IsImmuneToDamage +Returns a boolean indicating whether the player is currently immune to all types of damage. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is immune to damage, `false` otherwise. + +### Example Usage +In this example, we create a script that checks if the player is immune to damage when they enter combat. If they are immune, we grant them a temporary damage bonus and notify them. If they are not immune, we apply a small damage taken increase and notify them. + +```typescript +const DAMAGE_BONUS_PERCENTAGE = 0.1; +const DAMAGE_TAKEN_INCREASE_PERCENTAGE = 0.05; +const BONUS_DURATION_SECONDS = 10; + +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + if (player.IsImmuneToDamage()) { + const damageBonus = player.GetFloatValue(PlayerFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS_PCT) + DAMAGE_BONUS_PERCENTAGE; + player.SetFloatValue(PlayerFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS_PCT, damageBonus); + player.SendBroadcastMessage(`You are immune to damage! Granting a ${DAMAGE_BONUS_PERCENTAGE * 100}% damage bonus for ${BONUS_DURATION_SECONDS} seconds.`); + + player.DelayFunction((p: Player) => { + const resetDamageBonus = p.GetFloatValue(PlayerFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS_PCT) - DAMAGE_BONUS_PERCENTAGE; + p.SetFloatValue(PlayerFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS_PCT, resetDamageBonus); + p.SendBroadcastMessage("Your damage bonus has expired."); + }, BONUS_DURATION_SECONDS * 1000, player); + } else { + const damageTakenIncrease = player.GetFloatValue(PlayerFields.PLAYER_FIELD_MOD_DAMAGE_TAKEN_PCT) + DAMAGE_TAKEN_INCREASE_PERCENTAGE; + player.SetFloatValue(PlayerFields.PLAYER_FIELD_MOD_DAMAGE_TAKEN_PCT, damageTakenIncrease); + player.SendBroadcastMessage(`You are not immune to damage. Applying a ${DAMAGE_TAKEN_INCREASE_PERCENTAGE * 100}% damage taken increase.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script, we first check if the player is immune to damage using the `IsImmuneToDamage()` method. If they are immune, we grant them a temporary damage bonus by increasing their `PLAYER_FIELD_MOD_DAMAGE_DONE_POS_PCT` value and notify them. We then use `DelayFunction()` to schedule a callback that will reset the damage bonus after the specified duration. + +If the player is not immune to damage, we apply a small damage taken increase by modifying their `PLAYER_FIELD_MOD_DAMAGE_TAKEN_PCT` value and notify them. + +This script demonstrates how `IsImmuneToDamage()` can be used to check the player's immunity status and make decisions based on that information. + +## IsInArenaTeam +This method checks if the player is part of an arena team based on the type provided. + +### Parameters +* type: number - The type of arena team to check for (2v2, 3v3, 5v5) + * 2 - 2v2 Arena + * 3 - 3v3 Arena + * 5 - 5v5 Arena + +### Returns +* boolean - Returns 'true' if the player is in the specified arena team, 'false' otherwise. + +### Example Usage +This example demonstrates how to reward players with bonus honor points when they complete a battleground while being part of an arena team. + +```typescript +const BONUS_HONOR_POINTS = 100; + +const BattlegroundComplete: player_event_on_battleground_finish = (event: number, player: Player, bgId: number, winnerId: number, loserId: number) => { + // Check if the player is in a 3v3 arena team + if (player.IsInArenaTeam(3)) { + const teamId = player.GetArenaTeamId(3); + const arenaTeam = ArenaTeam.GetArenaTeamById(teamId); + + // Check if the player's team rating is above 1800 + if (arenaTeam && arenaTeam.GetRating() >= 1800) { + player.ModifyHonorPoints(BONUS_HONOR_POINTS); + player.SendBroadcastMessage(`You have been awarded ${BONUS_HONOR_POINTS} bonus honor points for being part of a high-rated 3v3 arena team!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_BATTLEGROUND_FINISH, (...args) => BattlegroundComplete(...args)); +``` + +In this example: +1. We define a constant `BONUS_HONOR_POINTS` to store the amount of bonus honor points to be awarded. +2. We register a callback function `BattlegroundComplete` for the `PLAYER_EVENT_ON_BATTLEGROUND_FINISH` event. +3. Inside the callback function, we check if the player is part of a 3v3 arena team using `player.IsInArenaTeam(3)`. +4. If the player is in a 3v3 arena team, we retrieve the team ID using `player.GetArenaTeamId(3)` and then get the arena team object using `ArenaTeam.GetArenaTeamById(teamId)`. +5. We check if the player's arena team has a rating of 1800 or higher. +6. If the player's arena team meets the rating requirement, we award the player with bonus honor points using `player.ModifyHonorPoints(BONUS_HONOR_POINTS)`. +7. Finally, we send a broadcast message to the player informing them about the bonus honor points they received for being part of a high-rated 3v3 arena team. + +This example showcases how the `IsInArenaTeam` method can be used in combination with other methods and events to create a more complex and rewarding system for players participating in arena teams and battlegrounds. + +## IsInGroup +Returns a boolean value indicating whether the player is currently in a group or not. + +### Parameters +None + +### Returns +boolean - 'true' if the player is in a group, 'false' otherwise. + +### Example Usage +This example demonstrates how to check if a player is in a group and perform actions based on their group status. + +```typescript +const OnLogin: player_event_on_login = (event: number, player: Player) => { + if (player.IsInGroup()) { + // Player is in a group + const group = player.GetGroup(); + const groupMembers = group.GetMembers(); + + player.SendBroadcastMessage(`Welcome back! You are in a group with ${groupMembers.length} members.`); + + // Buff the player if they are in a group + player.AddAura(1126, player); // Mark of the Wild + player.AddAura(21562, player); // Prayer of Fortitude + + // Grant bonus experience and reputation gains for being in a group + player.SetXPRate(player.GetXPRate() * 1.1); // 10% bonus experience + player.SetRepRate(player.GetRepRate() * 1.05); // 5% bonus reputation + + // Teleport the player to their group leader if they are not the leader + if (!group.IsLeader(player)) { + const leader = group.GetLeader(); + player.Teleport(leader.GetMapId(), leader.GetX(), leader.GetY(), leader.GetZ(), leader.GetO()); + } + } else { + // Player is not in a group + player.SendBroadcastMessage("You are not currently in a group. Join or create a group to enjoy additional benefits!"); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. When a player logs in, the script checks if they are in a group using the `IsInGroup()` method. +2. If the player is in a group: + - It retrieves the player's group and the number of group members. + - It sends a welcome message to the player informing them about their group status. + - It applies beneficial auras to the player, such as Mark of the Wild and Prayer of Fortitude. + - It grants bonus experience and reputation gains to the player for being in a group. + - If the player is not the group leader, it teleports them to the location of the group leader. +3. If the player is not in a group: + - It sends a message encouraging the player to join or create a group to enjoy additional benefits. + +This script showcases how the `IsInGroup()` method can be used in combination with other player and group-related methods to create a more dynamic and engaging experience for players based on their group status. + +## IsInGuild +This method returns a boolean value indicating whether the player is currently a member of a guild or not. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is in a guild, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsInGuild()` method to check if a player is in a guild and perform different actions based on the result. + +```typescript +const GUILD_REWARD_ITEM_ENTRY = 12345; +const GUILD_REWARD_ITEM_COUNT = 5; + +const OnPlayerLogin: player_event_on_login = (event: number, player: Player) => { + if (player.IsInGuild()) { + // Player is in a guild, grant them a special reward item + const rewardItem = player.AddItem(GUILD_REWARD_ITEM_ENTRY, GUILD_REWARD_ITEM_COUNT); + + if (rewardItem) { + player.SendBroadcastMessage(`Welcome back, guild member! You have been granted ${GUILD_REWARD_ITEM_COUNT}x ${rewardItem.GetName()}.`); + } else { + player.SendBroadcastMessage("Welcome back, guild member! Unfortunately, we couldn't grant you the special reward item due to insufficient inventory space."); + } + } else { + // Player is not in a guild, encourage them to join one + player.SendBroadcastMessage("Welcome back! You are currently not a member of any guild. Consider joining one to access exclusive benefits and rewards!"); + + // Teleport the player to the guild recruitment area + const GUILD_RECRUITMENT_AREA_MAP = 0; + const GUILD_RECRUITMENT_AREA_X = -8800.0; + const GUILD_RECRUITMENT_AREA_Y = 645.0; + const GUILD_RECRUITMENT_AREA_Z = 94.0; + player.Teleport(GUILD_RECRUITMENT_AREA_MAP, GUILD_RECRUITMENT_AREA_X, GUILD_RECRUITMENT_AREA_Y, GUILD_RECRUITMENT_AREA_Z, 0.0); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnPlayerLogin(...args)); +``` + +In this example: +1. When a player logs in, the script checks if they are a member of a guild using the `IsInGuild()` method. +2. If the player is in a guild: + - The script grants them a special reward item (`GUILD_REWARD_ITEM_ENTRY`) with a specified count (`GUILD_REWARD_ITEM_COUNT`) using the `AddItem()` method. + - If the item is successfully added to the player's inventory, a welcome message is sent to the player informing them about the reward. + - If the item cannot be added due to insufficient inventory space, an alternative message is sent to the player. +3. If the player is not in a guild: + - A message is sent to the player encouraging them to join a guild to access exclusive benefits and rewards. + - The player is then teleported to a designated guild recruitment area using the `Teleport()` method, specified by the map ID and coordinates. +4. The script is registered to the `PLAYER_EVENT_ON_LOGIN` event using `RegisterPlayerEvent()`, ensuring that it is triggered whenever a player logs in. + +This example showcases how the `IsInGuild()` method can be used in combination with other player-related methods to create a more engaging and interactive experience for players based on their guild membership status. + +## IsInSameGroupWith +This method checks if the player is currently in the same group as another player. + +### Parameters +- `player`: [Player](./player.md) - The player to check if they are in the same group. + +### Returns +- `boolean` - Returns `true` if the players are in the same group, `false` otherwise. + +### Example Usage +This example demonstrates how to check if two players are in the same group and perform actions based on the result. + +```typescript +function ProcessGroupReward(player1: Player, player2: Player): void { + const REWARD_ITEM_ENTRY = 12345; + const REWARD_ITEM_COUNT = 1; + + if (player1.IsInSameGroupWith(player2)) { + // Give both players a reward item if they are in the same group + player1.AddItem(REWARD_ITEM_ENTRY, REWARD_ITEM_COUNT); + player2.AddItem(REWARD_ITEM_ENTRY, REWARD_ITEM_COUNT); + + // Send a message to both players + player1.SendBroadcastMessage("You and your group mate have been rewarded!"); + player2.SendBroadcastMessage("You and your group mate have been rewarded!"); + } else { + // If the players are not in the same group, send them a different message + player1.SendBroadcastMessage("You must be in the same group as the other player to receive the reward."); + player2.SendBroadcastMessage("You must be in the same group as the other player to receive the reward."); + } +} + +// Example usage: Check if two players are in the same group when one of them loots a specific item +const OnPlayerLootItem: player_event_on_loot_item = (event: number, player: Player, item: Item) => { + const TRIGGER_ITEM_ENTRY = 23456; + const OTHER_PLAYER_GUID = 12345; + + if (item.GetEntry() === TRIGGER_ITEM_ENTRY) { + const otherPlayer = GetPlayerByGUID(OTHER_PLAYER_GUID); + if (otherPlayer) { + ProcessGroupReward(player, otherPlayer); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_ITEM, OnPlayerLootItem); +``` + +In this example, the `ProcessGroupReward` function takes two players as arguments and checks if they are in the same group using the `IsInSameGroupWith` method. If the players are in the same group, they both receive a reward item and a broadcast message. If they are not in the same group, they receive a different message indicating that they must be in the same group to receive the reward. + +The `OnPlayerLootItem` event handler is triggered when a player loots an item. It checks if the looted item has a specific entry (`TRIGGER_ITEM_ENTRY`) and if so, it retrieves another player by their GUID (`OTHER_PLAYER_GUID`). If the other player is found, it calls the `ProcessGroupReward` function to check if the players are in the same group and perform the appropriate actions. + +This example showcases how the `IsInSameGroupWith` method can be used in a practical scenario to determine if two players are in the same group and make decisions based on that information. + +## IsInSameRaidWith +Checks if the player is currently in the same raid group as another player. + +### Parameters +- player: [Player](./player.md) - The player to check if in the same raid group. + +### Returns +- boolean: Returns 'true' if the player is in the same raid group as the specified player, 'false' otherwise. + +### Example Usage +This example demonstrates how to use the `IsInSameRaidWith` method to determine if the player is in the same raid group as another player and grant them a special buff if they are. + +```typescript +const SPECIAL_BUFF_SPELL_ID = 12345; + +function ApplyRaidBuff(player: Player, target: Player): void { + if (player.IsInSameRaidWith(target)) { + player.AddAura(SPECIAL_BUFF_SPELL_ID, player); + player.SendBroadcastMessage(`You have been granted a special raid buff!`); + } +} + +const OnLogin: player_event_on_login = (event: PlayerEvents, player: Player) => { + const targetGuid = player.GetSelection(); + if (targetGuid) { + const target = GetPlayerByGUID(targetGuid); + if (target) { + ApplyRaidBuff(player, target); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +``` + +In this example: +1. We define a constant `SPECIAL_BUFF_SPELL_ID` to represent the spell ID of the special buff we want to apply to raid members. +2. We create a function `ApplyRaidBuff` that takes two players as parameters: the player applying the buff and the target player. +3. Inside the function, we use the `IsInSameRaidWith` method to check if the player and target are in the same raid group. +4. If they are in the same raid group, we apply the special buff to the player using `AddAura` and send them a broadcast message informing them about the buff. +5. We register the `OnLogin` event handler using `RegisterPlayerEvent` for the `PLAYER_EVENT_ON_LOGIN` event. +6. When a player logs in, the `OnLogin` event handler is triggered. +7. We retrieve the selected target's GUID using `GetSelection`. +8. If a target is selected, we use `GetPlayerByGUID` to get the target player object. +9. If the target player is found, we call the `ApplyRaidBuff` function, passing the player and target as arguments. + +This example showcases how the `IsInSameRaidWith` method can be used in combination with other player-related functions to create interactive gameplay mechanics based on raid group membership. + +## IsInWater +Returns a boolean value indicating whether the player is currently in water or not. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is in water, `false` otherwise. + +### Example Usage +This example demonstrates how to check if a player is in water and apply a buff if they are. + +```typescript +const SWIM_SPEED_BUFF_ID = 42354; +const SWIM_SPEED_BUFF_DURATION = 60 * 5 * 1000; // 5 minutes + +const OnPlayerEnterWater: player_event_on_enter_water = (event: number, player: Player) => { + if (player.IsInWater()) { + // Check if the player already has the swim speed buff + if (!player.HasAura(SWIM_SPEED_BUFF_ID)) { + // Apply the swim speed buff to the player + player.AddAura(SWIM_SPEED_BUFF_ID, SWIM_SPEED_BUFF_DURATION); + player.SendBroadcastMessage("You feel a surge of energy as you enter the water!"); + } + } +}; + +const OnPlayerLeaveWater: player_event_on_leave_water = (event: number, player: Player) => { + // Check if the player has the swim speed buff + if (player.HasAura(SWIM_SPEED_BUFF_ID)) { + // Remove the swim speed buff from the player + player.RemoveAura(SWIM_SPEED_BUFF_ID); + player.SendBroadcastMessage("The energy fades as you leave the water."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_WATER, (...args) => OnPlayerEnterWater(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEAVE_WATER, (...args) => OnPlayerLeaveWater(...args)); +``` + +In this example: +1. We define constants for the swim speed buff ID and duration. +2. We register event handlers for when a player enters and leaves water using `RegisterPlayerEvent`. +3. In the `OnPlayerEnterWater` event handler: + - We check if the player is in water using `player.IsInWater()`. + - If the player is in water and doesn't already have the swim speed buff, we apply the buff using `player.AddAura()` and send a broadcast message to the player. +4. In the `OnPlayerLeaveWater` event handler: + - We check if the player has the swim speed buff using `player.HasAura()`. + - If the player has the buff, we remove it using `player.RemoveAura()` and send a broadcast message to the player. + +This script enhances the player's experience by granting them a temporary swim speed buff whenever they enter water, making it easier to navigate and explore underwater areas. The buff is automatically removed when the player leaves the water. + +## IsMoving +Returns a boolean value indicating whether the player is currently moving or not. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the player is currently moving, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsMoving()` method to check if a player is moving and perform actions based on their movement status. + +```typescript +const SPEED_BOOST_AURA = 12345; // Replace with the actual aura ID for the speed boost + +const onPlayerMove: player_event_on_move = (event: number, player: Player, oldX: number, oldY: number, oldZ: number, newX: number, newY: number, newZ: number) => { + if (player.IsMoving()) { + // Check if the player already has the speed boost aura + if (!player.HasAura(SPEED_BOOST_AURA)) { + // Apply the speed boost aura to the player + player.AddAura(SPEED_BOOST_AURA, player); + player.SendBroadcastMessage("You feel a surge of energy as you start moving!"); + } + } else { + // Check if the player has the speed boost aura + if (player.HasAura(SPEED_BOOST_AURA)) { + // Remove the speed boost aura from the player + player.RemoveAura(SPEED_BOOST_AURA); + player.SendBroadcastMessage("The surge of energy fades away as you stop moving."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_MOVE, (...args) => onPlayerMove(...args)); +``` + +In this example: +1. We define a constant `SPEED_BOOST_AURA` to represent the aura ID for the speed boost effect. Replace it with the actual aura ID you want to use. + +2. We register the `PLAYER_EVENT_ON_MOVE` event using `RegisterPlayerEvent()` to listen for player movement. + +3. Inside the event handler function `onPlayerMove`, we check if the player is moving using the `IsMoving()` method. + +4. If the player is moving and doesn't already have the speed boost aura, we apply the aura using `AddAura()` and send a broadcast message to the player indicating the speed boost. + +5. If the player stops moving and has the speed boost aura, we remove the aura using `RemoveAura()` and send a broadcast message to the player indicating the fading of the speed boost. + +This script enhances the player's movement by applying a speed boost aura whenever they start moving and removes the aura when they stop moving. It provides a dynamic experience based on the player's movement status. + +## IsRested +Returns a boolean value indicating whether the player is currently rested or not. Being rested means the player has accumulated rest bonus experience points by logging out in an inn or a city. + +### Parameters +None + +### Returns +boolean - Returns `true` if the player is currently rested, `false` otherwise. + +### Example Usage +This example demonstrates how to check if a player is rested and grant them a bonus buff if they are. + +```typescript +const WELL_RESTED_SPELL_ID = 24705; +const WELL_RESTED_SPELL_DURATION = 3600000; // 1 hour in milliseconds + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + if (player.IsRested()) { + // Check if the player already has the Well Rested buff + if (!player.HasAura(WELL_RESTED_SPELL_ID)) { + // Apply the Well Rested buff to the player + player.AddAura(WELL_RESTED_SPELL_ID, WELL_RESTED_SPELL_DURATION); + player.SendBroadcastMessage("You feel well rested and have been granted a bonus buff!"); + } + } else { + // Check if the player has the Well Rested buff but is no longer rested + if (player.HasAura(WELL_RESTED_SPELL_ID)) { + // Remove the Well Rested buff from the player + player.RemoveAura(WELL_RESTED_SPELL_ID); + player.SendBroadcastMessage("You no longer feel rested and the bonus buff has been removed."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. We define constants for the Well Rested spell ID and its duration. +2. We register the `PLAYER_EVENT_ON_LOGIN` event to trigger the `OnLogin` function when a player logs in. +3. Inside the `OnLogin` function, we check if the player is rested using `player.IsRested()`. +4. If the player is rested and doesn't already have the Well Rested buff, we apply the buff using `player.AddAura()` and send a broadcast message to the player. +5. If the player is not rested but has the Well Rested buff, we remove the buff using `player.RemoveAura()` and send a broadcast message to the player. + +This script ensures that players who log in while rested receive the Well Rested buff, and players who lose their rested status have the buff removed. The script also prevents applying the buff multiple times if the player is already rested and has the buff. + +## IsTaxiCheater +Returns whether or not the player has the taxi cheat activated. This cheat allows players to teleport to any taxi node without the required riding skill, level or gold cost. + +### Parameters +None + +### Returns +boolean - 'true' if the player has the taxi cheat activated, 'false' otherwise. + +### Example Usage +In this example, we will create a command that allows players to toggle the taxi cheat on and off. The command will also inform the player of their current taxi cheat status. + +```typescript +// Command name and security level +const COMMAND_NAME = 'taxicheat'; +const COMMAND_SECURITY = SEC_PLAYER; + +function ToggleTaxiCheat(player: Player): void { + if (player.IsTaxiCheater()) { + // Disable the taxi cheat + player.SetTaxiCheater(false); + player.SendBroadcastMessage('Taxi cheat disabled.'); + } else { + // Enable the taxi cheat + player.SetTaxiCheater(true); + player.SendBroadcastMessage('Taxi cheat enabled.'); + } +} + +function OnCommand(player: Player, command: string): boolean { + if (command === COMMAND_NAME) { + ToggleTaxiCheat(player); + return true; + } + return false; +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, OnCommand); +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_COMMAND, (command, security) => { + return command === COMMAND_NAME && security >= COMMAND_SECURITY; +}); +``` + +In this script: +1. We define the command name and the required security level. +2. The `ToggleTaxiCheat` function checks the player's current taxi cheat status using `IsTaxiCheater()`. + - If the cheat is active, it disables the cheat using `SetTaxiCheater(false)` and informs the player. + - If the cheat is inactive, it enables the cheat using `SetTaxiCheater(true)` and informs the player. +3. The `OnCommand` function is called when the player enters a command. It checks if the entered command matches the defined command name (`taxicheat`). If it does, it calls the `ToggleTaxiCheat` function to toggle the cheat status. +4. We register the `OnCommand` function to the `PLAYER_EVENT_ON_COMMAND` event to handle player commands. +5. We also register the command to the `SERVER_EVENT_ON_COMMAND` event to define the command and its required security level. + +With this script, players can use the `.taxicheat` command to toggle the taxi cheat on and off. The command will also inform them of their current taxi cheat status. + +## IsVisibleForPlayer +Returns true if the player can see another player based on the rules of the game. This can be useful for custom scripted events +or features that require checking for visibility between players. + +### Parameters +- player: [Player](./player.md) - The player object to check visibility of + +### Returns +- boolean - True if this player can see the specified player, false otherwise. + +### Example Usage +Create a custom 'Manhunt' event where the closest player is always visible to the runner. The runner gets a repeating alert of the hunter's current distance. + +```typescript +let MANHUNT_RUNNER: Player | null; +let MANHUNT_HUNTER: Player | null; + +function StartManhuntEvent(player: Player) { + if (!MANHUNT_RUNNER) { + MANHUNT_RUNNER = player; + SendWorldMessage(`${player.GetName()} is now the hunted! The manhunt begins in 1 minute. Hunters get ready!`); + player.AddAura(31797, player); // Aura: Permament Feign Death + CreateLuaEvent(PrepareHunters, 1000 * 60, 1); + } +} + +function PrepareHunters() { + const plrs = GetPlayersInWorld(); + if (plrs && MANHUNT_RUNNER) { + MANHUNT_HUNTER = plrs.find(p => p.GetGUIDLow() !== MANHUNT_RUNNER!.GetGUIDLow()); + if (MANHUNT_HUNTER) { + CreateLuaEvent(StartHuntingAlert, 5000, 0); + SendWorldMessage(`${MANHUNT_HUNTER.GetName()} has been chosen as the hunter! The hunt is on. `/manhunt` to join the chase.`); + MANHUNT_HUNTER.Teleport(0, MANHUNT_RUNNER.GetX(), MANHUNT_RUNNER.GetY(), MANHUNT_RUNNER.GetZ(), MANHUNT_RUNNER.GetO()); + } + } +} + +function StartHuntingAlert() { + if (MANHUNT_RUNNER && MANHUNT_HUNTER) { + const dist = MANHUNT_RUNNER.GetDistance(MANHUNT_HUNTER); + if (MANHUNT_RUNNER.IsVisibleForPlayer(MANHUNT_HUNTER)) { + SendMessageToPlayer(MANHUNT_RUNNER, `The hunter is ${dist} yards from you and closing in!`); + } else { + SendMessageToPlayer(MANHUNT_RUNNER, `You've escaped the hunter's sight. Last seen ${dist} yards away.`); + } + } +} + +// Player chat command to join manhunt +function OnCommand_Manhunt(player: Player) { + if (MANHUNT_RUNNER && player.GetGUIDLow() !== MANHUNT_RUNNER.GetGUIDLow()) { + player.Teleport(0, MANHUNT_RUNNER.GetX(), MANHUNT_RUNNER.GetY(), MANHUNT_RUNNER.GetZ(), MANHUNT_RUNNER.GetO()); + } + return false; +} + +RegisterPlayerEvent(30, StartManhuntEvent); +RegisterPlayerGossipEvent(MANHUNT_RUNNER?.GetGUIDLow(), 0, OnCommand_Manhunt); +``` + +In this example, a 'manhunt' event is started by a random player becoming the runner. After a delay, another random player is chosen as the hunter and teleported to the runner's location. + +An event is started that will periodically alert the runner of the hunter's distance, using `IsVisibleForPlayer` to determine if they are still in sight. + +Other players can join the hunt by using the `/manhunt` command which will teleport them to the runner's current location. + +## KickPlayer +Kicks the player from the server. This will close the player's connection and log them out. You can also provide a reason for kicking the player. + +### Parameters +None + +### Returns +None + +### Example Usage +Here's an example of kicking a player from the server after they use a forbidden item: + +```typescript +const FORBIDDEN_ITEM_ENTRY = 1234; + +const OnItemUse: player_event_on_item_use = (event: number, player: Player, item: Item, target: GameObject | Item | Unit | None, cast: Spell) => { + if (item.GetEntry() === FORBIDDEN_ITEM_ENTRY) { + player.SendBroadcastMessage("Using this item is not allowed. You have been kicked from the server."); + + // Log the incident + const playerName = player.GetName(); + const playerGUID = player.GetGUID(); + const itemName = item.GetName(); + const logMessage = `Player ${playerName} (GUID: ${playerGUID}) used forbidden item: ${itemName} (Entry: ${FORBIDDEN_ITEM_ENTRY})`; + WorldDBQuery("INSERT INTO forbidden_item_log (timestamp, log_message) VALUES (NOW(), ?)", logMessage); + + // Kick the player + player.KickPlayer(); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ITEM_USE, (...args) => OnItemUse(...args)); +``` + +In this example: + +1. We define a constant `FORBIDDEN_ITEM_ENTRY` with the entry ID of the item that players are not allowed to use. + +2. We register a `player_event_on_item_use` event handler to listen for when a player uses an item. + +3. Inside the event handler, we check if the used item's entry matches the forbidden item entry. + +4. If the player used the forbidden item: + - We send a broadcast message to the player informing them that using the item is not allowed and that they have been kicked. + - We log the incident by inserting a record into a custom database table `forbidden_item_log` with the current timestamp, player name, player GUID, item name, and item entry. + - Finally, we call the `KickPlayer()` method to kick the player from the server. + +This example demonstrates how you can use the `KickPlayer()` method to remove a player from the server when they violate certain rules or perform undesired actions. It also showcases logging the incident in the database for future reference or analysis. + +## KillPlayer +This method will kill the player immediately. The player will be considered dead and will need to be resurrected or revived to continue playing. This can be useful for custom scripting events or handling certain conditions where the player needs to die. + +### Parameters +None + +### Returns +None + +### Example Usage +Here's an example of using `KillPlayer()` in a script that handles a custom boss encounter: + +```typescript +const BOSS_ENTRY = 1234; +const BOSS_KILL_PLAYER_CHANCE = 10; // 10% chance for the boss to instantly kill the player + +const BossEncounter: creature_event_on_combat = (event: number, creature: Creature, target: Unit): void => { + if (creature.GetEntry() !== BOSS_ENTRY || !target.IsPlayer()) { + return; + } + + const player = target.ToPlayer(); + + // Boss random ability that has a chance to instantly kill the player + if (math.random(1, 100) <= BOSS_KILL_PLAYER_CHANCE) { + creature.CastSpell(player, 12345); // Cast a spell effect on the player + player.KillPlayer(); + creature.SendUnitYell("Your life ends here!", 0); + } + + // Other boss encounter logic... +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_COMBAT, (...args) => BossEncounter(...args)); +``` + +In this example, during a boss encounter, there's a 10% chance for the boss to instantly kill the player using the `KillPlayer()` method. This is combined with a spell effect and a yell from the boss to create a more immersive experience. + +Another example could be a script that handles a player reaching a certain condition, such as a curse or a disease that will kill the player after a certain time: + +```typescript +const CURSE_SPELL_ENTRY = 5678; +const CURSE_DURATION = 1 * 60 * 1000; // 1 minute + +const CurseHandler: player_event_on_spell_hit = (event: number, player: Player, caster: Unit, spellEntry: number): void => { + if (spellEntry !== CURSE_SPELL_ENTRY) { + return; + } + + player.SendBroadcastMessage("You have been cursed! You will die in 1 minute unless you find a cure!"); + + // Create a timed event to kill the player after the curse duration + CreateTimedEvent(CURSE_DURATION, (owner: TimedEvent, eventData: number) => { + if (!player || !player.IsInWorld()) { + return; + } + + if (player.HasAura(CURSE_SPELL_ENTRY)) { + player.KillPlayer(); + player.SendBroadcastMessage("The curse has taken your life!"); + } + }, 0); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SPELL_HIT, (...args) => CurseHandler(...args)); +``` + +In this example, when a player is hit by a specific curse spell, a timed event is created to kill the player after 1 minute unless they manage to remove the curse. The `KillPlayer()` method is used to instantly kill the player when the curse duration expires. + +These examples demonstrate how the `KillPlayer()` method can be used in different scenarios to create custom scripted events and add interesting gameplay mechanics to the game. + +## KilledMonsterCredit +This method gives the player quest kill credit for a specified creature entry. When a player kills a creature that is required for a quest, this method can be used to update the player's quest progress. + +### Parameters +* entry: number - The ID of the creature from the `creature_template` table for which the player should receive kill credit. + +### Example Usage +In this example, we'll create a script that gives the player additional quest kill credit for a specific creature when they kill it. This can be useful for increasing the drop rate of quest items or accelerating quest progress. + +```typescript +const QUEST_ENTRY = 1234; // Replace with the actual quest ID +const CREATURE_ENTRY = 5678; // Replace with the actual creature ID +const ADDITIONAL_CREDIT_COUNT = 2; // Number of additional kill credits to award + +const onCreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + // Check if the killed creature is the one we're interested in + if (creature.GetEntry() === CREATURE_ENTRY) { + // Check if the player has the quest and it's incomplete + if (player.HasQuest(QUEST_ENTRY) && !player.HasAchieved(QUEST_ENTRY)) { + // Give the player quest kill credit for the creature + player.KilledMonsterCredit(CREATURE_ENTRY); + + // Award additional kill credits + for (let i = 0; i < ADDITIONAL_CREDIT_COUNT; i++) { + player.KilledMonsterCredit(CREATURE_ENTRY); + } + + // Send a message to the player + player.SendBroadcastMessage(`You have received ${ADDITIONAL_CREDIT_COUNT + 1} kill credits for the quest.`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => onCreatureKill(...args)); +``` + +In this script: +1. We define constants for the quest ID, creature ID, and the number of additional kill credits to award. +2. We register a player event listener for the `PLAYER_EVENT_ON_KILL_CREATURE` event. +3. When the event is triggered, we check if the killed creature matches the desired creature ID. +4. If the player has the quest and it's incomplete, we give the player the standard quest kill credit using `KilledMonsterCredit(CREATURE_ENTRY)`. +5. We then loop `ADDITIONAL_CREDIT_COUNT` times and call `KilledMonsterCredit(CREATURE_ENTRY)` to award additional kill credits. +6. Finally, we send a message to the player informing them about the awarded kill credits. + +This script enhances the player's quest experience by providing additional kill credits for a specific creature, making it easier to complete the quest. + +## LearnSpell +Teaches the player a new spell based on the Spell ID provided. These spells can be referenced in the World Database spell_template table. For more information about spells, you can find more details here: https://www.azerothcore.org/wiki/spell_template. + +### Parameters +- spellId: number - The Spell ID from the spell_template table. + +### Example Usage +Teach a player a new spell when they reach a certain level and class combination. + +```typescript +const SPELL_SHADOWFORM = 15473; +const CLASS_PRIEST = 5; +const LEVEL_REQUIREMENT = 40; + +const onLevelChange: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + const playerLevel = player.GetLevel(); + const playerClass = player.GetClass(); + + if (playerLevel >= LEVEL_REQUIREMENT && playerClass === CLASS_PRIEST && !player.HasSpell(SPELL_SHADOWFORM)) { + player.SendBroadcastMessage("You have reached level " + LEVEL_REQUIREMENT + " as a Priest. Learning Shadowform..."); + player.LearnSpell(SPELL_SHADOWFORM); + + const shadowformSpell = player.GetSpell(SPELL_SHADOWFORM); + if (shadowformSpell) { + const spellLink = shadowformSpell.GetSpellLink(); + player.SendBroadcastMessage("You have learned a new spell: " + spellLink); + } else { + player.SendBroadcastMessage("Failed to learn Shadowform. Please contact an administrator."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => onLevelChange(...args)); +``` + +In this example, when a player reaches level 40 and is a Priest class, the script checks if they already know the Shadowform spell (Spell ID 15473). If they don't have the spell yet, it teaches them the spell using the `LearnSpell` method. + +After learning the spell, the script retrieves the learned spell using `GetSpell` and checks if it was successfully learned. If the spell is found, it creates a spell link using `GetSpellLink` and sends a broadcast message to the player informing them about the newly learned spell. If the spell was not found after learning it, an error message is sent to the player, prompting them to contact an administrator. + +This example demonstrates how to use the `LearnSpell` method in combination with other player methods and events to create a more complex script that enhances the gameplay experience based on the player's level and class. + +## LearnTalent +Teaches the player a talent. Talents can be found in the `Talent.dbc` file. + +### Parameters +* talent_id: number - The ID of the talent to learn from `Talent.dbc`. +* talentRank: number - The rank of the talent. + +### Example Usage +This example will teach a player a random talent when they level up to level 10, 20, 30, 40, 50, 60, 70, 80. + +```typescript +// Constants for the example +const TALENT_MAGE_ARCANE_CONCENTRATION = 12577; +const TALENT_MAGE_ARCANE_MEDITATION = 12463; +const TALENT_MAGE_ARCANE_MIND = 12469; +const TALENT_MAGE_ARCANE_INSTABILITY = 15060; + +const talentTable: number[] = [ + TALENT_MAGE_ARCANE_CONCENTRATION, + TALENT_MAGE_ARCANE_MEDITATION, + TALENT_MAGE_ARCANE_MIND, + TALENT_MAGE_ARCANE_INSTABILITY +]; + +const levelUpEvent: player_event_on_level_change = (event: number, player: Player, oldLevel: number) => { + // Check if the player is a mage + if (player.GetClass() === Classes.CLASS_MAGE) { + if (oldLevel === 9 || oldLevel === 19 || oldLevel === 29 || oldLevel === 39 || + oldLevel === 49 || oldLevel === 59 || oldLevel === 69 || oldLevel === 79) { + + // Generate a random index + const talentIndex = Math.floor(Math.random() * talentTable.length); + // Teach a random talent + player.LearnTalent(talentTable[talentIndex], 1); + // Inform the player about the new talent + player.SendBroadcastMessage(`You have learned a new talent!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => levelUpEvent(...args)); +``` + +In this script: +1. We define constants for some mage talents from the Arcane tree. +2. We create an array `talentTable` that holds the talent IDs. +3. In the `levelUpEvent` function, we first check if the player is a mage using `player.GetClass()`. +4. If the player is a mage and their previous level (`oldLevel`) is 9, 19, 29, 39, 49, 59, 69, or 79, we proceed. +5. We generate a random index using `Math.floor(Math.random() * talentTable.length)` to select a random talent from the `talentTable`. +6. We teach the player the randomly selected talent at rank 1 using `player.LearnTalent(talentTable[talentIndex], 1)`. +7. We send a message to the player informing them about the new talent using `player.SendBroadcastMessage()`. + +This script adds an element of randomness and surprise for mage players, granting them a random Arcane talent every 10 levels until level 80. + +## LeaveBattleground +Forces the player to leave a battleground. If the player is not in a battleground, this method will have no effect. + +### Parameters +* teleToEntry: boolean (optional) - If set to true, the player will be teleported to their entry point for the battleground. + +### Example Usage +This example listens for the `PLAYER_EVENT_ON_COMMAND` event and checks if the player types the ".leavebg" command. If so, it checks if the player is in a battleground and then forces them to leave, teleporting them back to their entry point. + +```typescript +const onCommand: player_event_on_command = (event: number, player: Player, command: string, args: string[]) => { + if(command === "leavebg") { + if(player.InBattleground()) { + player.SendBroadcastMessage("You will now be removed from the battleground."); + player.LeaveBattleground(true); + } else { + player.SendBroadcastMessage("You are not currently in a battleground."); + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => onCommand(...args)); +``` + +In this more complex example, we listen for the `PLAYER_EVENT_ON_LOGOUT_REQUEST` event, which is triggered when a player attempts to log out. We check if the player is in a battleground, and if so, we prevent them from logging out and instead force them to leave the battleground after a 5 second delay. We use the `RegisterTimedEvent` function to create the delay. + +```typescript +const LOGOUT_DELAY = 5 * IN_MILLISECONDS; + +const onLogoutRequest: player_event_on_logout_request = (event: number, player: Player) => { + if(player.InBattleground()) { + player.SendBroadcastMessage("You cannot log out while in a battleground. You will be removed from the battleground in 5 seconds."); + PreventDefault(); + + const timedEvent: timed_event = (cPlayer: Player) => { + if(cPlayer.InBattleground()) { + cPlayer.LeaveBattleground(true); + } + }; + + RegisterTimedEvent(LOGOUT_DELAY, timedEvent, player); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGOUT_REQUEST, (...args) => onLogoutRequest(...args)); +``` + +## LogoutPlayer +Forces the player to log out of the game. This can be used to handle players that may need to be removed from the game or to handle custom logout events. + +### Parameters +* saveToDb: boolean (optional) - If set to true, the player's data will be saved to the database before logging out. If false or not provided, the player's data will not be saved. + +### Example Usage: +This example listens for a player to type the ".logout" command and then starts a 20 second logout timer before forcing the logout and saving the character data. + +```typescript +const LOGOUT_TIMER = 20000; // in ms (20 seconds) + +const command_logout: player_event_On_Chat = (event: number, player: Player, msg: string) => { + const msgParts = msg.split(/\s+/); + + if (msgParts[0].toLowerCase() === ".logout") { + player.SendBroadcastMessage(`You will be logged out in ${LOGOUT_TIMER / 1000} seconds.`); + + setTimeout(() => { + if (player.IsInCombat()) { + player.SendBroadcastMessage("You cannot log out while in combat!"); + return; + } + + player.SendBroadcastMessage("Logging out..."); + player.LogoutPlayer(true); + }, LOGOUT_TIMER); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => command_logout(...args)); +``` + +In this example: +1. We define a constant `LOGOUT_TIMER` to store the logout timer duration in milliseconds (20 seconds). +2. We listen for the player's chat event using `RegisterPlayerEvent` with the `PLAYER_EVENT_ON_CHAT` event. +3. In the event handler function `command_logout`, we split the chat message by whitespace to get the individual parts. +4. We check if the first part of the message (converted to lowercase) is equal to ".logout". +5. If the condition is met, we send a broadcast message to the player informing them about the logout timer. +6. We use `setTimeout` to delay the execution of the logout logic by the specified `LOGOUT_TIMER` duration. +7. Inside the `setTimeout` callback: + - We check if the player is in combat using `player.IsInCombat()`. + - If the player is in combat, we send a message informing them that they cannot log out during combat and return. + - If the player is not in combat, we send a message indicating that the logout process is starting. + - We call `player.LogoutPlayer(true)` to force the player to log out and save their character data to the database. + +This example demonstrates how the `LogoutPlayer` method can be used in conjunction with a custom chat command to implement a logout timer and handle the logout process while considering the player's combat state. + +## ModifyArenaPoints +This method allows you to add or remove Arena Points from a player's current total. Arena Points are a form of currency used to purchase various PvP rewards. If the amount is positive, points will be added to the player's total. If the amount is negative, points will be deducted from the player's total. + +### Parameters +* amount: number - The amount of Arena Points to add or remove from the player's current total. Positive values will add points, while negative values will deduct points. + +### Example Usage +Let's say we want to create a script that rewards players with bonus Arena Points for achieving a certain number of honorable kills in a single battleground match. Here's how we could implement this using the `ModifyArenaPoints` method: + +```typescript +const HONORABLE_KILLS_THRESHOLD = 15; +const ARENA_POINTS_BONUS = 50; + +const OnPlayerKilledUnit: player_event_on_killed_unit = (event: number, killer: Player, killed: Unit) => { + if (killed && killed.IsPlayer() && killer.InBattleground()) { + killer.SetData("BG_HONORABLE_KILLS", killer.GetData("BG_HONORABLE_KILLS") + 1); + + if (killer.GetData("BG_HONORABLE_KILLS") >= HONORABLE_KILLS_THRESHOLD) { + killer.ModifyArenaPoints(ARENA_POINTS_BONUS); + killer.SendBroadcastMessage(`You have been awarded ${ARENA_POINTS_BONUS} bonus Arena Points for achieving ${HONORABLE_KILLS_THRESHOLD} honorable kills in this battleground!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILLED_UNIT, (...args) => OnPlayerKilledUnit(...args)); +``` + +In this example, we define a constant `HONORABLE_KILLS_THRESHOLD` that represents the number of honorable kills a player must achieve in a single battleground to receive the bonus Arena Points. We also define a constant `ARENA_POINTS_BONUS` that specifies the number of bonus points to award. + +We then register a `PLAYER_EVENT_ON_KILLED_UNIT` event handler that triggers whenever a player kills another unit. Inside the event handler, we first check if the killed unit is a player and if the killer is currently in a battleground. If both conditions are met, we increment a custom data value `BG_HONORABLE_KILLS` for the killer using the `SetData` method. + +Next, we check if the killer's `BG_HONORABLE_KILLS` value has reached or exceeded the `HONORABLE_KILLS_THRESHOLD`. If it has, we use the `ModifyArenaPoints` method to add the `ARENA_POINTS_BONUS` to the killer's Arena Points total. We also send a broadcast message to the killer informing them of the bonus points they have been awarded. + +This script encourages players to perform well in battlegrounds by rewarding them with bonus Arena Points for achieving a high number of honorable kills in a single match. + +## ModifyHonorPoints +This method allows you to add or remove honor points from a player's current total. Honor points are used in World of Warcraft to purchase various PvP related items and rewards. + +### Parameters +* amount: number - The amount of honor points to add or remove. Positive numbers will add honor points, while negative numbers will deduct honor points. + +### Example Usage +This example script awards bonus honor points to a player when they kill a player of the opposite faction who is within 5 levels of their own level. + +```typescript +const BONUS_HONOR_POINTS = 100; +const MAX_LEVEL_DIFFERENCE = 5; + +const OnPVPKill: player_event_on_kill_player = (event: number, killer: Player, killed: Player) => { + const killerLevel = killer.GetLevel(); + const killedLevel = killed.GetLevel(); + + if (Math.abs(killerLevel - killedLevel) <= MAX_LEVEL_DIFFERENCE) { + const killerHonorPoints = killer.GetHonorPoints(); + const newHonorPoints = killerHonorPoints + BONUS_HONOR_POINTS; + + killer.ModifyHonorPoints(BONUS_HONOR_POINTS); + killer.SendBroadcastMessage(`You have been awarded ${BONUS_HONOR_POINTS} bonus honor points for killing a player within ${MAX_LEVEL_DIFFERENCE} levels of you!`); + killer.SendBroadcastMessage(`Your total honor points are now ${newHonorPoints}.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_PLAYER, (...args) => OnPVPKill(...args)); +``` + +In this script: +1. We define constants for the bonus honor points and the maximum level difference allowed to receive the bonus. +2. In the `OnPVPKill` event handler, we get the levels of both the killer and the killed players. +3. We check if the absolute difference between their levels is less than or equal to the `MAX_LEVEL_DIFFERENCE`. +4. If the level difference condition is met, we get the killer's current honor points and calculate their new total after adding the bonus. +5. We use `ModifyHonorPoints()` to add the bonus honor points to the killer's total. +6. We send the killer two messages: one informing them of the bonus honor points received, and another with their new total honor points. + +This script encourages players to engage in PvP combat with players of a similar level by rewarding them with bonus honor points, adding an extra challenge and incentive to PvP gameplay. + +## ModifyMoney +Adds or subtracts money from the player's current money amount. Money amounts are always represented in copper. + +### Parameters +* copperAmt: number - The amount of money in copper to add or subtract from the player's current money amount. Use a positive value to add money, or a negative value to subtract money. + +### Example Usage +This example demonstrates how to modify a player's money based on their level when they kill a creature. If the player is level 10 or higher, they will receive bonus money for each level above 10. If the player has less than 1 gold (10000 copper), their money will be reduced by 10% of the amount they received for killing the creature. + +```typescript +const onCreatureKill: player_event_on_creature_kill = (event: number, player: Player, creature: Creature) => { + const BASE_MONEY_REWARD = 500; // 5 silver + const LEVEL_BONUS_THRESHOLD = 10; + const LEVEL_BONUS_AMOUNT = 100; // 1 silver per level + const LOW_MONEY_THRESHOLD = 10000; // 1 gold + const LOW_MONEY_PENALTY_PCT = 0.1; // 10% penalty + + let moneyReward = BASE_MONEY_REWARD; + + if (player.GetLevel() > LEVEL_BONUS_THRESHOLD) { + const levelBonus = (player.GetLevel() - LEVEL_BONUS_THRESHOLD) * LEVEL_BONUS_AMOUNT; + moneyReward += levelBonus; + } + + player.ModifyMoney(moneyReward); + + if (player.GetCoinage() < LOW_MONEY_THRESHOLD) { + const penaltyAmount = Math.floor(moneyReward * LOW_MONEY_PENALTY_PCT); + player.ModifyMoney(-penaltyAmount); + player.SendBroadcastMessage(`You have been penalized ${penaltyAmount} copper for having low funds.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CREATURE_KILL, (...args) => onCreatureKill(...args)); +``` + +In this example: +1. The base money reward for killing a creature is set to 5 silver (500 copper). +2. If the player's level is higher than the `LEVEL_BONUS_THRESHOLD` (10), they receive an additional 1 silver (100 copper) for each level above 10. +3. The calculated `moneyReward` is added to the player's money using `player.ModifyMoney(moneyReward)`. +4. If the player's total money (`player.GetCoinage()`) is less than the `LOW_MONEY_THRESHOLD` (1 gold or 10000 copper), they are penalized by 10% of the `moneyReward` they just received. + - The penalty amount is calculated using `Math.floor(moneyReward * LOW_MONEY_PENALTY_PCT)` to ensure an integer value. + - The penalty is subtracted from the player's money using `player.ModifyMoney(-penaltyAmount)`. + - The player is informed about the penalty via a broadcast message. + +This example showcases how to use `ModifyMoney()` to add and subtract money from a player based on specific conditions, such as their level and current money amount. + +## Mute +Mutes the player for a specified duration, preventing them from sending chat messages or mails during that time. + +### Parameters +* muteTime: number - The duration in seconds for which the player will be muted. + +### Example Usage +Here's an example of how to mute a player for a certain duration when they use a specific word in chat: + +```typescript +const MUTE_DURATION = 300; // 5 minutes +const FORBIDDEN_WORD = "badword"; + +const onChat: player_event_on_chat = (event: number, player: Player, msg: string, Type: number, lang: Language): void => { + if (msg.toLowerCase().includes(FORBIDDEN_WORD)) { + player.Mute(MUTE_DURATION); + + // Send a message to the player informing them of the mute + player.SendBroadcastMessage(`You have been muted for ${MUTE_DURATION} seconds for using a forbidden word.`); + + // Announce to other players that the offender has been muted + player.GetMap().SendServerMessage(`Player ${player.GetName()} has been muted for using a forbidden word.`); + + // Log the mute event to the server console + console.log(`Player ${player.GetName()} (GUID: ${player.GetGUID()}) has been muted for ${MUTE_DURATION} seconds.`); + + // Optionally, you can also store the mute information in the database for tracking purposes + let query = `INSERT INTO player_mutes (guid, mute_duration, mute_reason, mute_timestamp) VALUES (${player.GetGUID()}, ${MUTE_DURATION}, 'Using forbidden word', ${GetUnixTime()});`; + QueryWorld(query); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CHAT, (...args) => onChat(...args)); +``` + +In this example: +1. We define the mute duration (in seconds) and the forbidden word that triggers the mute. +2. When a player sends a chat message, we check if the message contains the forbidden word (case-insensitive). +3. If the forbidden word is found, we mute the player using `player.Mute(MUTE_DURATION)`. +4. We send a message to the muted player informing them about the mute duration. +5. We announce to other players on the same map that the offender has been muted. +6. We log the mute event to the server console for administrators to review. +7. Optionally, we insert a record into a custom database table `player_mutes` to store information about the mute event for tracking purposes. + +This script demonstrates how to effectively utilize the `Mute` method to handle chat violations and maintain a positive gaming environment. The mute duration can be adjusted based on the severity of the offense or your server's policies. + +## RemoveFromBattlegroundRaid +This method forcefully removes the player from a battleground raid group. It can be useful in situations where you need to manually manage a player's participation in a battleground raid, such as when implementing custom battleground mechanics or handling player disconnections. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any value. + +### Example Usage +Here's an example of how you can use the `RemoveFromBattlegroundRaid` method to handle player disconnections in a battleground: + +```typescript +const BATTLEGROUND_ID = 1; // Replace with the desired battleground ID + +const onPlayerLogout: player_event_on_logout = (event: number, player: Player) => { + const bgId = player.GetBattlegroundId(); + + if (bgId === BATTLEGROUND_ID) { + const bg = player.GetBattleground(); + + if (bg) { + const bgPlayers = bg.GetPlayers(); + const disconnectedCount = bgPlayers.filter(p => !p.IsInWorld()).length; + + if (disconnectedCount >= bgPlayers.length * 0.5) { + // If more than 50% of the players have disconnected, remove all players from the battleground raid + bgPlayers.forEach(p => p.RemoveFromBattlegroundRaid()); + bg.SetStatus(BattlegroundStatus.STATUS_WAIT_LEAVE); + } else { + // If the disconnected player is in a battleground raid, remove them from it + if (player.IsInBattlegroundRaid()) { + player.RemoveFromBattlegroundRaid(); + } + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGOUT, (...args) => onPlayerLogout(...args)); +``` + +In this example: +1. We define a constant `BATTLEGROUND_ID` to specify the ID of the battleground we want to handle disconnections for. +2. We register a player event handler for the `PLAYER_EVENT_ON_LOGOUT` event. +3. When a player logs out, we check if they are in the specified battleground using `player.GetBattlegroundId()`. +4. If the player is in the battleground, we retrieve the battleground instance using `player.GetBattleground()`. +5. We count the number of disconnected players in the battleground using `bgPlayers.filter(p => !p.IsInWorld()).length`. +6. If more than 50% of the players have disconnected, we remove all players from the battleground raid using `bgPlayers.forEach(p => p.RemoveFromBattlegroundRaid())` and set the battleground status to `STATUS_WAIT_LEAVE`. +7. If the disconnected player is in a battleground raid (but less than 50% of players have disconnected), we remove them from the raid using `player.RemoveFromBattlegroundRaid()`. + +This script ensures that if a significant number of players disconnect from the battleground, all players are removed from the battleground raid, and the battleground is put into a waiting state. If only a few players disconnect, they are individually removed from the battleground raid. + +## RemoveFromGroup +This method forces the player to leave their current group or raid. This can be useful for custom scripting where you need to temporarily remove a player from a group and add them back, or if you want to disband an entire group. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any values. + +### Example Usage +Temporarily remove a player from a group, then add them back after 30 seconds: +```typescript +const REJOIN_DELAY = 30 * 1000; // 30 seconds + +const onKillCredit: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + const group = player.GetGroup(); + + if (group) { + // Store the player's group information + const groupGuid = group.GetGUID(); + const subGroupId = group.GetMemberGroup(player.GetGUID()); + + // Remove the player from the group + player.RemoveFromGroup(); + + // Delay the player rejoining their group + player.AddDelayedEvent(REJOIN_DELAY, () => { + // Check if the group still exists + const oldGroup = Group.GetGroupByGUID(groupGuid); + if (oldGroup) { + // Rejoin the group in the same subgroup + oldGroup.AddMember(player.GetGUID(), subGroupId); + } + }); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => onKillCredit(...args)); +``` + +In this example, when a player kills a creature, they are temporarily removed from their group. After a delay of 30 seconds, the script checks if the original group still exists, and if so, the player is added back to the group in the same subgroup they were in before. + +This can be useful in certain scripting scenarios where you need to temporarily isolate a player from their group, perform some actions, and then add them back to the group. + +Note: Be cautious when using this method, as removing players from groups unexpectedly can lead to confusion and frustration for players. Make sure to communicate clearly to the players what is happening and why, and ensure that the removal is only temporary if that is the intent. + +## RemoveItem +Removes a specified amount of an item from the player's inventory. The item can be specified by either the item object itself or the item entry ID. + +### Parameters +* item: [Item](./item.md) - (Optional) The item object to remove from the player's inventory. +* entry: number - The entry ID of the item to remove from the player's inventory. +* itemCount: number - (Optional) The amount of the item to remove. If not specified, it defaults to 1. + +### Example Usage +This example script listens for the PLAYER_EVENT_ON_QUEST_ABANDON event and removes the quest items from the player's inventory when they abandon the quest. + +```typescript +const QUEST_ITEM_ENTRY_1 = 12345; +const QUEST_ITEM_ENTRY_2 = 67890; + +const onQuestAbandon: player_event_on_quest_abandon = (event: number, player: Player, quest: Quest) => { + const questId = quest.GetId(); + + if (questId === 1234) { + // Remove the first quest item + player.RemoveItem(null, QUEST_ITEM_ENTRY_1, 1); + + // Remove all instances of the second quest item + const itemCount = player.GetItemCount(QUEST_ITEM_ENTRY_2); + player.RemoveItem(null, QUEST_ITEM_ENTRY_2, itemCount); + + // Optionally, you can also remove the quest itself from the player's quest log + player.RemoveQuest(questId); + + // Inform the player that the quest items have been removed + player.SendBroadcastMessage("The quest items have been removed from your inventory."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_ABANDON, (...args) => onQuestAbandon(...args)); +``` + +In this example: +1. We define the entry IDs of the quest items that need to be removed when the player abandons the quest. +2. We listen for the PLAYER_EVENT_ON_QUEST_ABANDON event using the RegisterPlayerEvent function. +3. When the event is triggered, we check if the abandoned quest's ID matches the specific quest we are interested in (in this case, quest ID 1234). +4. If it matches, we remove the first quest item using player.RemoveItem, specifying the item entry ID and the count of 1. +5. We then remove all instances of the second quest item by first getting the count of the item in the player's inventory using player.GetItemCount and then removing that count using player.RemoveItem. +6. Optionally, we can also remove the quest itself from the player's quest log using player.RemoveQuest. +7. Finally, we send a broadcast message to the player informing them that the quest items have been removed from their inventory. + +This script ensures that when a player abandons a specific quest, the associated quest items are automatically removed from their inventory, providing a convenient way to manage quest-related items. + +## RemoveLifetimeKills +Removes a specified number of lifetime kills from the player's lifetime kill count. This can be useful for implementing custom penalties, prestige systems, or adjusting the player's kill count based on certain conditions or events. + +### Parameters +* val: number - The number of lifetime kills to remove from the player's count. + +### Example Usage +In this example, we'll create a script that reduces a player's lifetime kill count by a percentage whenever they die in a specific map. + +```typescript +const MAP_ID = 123; // Replace with the desired map ID +const KILL_COUNT_PENALTY_PCT = 0.1; // 10% penalty + +const OnPlayerDeath: player_event_on_death = (event: number, player: Player, killer: WorldObject) => { + if (player.GetMapId() === MAP_ID) { + const currentKills = player.GetLifetimeKills(); + const penaltyKills = Math.floor(currentKills * KILL_COUNT_PENALTY_PCT); + + if (penaltyKills > 0) { + player.RemoveLifetimeKills(penaltyKills); + player.SendBroadcastMessage(`You have lost ${penaltyKills} lifetime kills as a penalty for dying in this map.`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => OnPlayerDeath(...args)); +``` + +In this script: +1. We define the specific `MAP_ID` where the penalty will be applied and the `KILL_COUNT_PENALTY_PCT` as 10%. +2. When a player dies, the `OnPlayerDeath` event is triggered. +3. We check if the player's current map matches the specified `MAP_ID`. +4. If the player is in the correct map, we calculate the number of kills to remove based on the current lifetime kills and the penalty percentage. +5. If the calculated `penaltyKills` is greater than 0, we use the `RemoveLifetimeKills` method to subtract the penalty from the player's lifetime kill count. +6. Finally, we send a broadcast message to the player informing them about the number of lifetime kills they lost as a penalty. + +This script demonstrates how the `RemoveLifetimeKills` method can be used in combination with other game events and conditions to create custom penalties or adjustments to a player's lifetime kill count based on specific circumstances. + +## RemoveQuest +Removes the specified quest from the player's quest log. If the quest is complete, it will be removed from the player's completed quests. If the quest is incomplete, it will be removed from the player's active quests. + +### Parameters +* entry: number - The entry ID of the quest to remove. + +### Example Usage +In this example, we'll remove a specific quest from the player's quest log when they enter a certain area. This could be useful for removing outdated or deprecated quests that are no longer relevant to the game. + +```typescript +const DEPRECATED_QUEST_ENTRY = 1234; +const DEPRECATED_QUEST_AREA = 5678; + +const OnAreaTrigger: player_event_on_area_trigger = (event: number, player: Player, areaId: number) => { + if (areaId === DEPRECATED_QUEST_AREA) { + if (player.HasQuest(DEPRECATED_QUEST_ENTRY)) { + player.RemoveQuest(DEPRECATED_QUEST_ENTRY); + player.SendBroadcastMessage("The deprecated quest has been removed from your quest log."); + + // Check if the player has any items related to the quest + const questItems = [1234, 5678, 9012]; // Replace with actual item entry IDs + for (const itemEntry of questItems) { + const item = player.GetItemByEntry(itemEntry); + if (item) { + player.RemoveItem(item.GetEntry(), item.GetCount()); + player.SendBroadcastMessage(`Removed ${item.GetCount()}x ${item.GetName()} from your inventory.`); + } + } + + // Optionally, grant the player a small reward for having the quest + const rewardItemEntry = 1234; // Replace with the desired reward item entry ID + const rewardItemCount = 1; + player.AddItem(rewardItemEntry, rewardItemCount); + player.SendBroadcastMessage(`You have been granted ${rewardItemCount}x ${GetItemLink(rewardItemEntry)} as compensation.`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER, (...args) => OnAreaTrigger(...args)); +``` + +In this script: +1. We define the entry ID of the deprecated quest and the area ID that triggers the quest removal. +2. When the player enters the specified area, we check if they have the deprecated quest in their quest log using `player.HasQuest()`. +3. If the player has the quest, we remove it using `player.RemoveQuest()` and send a broadcast message to inform the player. +4. We then check if the player has any items related to the quest in their inventory. If found, we remove those items using `player.RemoveItem()` and send a message to notify the player. +5. Optionally, we can grant the player a small reward item as compensation for having the quest. We use `player.AddItem()` to add the reward item to their inventory and send a message to inform them. +6. Finally, we register the `OnAreaTrigger` event to trigger the script whenever the player enters the specified area. + +This script demonstrates how to remove a quest from the player's quest log and handle related tasks such as removing quest items and granting a small reward. + +## RemoveSpell +Removes a spell from the player's spell book based on the spell entry ID. + +### Parameters +* entry: number - The ID of the spell to remove from the player's spell book + +### Example Usage +This example listens for the `PLAYER_EVENT_ON_LEARN_SPELL` event and removes a spell if the player already knows a similar spell. + +```typescript +const SPELL_SLOW_FALL = 130; +const SPELL_LEVITATE = 1706; + +const onLearnSpell: player_event_on_learn_spell = (event: number, player: Player, spellId: number): void => { + if (spellId === SPELL_SLOW_FALL) { + if (player.HasSpell(SPELL_LEVITATE)) { + player.RemoveSpell(SPELL_LEVITATE); + player.SendBroadcastMessage("You have learned Slow Fall. Levitate has been removed from your spell book."); + } + } + else if (spellId === SPELL_LEVITATE) { + if (player.HasSpell(SPELL_SLOW_FALL)) { + player.RemoveSpell(SPELL_SLOW_FALL); + player.SendBroadcastMessage("You have learned Levitate. Slow Fall has been removed from your spell book."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEARN_SPELL, (...args) => onLearnSpell(...args)); +``` + +In this example: +1. We define constants for the spell IDs of Slow Fall and Levitate. +2. We register a callback function `onLearnSpell` for the `PLAYER_EVENT_ON_LEARN_SPELL` event. +3. When the player learns a new spell, the `onLearnSpell` function is called with the player object and the learned spell ID. +4. If the learned spell is Slow Fall (ID 130): + - We check if the player already has the Levitate spell using `player.HasSpell(SPELL_LEVITATE)`. + - If the player has Levitate, we remove it from their spell book using `player.RemoveSpell(SPELL_LEVITATE)`. + - We send a broadcast message to the player informing them that Levitate has been removed. +5. Similarly, if the learned spell is Levitate (ID 1706): + - We check if the player already has the Slow Fall spell using `player.HasSpell(SPELL_SLOW_FALL)`. + - If the player has Slow Fall, we remove it from their spell book using `player.RemoveSpell(SPELL_SLOW_FALL)`. + - We send a broadcast message to the player informing them that Slow Fall has been removed. + +This script ensures that the player only has one of the two similar spells (Slow Fall or Levitate) in their spell book at a time. When they learn one of these spells, the other spell is automatically removed to avoid redundancy. + +## RemovedInsignia +This method is called when a player loots another player's corpse and removes their insignia. It is commonly used in PvP scenarios where players can loot insignias from fallen enemies to gain honor points or other rewards. + +### Parameters +* looter: [Player](./player.md) - The player who is looting the insignia from the corpse. + +### Example Usage +In this example, we'll create a script that rewards players with honor points and a custom currency called "Conquest Points" when they loot an insignia from an enemy player's corpse in a battleground. + +```typescript +const CONQUEST_POINTS_ENTRY = 123456; // Custom currency entry ID +const CONQUEST_POINTS_AMOUNT = 10; // Amount of Conquest Points to reward +const HONOR_POINTS_AMOUNT = 100; // Amount of Honor Points to reward + +const onPlayerLootInsignia: player_event_on_loot_insignia = (event: number, player: Player, looter: Player): void => { + // Check if the player is in a battleground + if (player.InBattleground()) { + // Reward the looter with Conquest Points + looter.AddItem(CONQUEST_POINTS_ENTRY, CONQUEST_POINTS_AMOUNT); + + // Reward the looter with Honor Points + looter.ModifyHonorPoints(HONOR_POINTS_AMOUNT); + + // Send a message to the looter + looter.SendBroadcastMessage(`You have looted ${player.GetName()}'s insignia and received ${CONQUEST_POINTS_AMOUNT} Conquest Points and ${HONOR_POINTS_AMOUNT} Honor Points!`); + + // Send a message to the player whose insignia was looted + player.SendBroadcastMessage(`Your insignia has been looted by ${looter.GetName()}!`); + + // Log the event to the server console + console.log(`[Insignia Looted] ${looter.GetName()} looted ${player.GetName()}'s insignia in a battleground.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOOT_INSIGNIA, (...args) => onPlayerLootInsignia(...args)); +``` + +In this script: +1. We define constants for the custom currency entry ID, the amount of Conquest Points to reward, and the amount of Honor Points to reward. +2. We create a function called `onPlayerLootInsignia` that handles the `PLAYER_EVENT_ON_LOOT_INSIGNIA` event. +3. Inside the function, we first check if the player whose insignia is being looted is in a battleground using the `InBattleground()` method. +4. If the player is in a battleground, we reward the looter with Conquest Points using the `AddItem()` method and the specified entry ID and amount. +5. We also reward the looter with Honor Points using the `ModifyHonorPoints()` method and the specified amount. +6. We send a broadcast message to the looter informing them of the rewards they received using the `SendBroadcastMessage()` method. +7. We send a broadcast message to the player whose insignia was looted, informing them of who looted their insignia. +8. Finally, we log the event to the server console for tracking purposes. + +This script enhances the PvP experience by rewarding players for looting insignias from enemy players' corpses in battlegrounds, providing an incentive for players to actively participate in PvP combat. + +## ResetAchievements +This method will reset all of the player's completed achievements, effectively removing any achievements they have earned on their account. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any values. + +### Example Usage +In this example, we will reset a player's achievements if they have been inactive for a certain number of days. This script will run whenever a player logs into the world. + +```typescript +const DAYS_INACTIVE_THRESHOLD = 90; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + // Get the player's last login timestamp + const lastLogin = player.GetLastLogin(); + + // Get the current timestamp + const currentTime = os.time(); + + // Calculate the number of days since the player's last login + const daysSinceLastLogin = (currentTime - lastLogin) / 86400; // 86400 seconds in a day + + // If the player has been inactive for more than the threshold, reset their achievements + if (daysSinceLastLogin > DAYS_INACTIVE_THRESHOLD) { + player.SendBroadcastMessage(`Welcome back! Due to your extended absence, your achievements have been reset.`); + player.ResetAchievements(); + + // Optionally, you can also grant the player a special "Returning Player" achievement + const RETURNING_PLAYER_ACHIEVEMENT_ID = 1234; + player.AddAchievement(RETURNING_PLAYER_ACHIEVEMENT_ID); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this script: +1. We define a constant `DAYS_INACTIVE_THRESHOLD` to set the number of days a player must be inactive before their achievements are reset. +2. We register a `PLAYER_EVENT_ON_LOGIN` event handler to run our script whenever a player logs into the world. +3. We retrieve the player's last login timestamp using `player.GetLastLogin()`. +4. We calculate the number of days since the player's last login by subtracting the last login timestamp from the current timestamp and dividing by the number of seconds in a day (86400). +5. If the number of days since the player's last login exceeds our inactive threshold, we proceed to reset their achievements. +6. We send the player a broadcast message informing them that their achievements have been reset due to their extended absence. +7. We call the `player.ResetAchievements()` method to reset all of the player's completed achievements. +8. Optionally, we can also grant the player a special "Returning Player" achievement using `player.AddAchievement()` to acknowledge their return to the game after an extended absence. + +This script provides a way to manage inactive players' achievements and encourage them to return to the game by offering a special "Returning Player" achievement. You can customize the inactive threshold and the messages sent to the player to suit your server's needs. + +## ResetAllCooldowns +This method resets all of the player's cooldowns, including spell cooldowns, item cooldowns, and category cooldowns. + +### Parameters +None + +### Returns +None + +### Example Usage +This example script demonstrates how to reset a player's cooldowns when they die in a specific area. + +```typescript +const AREA_ID = 1234; // Replace with the desired area ID + +const onPlayerDeath: player_event_on_death = (event: number, player: Player, killer: Unit) => { + if (player.GetAreaId() === AREA_ID) { + player.ResetAllCooldowns(); + player.SendBroadcastMessage("Your cooldowns have been reset!"); + + // Optionally, you can also reset the player's item cooldowns + const items = player.GetItems(); + for (const item of items) { + item.ResetCooldown(); + } + + // You can also reset specific spell category cooldowns + const categoryId = 123; // Replace with the desired spell category ID + player.ResetTypeCooldowns(categoryId); + + // Optionally, you can send a message to the player's party or raid + const group = player.GetGroup(); + if (group) { + group.SendGroupMessage(`${player.GetName()}'s cooldowns have been reset!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => onPlayerDeath(...args)); +``` + +In this example: +1. We define a constant `AREA_ID` to specify the area where the cooldown reset should occur. +2. Inside the `onPlayerDeath` event handler, we check if the player's current area matches the specified `AREA_ID`. +3. If the player is in the desired area, we call `player.ResetAllCooldowns()` to reset all of their cooldowns. +4. We send a broadcast message to the player informing them that their cooldowns have been reset. +5. Optionally, we can also reset the player's item cooldowns by iterating over their items using `player.GetItems()` and calling `item.ResetCooldown()` on each item. +6. We can also reset specific spell category cooldowns by calling `player.ResetTypeCooldowns(categoryId)` with the desired category ID. +7. Optionally, we can send a message to the player's party or raid using `group.SendGroupMessage()` if the player is in a group. +8. Finally, we register the `onPlayerDeath` event handler using `RegisterPlayerEvent()` to trigger the cooldown reset when the player dies. + +This example showcases a more advanced usage of the `ResetAllCooldowns()` method, demonstrating how to reset cooldowns conditionally based on the player's location and how to reset specific item and spell category cooldowns as well. It also includes optional features like sending messages to the player and their group. + +## ResetHonor +Resets the player's weekly honor points and kills to zero. This is useful for managing weekly rewards or ladder rankings based on honor points earned each week. + +### Parameters +None + +### Returns +None + +### Example Usage +This example script will reset all online players' weekly honor every Wednesday at midnight server time. It also rewards players with bonus gold based on their weekly honor points earned before the reset occurs. + +```typescript +// Set up a weekly honor reset schedule +const WEEKLY_HONOR_RESET_DAY = 3; // 3 = Wednesday +const WEEKLY_HONOR_RESET_HOUR = 0; // 0 = Midnight + +// Define honor point thresholds and their respective gold rewards +const HONOR_REWARD_TIERS = [ + { points: 5000, gold: 100 }, + { points: 10000, gold: 250 }, + { points: 20000, gold: 500 }, +]; + +function RewardWeeklyHonor(player: Player): void { + const honorPoints = player.GetHonorPoints(); + + for (const { points, gold } of HONOR_REWARD_TIERS) { + if (honorPoints >= points) { + player.ModifyMoney(gold * 10000); + player.SendBroadcastMessage(`You have been rewarded ${gold} gold for earning over ${points} honor this week!`); + break; + } + } +} + +function PerformWeeklyHonorReset(): void { + const players = GetPlayersInWorld(); + + for (const player of players) { + RewardWeeklyHonor(player); + player.ResetHonor(); + player.SendBroadcastMessage("Your weekly honor has been reset. Keep up the good fight!"); + } +} + +function OnWorldUpdate(events: Map) { + const today = os.date("*t"); + + if (today.wday == WEEKLY_HONOR_RESET_DAY && today.hour == WEEKLY_HONOR_RESET_HOUR) { + PerformWeeklyHonorReset(); + } +} + +RegisterServerEvent(ServerEvents.ELUNA_EVENT_ON_LUA_STATE_CLOSE, OnWorldUpdate); +``` +This script does the following: + +1. Defines constants for the weekly reset day and hour, as well as honor point thresholds and their corresponding gold reward amounts. + +2. Implements a `RewardWeeklyHonor` function that checks a player's weekly honor points against the defined thresholds and rewards them accordingly with bonus gold, sending them a message about their reward. + +3. Implements a `PerformWeeklyHonorReset` function that iterates through all online players, rewards their weekly honor using the `RewardWeeklyHonor` function, resets their honor to zero using the `ResetHonor` method, and sends them a message confirming the reset. + +4. Registers an `OnWorldUpdate` event handler that triggers the `PerformWeeklyHonorReset` function every Wednesday at midnight server time. + +This script incentivizes players to actively participate in PvP throughout the week to earn honor points and receive gold rewards, while still ensuring a fair playing field by resetting everyone's honor points back to zero on a weekly basis. + +## ResetPetTalents +This method will reset all talent points for the player's active pet, allowing for the pet's talents to be re-selected. + +### Parameters +None + +### Returns +None + +### Example Usage +This example will reset the player's pet's talents when the player levels up and their level is divisible by 10. + +```typescript +const LEVELS_TO_RESET_PET_TALENTS = [10, 20, 30, 40, 50, 60, 70, 80]; + +const OnPlayerLevelUp: player_event_on_level_change = (event: number, player: Player, oldLevel: number): void => { + const newLevel = player.GetLevel(); + + if (LEVELS_TO_RESET_PET_TALENTS.includes(newLevel)) { + const pet = player.GetPet(); + + if (pet) { + player.ResetPetTalents(); + + player.SendBroadcastMessage(`Your pet's talents have been reset due to reaching level ${newLevel}!`); + + const stableSlotCount = player.GetStableSlots(); + for (let i = 0; i < stableSlotCount; i++) { + const stablePet = player.GetStablePet(i); + if (stablePet) { + player.ResetPetTalents(); + player.SendBroadcastMessage(`Your stable pet's (slot ${i + 1}) talents have also been reset.`); + } + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEVEL_CHANGE, (...args) => OnPlayerLevelUp(...args)); +``` + +In this example: +1. We define an array of levels at which we want to reset the player's pet's talents. +2. When the player levels up, we check if their new level is included in the `LEVELS_TO_RESET_PET_TALENTS` array. +3. If the player's level matches one of the defined levels, we proceed with resetting their active pet's talents using `player.ResetPetTalents()`. +4. We send a broadcast message to the player informing them that their pet's talents have been reset. +5. We also iterate through the player's stable slots and reset the talents of any pets in the stable. +6. For each stable pet that had its talents reset, we send an additional broadcast message to the player indicating which stable slot the pet is in. + +This script ensures that the player's pet and stable pets have their talents reset at key levels, allowing the player to re-select their pet's talents and adapt to new challenges as they progress through the game. + +## ResetSpellCooldown +Resets the cooldown of a specified spell for the player. This can be useful for creating custom abilities or effects that bypass the default spell cooldown restrictions. + +### Parameters +* spellId: number - The ID of the spell to reset the cooldown for. You can find spell IDs in the `spell_template` table in the world database. +* update: boolean (optional) - If set to true, will send an update to the client to reflect the cooldown reset. Defaults to false if not specified. + +### Example Usage +Creating a custom item that resets the cooldown of the Hearthstone spell when used: +```typescript +const HEARTHSTONE_SPELL_ID = 8690; +const CUSTOM_ITEM_ENTRY = 123456; + +const useItem: player_event_on_use_item = (event, player, item, target) => { + if (item.GetEntry() === CUSTOM_ITEM_ENTRY) { + player.ResetSpellCooldown(HEARTHSTONE_SPELL_ID, true); + player.SendBroadcastMessage("Your Hearthstone cooldown has been reset!"); + + // Remove the item after use + player.RemoveItem(item.GetEntry(), 1); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => useItem(...args)); +``` + +In this example, we create a custom item with the entry ID `123456`. When a player uses this item, the script checks if the item's entry matches the custom item entry. If it does, the script will: +1. Reset the cooldown of the Hearthstone spell (ID `8690`) for the player using `ResetSpellCooldown()`, passing `true` to update the client. +2. Send a message to the player indicating that their Hearthstone cooldown has been reset using `SendBroadcastMessage()`. +3. Remove one instance of the custom item from the player's inventory using `RemoveItem()`. + +This script allows players to instantly use their Hearthstone again by consuming the custom item, bypassing the default 30-minute cooldown. The script can be expanded to include additional functionality, such as checking if the player has the Hearthstone spell learned or adding a custom cooldown to the item itself to prevent abuse. + +## ResetTalents +Resets the player's talents, refunding all spent talent points. + +### Parameters +* noCost (optional): boolean - If set to true, the player will not be charged the cost of resetting their talents. Default value is false. + +### Example Usage +This script allows players to reset their talents by talking to an NPC, but only if they are in a specific zone and meet a minimum level requirement. The script also checks if the player has enough gold to cover the cost of resetting their talents, unless they have a specific item in their inventory. + +```typescript +const RESET_TALENT_ITEM = 1234; // Item ID for a special item that allows players to reset talents for free +const RESET_TALENT_COST = 10000; // Cost in copper to reset talents (10 gold) +const MIN_LEVEL_TO_RESET = 10; // Minimum level required to reset talents +const RESET_TALENT_ZONE = 12; // Zone ID where players are allowed to reset talents + +function OnGossipHello(event: OnGossipEvent, player: Player, object: GameObject) { + if (player.GetZoneId() !== RESET_TALENT_ZONE) { + player.SendBroadcastMessage("You must be in the specified zone to reset your talents."); + return; + } + + if (player.GetLevel() < MIN_LEVEL_TO_RESET) { + player.SendBroadcastMessage(`You must be at least level ${MIN_LEVEL_TO_RESET} to reset your talents.`); + return; + } + + let shouldCharge = true; + if (player.HasItem(RESET_TALENT_ITEM)) { + shouldCharge = false; + player.RemoveItem(RESET_TALENT_ITEM, 1); + player.SendBroadcastMessage("Your special item has been consumed to reset your talents for free."); + } else if (player.GetCoinage() < RESET_TALENT_COST) { + player.SendBroadcastMessage(`You need at least ${RESET_TALENT_COST / 10000} gold to reset your talents.`); + return; + } + + player.ResetTalents(shouldCharge); + player.SendBroadcastMessage("Your talents have been reset."); +} + +RegisterGameObjectEvent(1234, GameObjectEvents.GAMEOBJECT_EVENT_ON_GOSSIP_HELLO, OnGossipHello); +``` + +In this example: +1. The script checks if the player is in the specified zone (`RESET_TALENT_ZONE`) and meets the minimum level requirement (`MIN_LEVEL_TO_RESET`). If not, it sends an appropriate message to the player and exits. +2. If the player has a special item (`RESET_TALENT_ITEM`), the script sets `shouldCharge` to false, consumes the item, and informs the player that their talents have been reset for free. +3. If the player does not have the special item, the script checks if they have enough gold (`RESET_TALENT_COST`) to cover the cost of resetting their talents. If not, it sends a message to the player and exits. +4. Finally, the script calls `ResetTalents(shouldCharge)` to reset the player's talents, either charging them the specified amount or resetting for free based on the `shouldCharge` variable. + +This script provides a more complex example of using the `ResetTalents()` method, incorporating zone checks, level requirements, item consumption, and gold costs. + +## ResetTalentsCost +Returns the total cost in copper for the player to reset their talents. This cost is based on an accumulation of all the times a player has reset their talents in the past. + +### Parameters +None + +### Returns +cost: number - The amount in copper to reset talents + +### Example Usage: +This example listens for when a player talks to an NPC and if they have enough money, they can reset their talents for free. Otherwise, a message is sent telling them they don't have enough money and how much more they need. + +```typescript +const INNKEEPER_ENTRY = 1234; +const onGossipHello: player_event_on_gossip_hello = (event: number, player: Player, object: GameObject) => { + const talentResetCost = player.ResetTalentsCost(); + const playerMoney = player.GetCoinage(); + + if (object.GetEntry() === INNKEEPER_ENTRY) { + if (playerMoney >= talentResetCost) { + player.ResetTalents(true); + player.ModifyMoney(-talentResetCost); + player.SendNotification(`Your talents have been reset for ${GetMoneyString(talentResetCost)}`); + } else { + const neededMoney = talentResetCost - playerMoney; + player.SendNotification(`You don't have enough money to reset your talents. You need ${GetMoneyString(neededMoney)} more.`); + } + player.GossipComplete(); + } +}; + +function GetMoneyString(copper: number): string { + const gold = Math.floor(copper / 10000); + copper -= gold * 10000; + const silver = Math.floor(copper / 100); + copper -= silver * 100; + + return `${gold}g ${silver}s ${copper}c`; +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, (...args) => onGossipHello(...args)); +``` + +In this example, when a player interacts with an NPC with the entry `INNKEEPER_ENTRY`, it will check if the player has enough money to reset their talents. If they do, it will reset their talents, take the money from them, and send them a notification with the cost. If they don't have enough money, it will send a notification telling them how much more money they need. + +The `GetMoneyString` function is a helper function that converts the copper amount to a formatted string with gold, silver, and copper. + +## ResetTypeCooldowns +Resets the cooldown of all spells within the specified category for the player. This can be useful for creating custom buffs, items, or mechanics that allow players to bypass normal spell cooldowns. + +### Parameters +* category: number - The spell category to reset cooldowns for. Spell categories are defined in the SpellCategory.dbc file. +* update: boolean (optional) - If set to true, will send cooldown update packets to the client. Defaults to true if not specified. + +### Example Usage +Example script that resets all cooldowns for a player's Fire spells (category 11) when they kill a creature: +```typescript +const FIRE_SPELL_CATEGORY = 11; + +const onCreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + // Check if the creature killed is a specific entry ID + if (creature.GetEntry() == 12345) { + // Reset cooldowns for Fire spells + player.ResetTypeCooldowns(FIRE_SPELL_CATEGORY); + + // Notify the player + player.SendBroadcastMessage("Your Fire spell cooldowns have been reset!"); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => onCreatureKill(...args)); +``` + +Example script that adds a custom item which resets a player's hearthstone cooldown when used: +```typescript +const HEARTHSTONE_CATEGORY = 94; +const CUSTOM_ITEM_ENTRY = 12345; + +const onItemUse: player_event_on_use_item = (event: number, player: Player, item: Item, gameObject: GameObject, target: Unit) => { + // Check if the used item is our custom item + if (item.GetEntry() == CUSTOM_ITEM_ENTRY) { + // Reset hearthstone cooldown + player.ResetTypeCooldowns(HEARTHSTONE_CATEGORY, false); + + // Remove the item from the player's inventory + player.RemoveItem(item.GetEntry(), 1); + + // Notify the player + player.SendBroadcastMessage("Your hearthstone cooldown has been reset!"); + + // Prevent default item use behavior + return false; + } + + // Allow default item use behavior for other items + return true; +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => onItemUse(...args)); +``` +These examples demonstrate how the ResetTypeCooldowns method can be used in different scenarios to create unique gameplay mechanics or to provide utility to players. By resetting cooldowns for specific spell categories, you can alter the pacing of combat or allow players to use certain abilities more frequently than normally allowed. + diff --git a/docs/classes/Unit.md b/docs/classes/Unit.md index daf7cac..519ccdd 100644 --- a/docs/classes/Unit.md +++ b/docs/classes/Unit.md @@ -40,3 +40,7509 @@ In this script: This script adds an element of surprise and reward for players when they kill creatures, granting them a random beneficial aura from a predefined list. The auras can provide various benefits such as increased stats, damage output, or defensive capabilities, enhancing the player's gameplay experience. +## AddThreat +Adds threat to the [Unit] from the victim. This method allows you to manually adjust the threat level of a unit towards the specified victim. + +### Parameters +- `victim`: [Unit](./unit.md) - The unit that will receive the threat. +- `threat`: number - The amount of threat to add. +- `schoolMask`: [SpellSchoolMask](./spellschoolmask.md) (optional) - The school mask of the threat. +- `spell`: number (optional) - The spell ID associated with the threat. + +### Example Usage +In this example, we'll create a script that increases the threat of a boss towards the main tank when the boss reaches a certain health percentage. + +```typescript +const BOSS_ENTRY = 12345; +const MAIN_TANK_NAME = 'TankPlayer'; +const HEALTH_PERCENTAGE_THRESHOLD = 30; +const ADDITIONAL_THREAT = 5000; + +const BossReachedThreshold: creature_event_on_health_pct = (event: number, creature: Creature, healthPct: number) => { + if (creature.GetEntry() === BOSS_ENTRY && healthPct <= HEALTH_PERCENTAGE_THRESHOLD) { + const mainTank = creature.GetMap().GetPlayers().find(player => player.GetName() === MAIN_TANK_NAME); + + if (mainTank) { + creature.AddThreat(mainTank, ADDITIONAL_THREAT); + creature.SendUnitWhisper(`I will crush you, ${MAIN_TANK_NAME}!`, mainTank.GetGUID()); + creature.PlayDirectSound(1234); // Play a sound effect + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_HEALTH_PCT, (...args) => BossReachedThreshold(...args)); +``` + +In this script: +1. We define constants for the boss entry, main tank name, health percentage threshold, and the additional threat amount. +2. We register a creature event handler for the `CREATURE_EVENT_ON_HEALTH_PCT` event. +3. Inside the event handler, we check if the creature is the desired boss and if its health percentage is below or equal to the specified threshold. +4. If the conditions are met, we search for the main tank player in the creature's map using `GetMap().GetPlayers()` and the main tank's name. +5. If the main tank is found, we add the additional threat to the boss towards the main tank using `AddThreat()`. +6. We send a whisper message to the main tank using `SendUnitWhisper()` to indicate the boss's focus on them. +7. Finally, we play a sound effect using `PlayDirectSound()` to enhance the immersion of the encounter. + +This script demonstrates how you can use the `AddThreat()` method to dynamically adjust the threat of a creature towards a specific player based on certain conditions, such as the boss's health percentage. It also showcases additional features like sending whisper messages and playing sound effects to create a more engaging experience. + +## AddUnitState +This method adds a unit state to the unit. Unit states are used to control the behavior and appearance of units in the game. Some common unit states include: + +- `UNIT_STATE_ROOT`: The unit is rooted in place and cannot move. +- `UNIT_STATE_STUNNED`: The unit is stunned and cannot perform any actions. +- `UNIT_STATE_CONFUSED`: The unit is confused and may attack random targets. +- `UNIT_STATE_FLEEING`: The unit is fleeing from combat. + +For a complete list of unit states, you can refer to the `UnitState` enum in the Azerothcore source code. + +### Parameters +- `state`: number - The unit state to add. You can use the numeric value directly or the corresponding enum value from `UnitState`. + +### Example Usage +Here's an example of how to use `AddUnitState` to create a spell that roots the target in place for a short duration: + +```typescript +const SPELL_ROOT = 12345; + +const SpellScript = { + canCast(player: Player, target: Unit, spell: Spell): boolean { + // Check if the target is already rooted + if (target.HasUnitState(UnitState.UNIT_STATE_ROOT)) { + player.SendBroadcastMessage("Target is already rooted!"); + return false; + } + return true; + }, + + onCast(player: Player, target: Unit, spell: Spell): void { + // Add the UNIT_STATE_ROOT to the target + target.AddUnitState(UnitState.UNIT_STATE_ROOT); + + // Send a message to the player + player.SendBroadcastMessage(`${target.GetName()} has been rooted for 5 seconds!`); + + // Remove the UNIT_STATE_ROOT after 5 seconds + target.RegisterEvent((): void => { + target.ClearUnitState(UnitState.UNIT_STATE_ROOT); + player.SendBroadcastMessage(`${target.GetName()} is no longer rooted!`); + }, 5000, 1); + }, +}; + +RegisterSpellScript(SPELL_ROOT, SpellScript); +``` + +In this example, we define a spell script for a custom spell with the ID `12345`. The `canCast` function checks if the target already has the `UNIT_STATE_ROOT` state, and prevents the spell from being cast if it does. + +If the spell is successfully cast, the `onCast` function adds the `UNIT_STATE_ROOT` state to the target using `AddUnitState`. It also sends a message to the player indicating that the target has been rooted. + +Finally, we use `RegisterEvent` to remove the `UNIT_STATE_ROOT` state from the target after 5 seconds (5000 milliseconds) and send another message to the player. + +This is just one example of how `AddUnitState` can be used to create interesting gameplay mechanics. You can experiment with different unit states and combinations to create a wide variety of effects and abilities. + +## Attack +The `Attack` method causes the `Unit` to attack a specified target. If `meleeAttack` is set to `true`, the `Unit` will perform a melee attack; otherwise, it will use its default attack type (e.g., ranged for hunters). + +### Parameters +- `who`: [Unit](./unit.md) - The target `Unit` to attack. +- `meleeAttack` (optional): boolean - Determines whether the attack should be a melee attack. Default is `false`. + +### Returns +- `void` + +### Example Usage +In this example, we create a script that causes a creature to attack a random player within a certain range every 5 seconds. + +```typescript +const CREATURE_ENTRY = 1234; +const ATTACK_RANGE = 10; +const ATTACK_INTERVAL = 5000; + +const CreatureAttack: creature_event_on_update = (event: number, creature: Creature, diff: number) => { + if (creature.GetEntry() !== CREATURE_ENTRY) { + return; + } + + if (creature.IsInCombat()) { + return; + } + + if (event % ATTACK_INTERVAL !== 0) { + return; + } + + const nearbyPlayers = creature.GetPlayersInRange(ATTACK_RANGE); + if (nearbyPlayers.length === 0) { + return; + } + + const randomIndex = Math.floor(Math.random() * nearbyPlayers.length); + const target = nearbyPlayers[randomIndex]; + + creature.Attack(target); + creature.SendUnitYell("You dare enter my domain? Feel my wrath!", 0); +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => CreatureAttack(...args)); +``` + +In this script: + +1. We define constants for the creature entry, attack range, and attack interval (in milliseconds). +2. In the `CreatureAttack` function, we first check if the creature matches the desired entry. If not, we return early. +3. We then check if the creature is already in combat. If so, we return early to avoid interrupting the ongoing combat. +4. We use the modulo operator (`%`) to check if the current event tick matches the attack interval. This ensures that the attack logic is executed every `ATTACK_INTERVAL` milliseconds. +5. We use the `GetPlayersInRange` method to retrieve an array of nearby players within the specified `ATTACK_RANGE`. +6. If there are no nearby players, we return early. +7. We generate a random index using `Math.random()` and select a random player from the `nearbyPlayers` array. +8. Finally, we use the `Attack` method to make the creature attack the selected target and send a taunting yell message. + +This script showcases how the `Attack` method can be used in combination with other methods and game events to create dynamic combat behavior for creatures. + +## AttackStop +The `AttackStop` method will cause the [Unit](./unit.md) to stop attacking its current target if it is attacking one. This can be useful if you want to force a creature to stop attacking a player or another unit under certain conditions, such as if the target is too far away or if the creature's health is too low. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the unit successfully stopped attacking, or `false` if the unit was not attacking anything. + +### Example Usage +In this example, we will create an AI script for a creature that will cause it to stop attacking its target if the target is too far away or if the creature's health is too low. + +```typescript +const CREATURE_ENTRY = 1234; +const MAX_DISTANCE = 30; +const LOW_HEALTH_THRESHOLD = 20; + +const AIUpdate: creature_event_on_ai_update = (event: number, creature: Creature, diff: number) => { + const target = creature.GetVictim(); + + if (target) { + const distance = creature.GetDistance(target); + const healthPct = creature.GetHealthPct(); + + if (distance > MAX_DISTANCE || healthPct < LOW_HEALTH_THRESHOLD) { + const success = creature.AttackStop(); + + if (success) { + creature.MonsterSay("I will not chase you any further!", 0); + } else { + console.log(`[Error] Failed to stop attacking for creature with entry ${CREATURE_ENTRY}`); + } + } + } +} + +RegisterCreatureEvent(CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_AI_UPDATE, (...args) => AIUpdate(...args)); +``` + +In this script, we define some constants for the creature entry, maximum distance, and low health threshold. Then we register an AI update event for the creature. + +When the event is triggered, we first check if the creature has a current target using `GetVictim()`. If it does, we calculate the distance between the creature and its target using `GetDistance()`, and we get the creature's current health percentage using `GetHealthPct()`. + +If the distance is greater than our defined maximum distance or if the creature's health is below our defined low health threshold, we call `AttackStop()` to make the creature stop attacking. If `AttackStop()` returns `true`, we know it was successful, so we make the creature say a message using `MonsterSay()`. If it returns `false`, we log an error message to the console. + +This is just one example of how you could use `AttackStop()` in a script. You could also use it in other situations, such as if you want a creature to stop attacking when a certain game event occurs, or if you want a creature to switch targets under certain conditions. + +## CastCustomSpell + +This method allows a unit to cast a custom spell on a target unit with optional parameters such as base points, triggered flag, cast item, and original caster. + +### Parameters +- target: [Unit](./unit.md) - The target unit to cast the spell on. +- spell: number - The ID of the spell to be cast. Refer to the Spell.dbc file for spell IDs. +- triggered?: boolean - (Optional) Determines if the spell should be cast as triggered or not. Default is false. +- bp0?: number - (Optional) Base points for effect 0 of the spell. +- bp1?: number - (Optional) Base points for effect 1 of the spell. +- bp2?: number - (Optional) Base points for effect 2 of the spell. +- castItem?: [Item](./item.md) - (Optional) The item used to cast the spell, if any. +- originalCaster?: number - (Optional) The original caster's GUID, used for spell reflection. + +### Example Usage + +Here's an example of how to use `CastCustomSpell` to create a scripted spell that deals damage based on the caster's attack power: + +```typescript +const CUSTOM_SPELL_ID = 12345; +const SPELL_COEFFICIENT = 1.5; + +const ApplyCustomSpell: player_event_on_cast_spell = (event, player, spell, skipCheck) => { + if (spell.GetEntry() === CUSTOM_SPELL_ID) { + const target = spell.GetTarget(); + if (target && target.IsUnit()) { + const attackPower = player.GetTotalAttackPowerValue(WeaponAttackType.BASE_ATTACK); + const damage = Math.floor(attackPower * SPELL_COEFFICIENT); + + player.CastCustomSpell(target, CUSTOM_SPELL_ID, true, damage, 0, 0); + + const damageInfo = { + attacker: player, + victim: target, + damage: damage, + damageType: SPELL_DIRECT_DAMAGE, + procAttacker: PROC_FLAG_NONE, + procVictim: PROC_FLAG_NONE, + procEx: PROC_EX_NORMAL_HIT, + hitInfo: SPELL_HIT_TYPE_UNK1, + }; + + target.DealDamage(player, damage, damageInfo); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CAST_SPELL, ApplyCustomSpell); +``` + +In this example: +1. We define a custom spell ID and a spell coefficient for damage calculation. +2. In the `ApplyCustomSpell` event handler, we check if the cast spell matches our custom spell ID. +3. If the target is a valid unit, we calculate the damage based on the player's attack power and the spell coefficient. +4. We use `CastCustomSpell` to apply the custom spell effect on the target, passing the calculated damage as the first base point (bp0). +5. We create a `damageInfo` object to store information about the damage dealt. +6. Finally, we use `DealDamage` to apply the damage to the target unit. + +This script demonstrates how to use `CastCustomSpell` along with other methods like `GetTotalAttackPowerValue` and `DealDamage` to create a custom spell that interacts with the game's mechanics. + +## CastSpell +Makes the [Unit] cast a spell on the specified target. + +### Parameters +- target: [Unit](./unit.md) - The target unit to cast the spell on. +- spell: number - The ID of the spell to be cast. Spell IDs can be found in the `spell_template` table in the world database. +- triggered: boolean (optional) - If set to true, the spell will be cast instantly without any cast time or mana cost. Default is false. + +### Example Usage +Here's an example of how to use the `CastSpell` method in a script that makes a unit cast a spell on a player when the player enters combat with the unit: + +```typescript +const SPELL_FIREBALL = 133; + +const onPlayerEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + // Check if the enemy is a specific creature entry + if (enemy.IsCreature() && enemy.ToCreature().GetEntry() === 1234) { + // Cast the Fireball spell on the player + enemy.CastSpell(player, SPELL_FIREBALL); + + // You can also specify the triggered parameter to make the spell instant + // enemy.CastSpell(player, SPELL_FIREBALL, true); + + // Send a message to the player + player.SendBroadcastMessage("The enemy casts Fireball on you!"); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onPlayerEnterCombat(...args)); +``` + +In this example: +1. We define a constant `SPELL_FIREBALL` with the ID of the Fireball spell (133). +2. We register a player event handler for the `PLAYER_EVENT_ON_ENTER_COMBAT` event using `RegisterPlayerEvent`. +3. Inside the event handler, we check if the enemy unit is a creature with a specific entry ID (1234). +4. If the condition is met, we use the `CastSpell` method to make the enemy unit cast the Fireball spell on the player. +5. We can optionally specify the `triggered` parameter as `true` to make the spell cast instantly without any cast time or mana cost. +6. Finally, we send a broadcast message to the player using `SendBroadcastMessage` to inform them that the enemy has cast Fireball on them. + +This example demonstrates how you can use the `CastSpell` method to make a unit cast a spell on a player based on certain conditions, such as when the player enters combat with a specific creature. You can customize the spell ID, creature entry, and add additional logic to suit your specific needs. + +## CastSpellAoF +Makes the [Unit] cast the spell to the given coordinates, used for area effect spells. This method is useful for casting spells on a specific location rather than on a target unit. + +### Parameters +* x: number - The X coordinate of the target location +* y: number - The Y coordinate of the target location +* z: number - The Z coordinate of the target location +* spell: number - The ID of the spell to be cast +* triggered?: boolean - Optional parameter to specify if the spell should be triggered instantly or cast as a normal spell (default: false) + +### Example Usage +In this example, we'll create a script that casts a random AOE spell on a random player's location every 30 seconds. + +```typescript +const AOE_SPELLS = [48360, 48363, 48365, 48367, 48368, 48371, 48372, 48374, 48375, 48377]; +const SPELL_INTERVAL = 30000; // 30 seconds + +let timerID: number | null = null; + +function CastRandomAOESpell() { + const players = GetPlayersInWorld(); + if (players.length === 0) { + return; + } + + const randomPlayer = players[Math.floor(Math.random() * players.length)]; + const randomSpell = AOE_SPELLS[Math.floor(Math.random() * AOE_SPELLS.length)]; + + const x = randomPlayer.GetX(); + const y = randomPlayer.GetY(); + const z = randomPlayer.GetZ(); + + randomPlayer.CastSpellAoF(x, y, z, randomSpell); +} + +function StartAOESpellTimer() { + timerID = CreateTimer(SPELL_INTERVAL, () => { + CastRandomAOESpell(); + StartAOESpellTimer(); + }); +} + +function StopAOESpellTimer() { + if (timerID !== null) { + DestroyTimer(timerID); + timerID = null; + } +} + +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_STARTUP, StartAOESpellTimer); +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_SHUTDOWN, StopAOESpellTimer); +``` + +In this script: +1. We define an array of AOE spell IDs (`AOE_SPELLS`) and the interval between each spell cast (`SPELL_INTERVAL`). +2. The `CastRandomAOESpell` function selects a random player from the world and a random AOE spell from the `AOE_SPELLS` array. +3. It then retrieves the player's coordinates (x, y, z) and uses the `CastSpellAoF` method to cast the random AOE spell at the player's location. +4. The `StartAOESpellTimer` function creates a timer that calls `CastRandomAOESpell` every `SPELL_INTERVAL` milliseconds. +5. The `StopAOESpellTimer` function destroys the timer when the server shuts down. +6. We register the `StartAOESpellTimer` function to be called on server startup and the `StopAOESpellTimer` function to be called on server shutdown. + +This script demonstrates how to use the `CastSpellAoF` method to cast AOE spells at specific coordinates, creating a dynamic event that affects random players in the world. + +## ClearInCombat +This method clears the unit's combat state, effectively removing the unit from combat. + +### Parameters +None + +### Returns +None + +### Example Usage +In this example, we'll create a script that allows a player to use a special item to instantly clear their combat state and reset their health and mana to full. + +```typescript +const ITEM_COMBAT_RESET = 12345; // Replace with the actual item entry ID + +const OnUseItem: player_event_on_use_item = (event: number, player: Player, item: Item, target: WorldObject): void => { + if (item.GetEntry() === ITEM_COMBAT_RESET) { + if (player.IsInCombat()) { + player.ClearInCombat(); + player.SetHealth(player.GetMaxHealth()); + player.SetPower(player.GetPowerType(), player.GetMaxPower(player.GetPowerType())); + + player.SendBroadcastMessage("You have used the Combat Reset item. Your combat state has been cleared, and your health and mana have been restored!"); + } else { + player.SendBroadcastMessage("You are not in combat. The Combat Reset item has no effect."); + } + + player.DestroyItemCount(ITEM_COMBAT_RESET, 1, true); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => OnUseItem(...args)); +``` + +In this script: +1. We define a constant `ITEM_COMBAT_RESET` to store the entry ID of the special item that players can use to reset their combat state. +2. We register the `OnUseItem` event to listen for when a player uses an item. +3. When the event is triggered, we check if the used item's entry ID matches the `ITEM_COMBAT_RESET` entry ID. +4. If the player is in combat, we call the `ClearInCombat()` method to remove the player from combat. +5. We then set the player's health and mana/energy to their maximum values using `SetHealth()` and `SetPower()` methods. +6. We send a broadcast message to the player informing them that their combat state has been cleared and their health and mana have been restored. +7. If the player is not in combat, we send a message informing them that the item has no effect since they are not in combat. +8. Finally, we destroy one instance of the `ITEM_COMBAT_RESET` item from the player's inventory using the `DestroyItemCount()` method. + +This script demonstrates how the `ClearInCombat()` method can be used in conjunction with other methods and events to create a unique gameplay mechanic, allowing players to instantly reset their combat state and restore their health and mana using a special item. + +## ClearThreatList +This method clears the threat list of the unit, effectively resetting all threat levels of the unit's enemies to zero. This can be useful in certain situations where you want to manipulate the threat mechanics of the game. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any value. + +### Example Usage +Here's an example of how you can use the `ClearThreatList` method in a script that reduces the threat level of a boss when it reaches a certain health threshold: + +```typescript +const BOSS_ENTRY = 12345; +const THREAT_REDUCTION_THRESHOLD = 30; + +const OnDamageTaken: creature_event_on_damage_taken = (event: number, creature: Creature, attacker: Unit, damage: number) => { + if (creature.GetEntry() === BOSS_ENTRY) { + const healthPercent = creature.GetHealthPct(); + + if (healthPercent <= THREAT_REDUCTION_THRESHOLD) { + creature.ClearThreatList(); + creature.SendUnitYell("My focus is weakened! You have a chance to strike now!", 0); + + // Apply a temporary damage buff to the raid + const players = creature.GetPlayersInRange(50); + for (const player of players) { + player.AddAura(1234, player); // Assumes aura 1234 is a damage buff + } + + // Start a timer to restore the boss's threat after a certain duration + creature.RegisterEvent( + () => { + creature.RemoveEvents(); + creature.SendUnitYell("My strength returns! Cower before me!", 0); + + // Remove the temporary damage buff from the raid + const players = creature.GetPlayersInRange(50); + for (const player of players) { + player.RemoveAura(1234); + } + }, + 10000 // Restore threat after 10 seconds + ); + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_DAMAGE_TAKEN, (...args) => OnDamageTaken(...args)); +``` + +In this example: +1. We define constants for the boss's entry ID and the health threshold at which the threat reduction should occur. +2. Inside the `OnDamageTaken` event handler, we check if the damaged creature is the boss we're interested in. +3. If the boss's health drops below the specified threshold, we clear its threat list using `ClearThreatList()`. +4. We make the boss yell a message indicating that its focus is weakened, giving players a chance to strike. +5. We apply a temporary damage buff to all players within a 50-yard range of the boss. +6. We start a timer using `RegisterEvent` to restore the boss's threat after a certain duration (in this case, 10 seconds). +7. Inside the timer callback, we remove the registered event, make the boss yell another message, and remove the temporary damage buff from the players. + +This script demonstrates how clearing the threat list can create an interesting gameplay mechanic where players have a window of opportunity to deal increased damage to the boss while its threat is temporarily reduced. + +## ClearUnitState +Removes a specific unit state from the [Unit]. Unit states are used to control certain behaviors or conditions of a unit, such as whether they are stunned, rooted, or disarmed. By clearing a unit state, you can remove these effects from the unit. + +### Parameters +* state: number - The unit state to remove. Refer to the UnitState enum for possible values. + +### Example Usage +In this example, we'll create a script that removes the stunned and rooted states from a player's target when they use a specific item. + +```typescript +const CLEANSING_TOTEM_ITEM_ENTRY = 12345; +const UNIT_STATE_STUNNED = 0x00000040; +const UNIT_STATE_ROOTED = 0x00000100; + +const OnUseItem: player_event_on_use_item = (event: number, player: Player, item: Item, target: Unit) => { + if (item.GetEntry() === CLEANSING_TOTEM_ITEM_ENTRY) { + const targetUnit = player.GetSelection(); + if (targetUnit) { + // Check if the target unit is stunned or rooted + if (targetUnit.HasUnitState(UNIT_STATE_STUNNED) || targetUnit.HasUnitState(UNIT_STATE_ROOTED)) { + // Remove the stunned and rooted states from the target + targetUnit.ClearUnitState(UNIT_STATE_STUNNED); + targetUnit.ClearUnitState(UNIT_STATE_ROOTED); + + // Send a message to the player indicating the states have been removed + player.SendBroadcastMessage(`You have cleansed the stunned and rooted effects from ${targetUnit.GetName()}!`); + } else { + // Send a message to the player if the target is not stunned or rooted + player.SendBroadcastMessage(`${targetUnit.GetName()} is not currently stunned or rooted.`); + } + } else { + // Send a message to the player if they don't have a target selected + player.SendBroadcastMessage("You must select a target to use this item."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => OnUseItem(...args)); +``` + +In this script: +1. We define constants for the item entry and the unit states we want to remove (stunned and rooted). +2. When a player uses an item, we check if the item used matches the specified entry (CLEANSING_TOTEM_ITEM_ENTRY). +3. If the item matches, we get the player's current target using `player.GetSelection()`. +4. We check if the target unit exists and if it has the stunned or rooted unit states using `targetUnit.HasUnitState()`. +5. If the target is stunned or rooted, we remove those states using `targetUnit.ClearUnitState()` for each state. +6. We send a message to the player indicating that the states have been removed from the target. +7. If the target is not stunned or rooted, or if the player doesn't have a target selected, we send appropriate messages to the player. + +This script demonstrates how to use the `ClearUnitState()` method to remove specific unit states from a target unit when a player uses a designated item. It also showcases error handling by checking if the player has a valid target and if the target has the desired unit states before attempting to remove them. + +## CountPctFromCurHealth +Returns the percentage of the unit's current health in relation to their maximum health. + +### Parameters +None + +### Returns +pct: number - The percentage of the unit's current health. + +### Example Usage: +Buff the player with a special ability when dropping below 20% health. + +```typescript +const SPECIAL_ABILITY_AURA = 12345; +const HEALTH_THRESHOLD = 20; + +const CheckPlayerHealth: player_event_on_update = (event: number, player: Player, diff: number) => { + const healthPct = player.CountPctFromCurHealth(); + + if (healthPct <= HEALTH_THRESHOLD) { + if (!player.HasAura(SPECIAL_ABILITY_AURA)) { + player.AddAura(SPECIAL_ABILITY_AURA, player); + player.SendBroadcastMessage("You feel a surge of power as your health drops low!"); + } + } else { + if (player.HasAura(SPECIAL_ABILITY_AURA)) { + player.RemoveAura(SPECIAL_ABILITY_AURA); + player.SendBroadcastMessage("The special ability fades as your health recovers."); + } + } +} + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => CheckPlayerHealth(...args), 1000); +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example, we register a player update event that checks the player's health percentage every second (1000 ms). When the player's health drops below the defined `HEALTH_THRESHOLD` (20% in this case), we apply a special ability aura to the player and send them a message. If the player's health recovers above the threshold, we remove the aura and send another message. + +The `OnLogin` event is used to register the `CheckPlayerHealth` function to the `PLAYER_EVENT_ON_UPDATE` event when the player logs in, ensuring that the health monitoring starts as soon as the player enters the game. + +This script demonstrates how the `CountPctFromCurHealth` method can be used in combination with other methods and events to create dynamic gameplay experiences based on the player's current health status. + +## CountPctFromMaxHealth +This method returns the percentage of the [Unit]'s current health in relation to their maximum health. + +### Parameters +This method does not take any parameters. + +### Returns +number - The percentage of the [Unit]'s current health. + +### Example Usage +In this example, we will create a script that will display a warning message to the [Player] when their health drops below 50% of their maximum health. + +```typescript +const HEALTH_WARNING_THRESHOLD = 50; + +const HealthCheck: player_event_on_update = (event: number, player: Player, diff: number) => { + const healthPct = player.CountPctFromMaxHealth(); + + if (healthPct <= HEALTH_WARNING_THRESHOLD) { + const healthPctRounded = Math.round(healthPct); + const maxHealth = player.GetMaxHealth(); + const currentHealth = player.GetHealth(); + + player.SendBroadcastMessage(`WARNING: Your health is at ${healthPctRounded}%!`); + player.SendBroadcastMessage(`You have ${currentHealth} / ${maxHealth} health remaining.`); + + if (healthPct <= 20) { + player.SendBroadcastMessage("CRITICAL: Your health is critically low! Seek healing immediately!"); + } else if (healthPct <= 35) { + player.SendBroadcastMessage("DANGER: Your health is dangerously low! Be cautious and consider healing."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => HealthCheck(...args)); +``` + +In this script: +1. We define a constant `HEALTH_WARNING_THRESHOLD` to set the percentage threshold at which we want to start displaying warning messages to the player. +2. We create a function `HealthCheck` that will be triggered on the `PLAYER_EVENT_ON_UPDATE` event. +3. Inside the function, we call `player.CountPctFromMaxHealth()` to get the current health percentage of the player. +4. We check if the health percentage is less than or equal to the warning threshold. +5. If the condition is met, we perform the following actions: + - Round the health percentage to the nearest integer using `Math.round()`. + - Get the player's maximum health using `player.GetMaxHealth()`. + - Get the player's current health using `player.GetHealth()`. + - Send a broadcast message to the player indicating their current health percentage. + - Send another broadcast message showing the player's current health and maximum health. + - If the health percentage is critically low (20% or below), send an additional critical warning message. + - If the health percentage is dangerously low (35% or below), send an additional danger warning message. +6. Finally, we register the `HealthCheck` function to be triggered on the `PLAYER_EVENT_ON_UPDATE` event using `RegisterPlayerEvent()`. + +This script provides a more comprehensive example of using the `CountPctFromMaxHealth()` method to monitor the player's health and provide appropriate warnings based on different health percentage thresholds. + +## DeMorph +The `DeMorph` method is used to revert a [Unit](./unit.md)'s display ID back to its original native display ID, effectively removing any active morphs on the unit. + +When a unit is morphed, its display ID is changed to a different creature or object display ID. This method allows you to remove the morph effect and restore the unit's original appearance. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any value. + +### Example Usage +In this example, we'll create a script that morphs a player into a random creature when they enter combat, and then reverts the morph when the combat ends. + +```typescript +const morphEntries = [1234, 5678, 9012, 3456, 7890]; // Array of creature entry IDs for morphing + +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + const randomMorphEntry = morphEntries[Math.floor(Math.random() * morphEntries.length)]; + player.SetDisplayId(randomMorphEntry); +} + +const onLeaveCombat: player_event_on_leave_combat = (event: number, player: Player): void => { + player.DeMorph(); +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEAVE_COMBAT, (...args) => onLeaveCombat(...args)); +``` + +In this script: +1. We define an array called `morphEntries` that contains a list of creature entry IDs that we want to use for morphing the player. +2. We register a `PLAYER_EVENT_ON_ENTER_COMBAT` event handler using `RegisterPlayerEvent`. When the player enters combat, the `onEnterCombat` function is called. +3. Inside the `onEnterCombat` function, we select a random creature entry ID from the `morphEntries` array using `Math.random()` and store it in the `randomMorphEntry` variable. +4. We use the `SetDisplayId` method of the player object to morph the player into the randomly selected creature display ID. +5. We also register a `PLAYER_EVENT_ON_LEAVE_COMBAT` event handler using `RegisterPlayerEvent`. When the player leaves combat, the `onLeaveCombat` function is called. +6. Inside the `onLeaveCombat` function, we use the `DeMorph` method of the player object to revert the player's display ID back to their original appearance. + +With this script, whenever the player enters combat, they will be morphed into a random creature from the `morphEntries` array. When the combat ends, the player will be demorphed and restored to their original appearance. + +Note: Make sure to replace the placeholder entry IDs in the `morphEntries` array with valid creature entry IDs from your AzerothCore database. + +## DealDamage +Makes the [Unit] damage the target [Unit] based on the provided parameters. This method can be used to simulate any type of damage done to a unit, whether it's environmental, spell based, or melee damage. + +### Parameters +* target: [Unit](./unit.md) - The Unit that will be damaged +* damage: number - The amount of damage to deal +* durabilityloss?: boolean - If set to 'true', the damage will cause durability loss. Default is 'false' +* school?: SpellSchools - The school of the damage. Default is SPELL_SCHOOL_NORMAL +* spell?: number - The spell ID if the damage was caused by a spell + +### Example Usage: +Example of an NPC dealing shadow damage to a player on each successful melee attack with a chance to proc an additional shadow damage spell. +```typescript +const SHADOW_DAMAGE_SPELL_ID = 31618; +const SHADOW_DAMAGE_CHANCE = 25; + +const OnMeleeAttack: creature_event_on_hit_by_spell = (event: CreatureEvents, creature: Creature, attacker: Unit, spellId: number, schoolMask: number, typeMask: number, amount: number, isPeriodic: boolean) => { + if (attacker && attacker.IsPlayer()) { + const player = attacker.ToPlayer(); + if (player) { + creature.DealDamage(player, amount, false, SpellSchools.SPELL_SCHOOL_NORMAL); + + if (RandomChance(SHADOW_DAMAGE_CHANCE)) { + const shadowDamage = amount * 0.5; + creature.DealDamage(player, shadowDamage, false, SpellSchools.SPELL_SCHOOL_SHADOW, SHADOW_DAMAGE_SPELL_ID); + creature.SendUnitWhisper("Embrace the shadow!", 0, player); + } + } + } +}; + +RegisterCreatureEvent(CREATURE_EVENT_ON_HIT_BY_SPELL, (...args) => OnMeleeAttack(...args)); +``` + +In this example, whenever a player deals melee damage to the creature, the creature will retaliate with the same amount of normal damage. Additionally, there is a 25% chance that the creature will deal bonus shadow damage equal to 50% of the melee damage dealt, simulating a shadow damage proc effect. The `SendUnitWhisper` method is used to send a taunting message to the player when the proc occurs. + +## DealHeal +Makes the [Unit] heal the target [Unit] with the given spell. + +### Parameters +* target: [Unit](./unit.md) - The target Unit to be healed +* spell: number - The spell ID used to heal the target +* amount: number - The amount of healing to be dealt +* critical: boolean (optional) - Whether the heal should be a critical heal or not + +### Example Usage +This example script listens for the `UNIT_EVENT_ON_HEAL_TAKEN` event and modifies the healing amount based on certain conditions. + +```typescript +const onHealTaken: unit_event_on_heal_taken = (event: number, healer: Unit, healTarget: Unit, spell: number, amount: number): void => { + const SPELL_REJUVENATION = 774; + const SPELL_REGROWTH = 8936; + const DRUID_CLASS_MASK = 1024; + + // Check if the healer is a Druid + if (healer.GetClass() & DRUID_CLASS_MASK) { + // Increase healing done by Rejuvenation and Regrowth by 10% + if (spell === SPELL_REJUVENATION || spell === SPELL_REGROWTH) { + amount *= 1.1; + } + + // Apply the modified healing amount + healer.DealHeal(healTarget, spell, amount); + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_HEAL_TAKEN, (...args) => onHealTaken(...args)); +``` + +In this example: +1. We define the `onHealTaken` function to handle the `UNIT_EVENT_ON_HEAL_TAKEN` event. +2. Inside the function, we define constants for the Rejuvenation and Regrowth spell IDs and the Druid class mask. +3. We check if the healer's class matches the Druid class mask using the `GetClass()` method. +4. If the healer is a Druid and the spell used is either Rejuvenation or Regrowth, we increase the healing amount by 10%. +5. Finally, we call the `DealHeal()` method on the healer, passing the modified healing amount to apply the heal to the target. +6. We register the `onHealTaken` function to be triggered whenever the `UNIT_EVENT_ON_HEAL_TAKEN` event occurs using `RegisterUnitEvent()`. + +This script demonstrates how to intercept the healing event and modify the healing amount based on specific conditions, such as the healer's class and the spell used. It allows for customization of healing effects in the game. + +## Dismount +This method will dismount the [Unit](./unit.md) if it is mounted. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return anything. + +### Example Usage +Dismount the player when they enter a specific area. +```typescript +const AREA_ID_STORMWIND_KEEP = 1519; + +const onAreaTrigger: player_event_on_area_trigger = (event: number, player: Player, areaId: number): void => { + if (areaId === AREA_ID_STORMWIND_KEEP) { + // Check if the player is mounted + if (player.IsMounted()) { + // Dismount the player + player.Dismount(); + + // Send a message to the player + player.SendBroadcastMessage("You have been dismounted upon entering Stormwind Keep."); + + // Play a sound to the player + player.PlayDirectSound(1906); // Sound ID for "No" + + // Add a cooldown to prevent the player from mounting again for 10 seconds + player.AddAura(SPELL_AURA_MOUNTED, player, 10); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER, (...args) => onAreaTrigger(...args)); +``` +In this example: +1. We define a constant `AREA_ID_STORMWIND_KEEP` with the area ID of Stormwind Keep. +2. We register a player event handler for the `PLAYER_EVENT_ON_AREA_TRIGGER` event. +3. Inside the event handler, we check if the triggered area ID matches `AREA_ID_STORMWIND_KEEP`. +4. If the player is in Stormwind Keep, we check if the player is currently mounted using the `IsMounted()` method. +5. If the player is mounted, we call the `Dismount()` method to dismount the player. +6. We send a broadcast message to the player informing them that they have been dismounted. +7. We play a sound effect to the player using the `PlayDirectSound()` method with the sound ID for "No". +8. Finally, we add an aura to the player using the `AddAura()` method with the `SPELL_AURA_MOUNTED` spell ID and a duration of 10 seconds. This prevents the player from mounting again for a short period after being dismounted. + +This script ensures that players are dismounted when entering Stormwind Keep, providing a immersive experience and preventing any potential exploits or unintended behavior. + +## EmoteState +Makes the [Unit] perform the given emote continuously. This emote will be performed by the unit until it is instructed to stop or perform another emote. + +### Parameters +* emoteId: number - The ID of the emote to perform. You can find a list of emote IDs in the [Emotes.dbc](https://github.com/wowdev/WoWDBDefs/blob/master/definitions/Emotes.dbd). + +### Example Usage +This example demonstrates how to make a creature perform a continuous emote when a player interacts with it, and stop the emote after a certain duration. + +```typescript +const CREATURE_ENTRY = 1234; +const EMOTE_DANCE = 10; +const EMOTE_DURATION = 5000; // 5 seconds + +const onGossipHello: creature_event_on_gossip_hello = (event: number, player: Player, creature: Creature) => { + creature.EmoteState(EMOTE_DANCE); + + // Create a timed event to stop the emote after the specified duration + RegisterTimedEvent("StopEmote", EMOTE_DURATION, 1, () => { + creature.EmoteState(0); // Stop the emote by passing 0 as the emoteId + }); + + player.GossipMenuAddItem(0, "Hello, dancing creature!", 0, 1); + player.GossipSendMenu(1, creature, MenuId); +}; + +const onGossipSelect: creature_event_on_gossip_select = (event: number, player: Player, creature: Creature, sender: number, action: number) => { + if (sender === 0 && action === 1) { + player.GossipComplete(); + creature.Say("Thanks for watching my dance!", 0); + } +}; + +RegisterCreatureEvent(CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, onGossipHello); +RegisterCreatureEvent(CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_SELECT, onGossipSelect); +``` + +In this example: +1. When a player interacts with the creature (opens the gossip menu), the `onGossipHello` event is triggered. +2. The creature starts performing the dance emote continuously using `creature.EmoteState(EMOTE_DANCE)`. +3. A timed event is registered to stop the emote after the specified duration (`EMOTE_DURATION`) using `RegisterTimedEvent`. The event is given a unique name ("StopEmote") and will execute once after the specified delay. +4. The gossip menu is populated with a single option using `player.GossipMenuAddItem` and sent to the player using `player.GossipSendMenu`. +5. When the player selects the gossip option, the `onGossipSelect` event is triggered. +6. If the selected option matches the expected sender and action values, the gossip menu is closed using `player.GossipComplete`, and the creature says a message using `creature.Say`. + +This example showcases how to make a creature perform a continuous emote, stop the emote after a certain duration using a timed event, and interact with the player through the gossip system. + +## GetAura +Returns the [Aura](./aura.md) object of the specified spell ID on the [Unit](./unit.md). If the unit does not have the aura, the method will return `nil`. + +### Parameters +* spellID: number - The ID of the spell to retrieve the aura for. + +### Returns +* [Aura](./aura.md) or `nil` - The Aura object of the specified spell ID on the unit, or `nil` if the unit does not have the aura. + +### Example Usage +In this example, we'll create a script that checks if a player has the "Blessing of Might" aura when they enter combat. If the player doesn't have the aura, we'll cast it on them. + +```typescript +const BLESSING_OF_MIGHT_SPELL_ID = 19740; + +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + const blessingOfMight = player.GetAura(BLESSING_OF_MIGHT_SPELL_ID); + + if (!blessingOfMight) { + // Find a nearby paladin to cast Blessing of Might on the player + const nearbyPaladins = player.GetPlayersInRange(20, 2); // 2 is the faction mask for friendly players + + for (const paladin of nearbyPaladins) { + if (paladin.GetClass() === Classes.CLASS_PALADIN) { + paladin.CastSpell(player, BLESSING_OF_MIGHT_SPELL_ID, true); + player.SendBroadcastMessage(`${paladin.GetName()} has blessed you with Blessing of Might!`); + break; + } + } + + if (!player.GetAura(BLESSING_OF_MIGHT_SPELL_ID)) { + player.SendBroadcastMessage("No nearby paladins found to bless you with Blessing of Might."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script: +1. We define the spell ID for "Blessing of Might" as a constant. +2. When a player enters combat, we use the `GetAura()` method to check if the player has the "Blessing of Might" aura. +3. If the player doesn't have the aura, we search for nearby friendly paladins within 20 yards using `GetPlayersInRange()`. +4. We iterate through the nearby paladins and check if any of them are of the paladin class using `GetClass()`. +5. If a paladin is found, we cast "Blessing of Might" on the player using `CastSpell()` and send a broadcast message to the player informing them of the blessing. +6. If no nearby paladins are found, we send a broadcast message to the player informing them that no paladins were found to bless them. + +This example demonstrates how to use the `GetAura()` method to check for a specific aura on a unit and how to interact with other units (players) based on the presence or absence of that aura. + +## GetBaseSpellPower +Returns the base spell power of the unit for a given spell school. + +### Parameters +* spellSchool: number - The spell school to retrieve the base spell power for. The available spell schools are: + * 0: Normal + * 1: Holy + * 2: Fire + * 3: Nature + * 4: Frost + * 5: Shadow + * 6: Arcane + +### Returns +* number - The base spell power of the unit for the specified spell school. + +### Example Usage +```typescript +const SCHOOL_FIRE = 2; +const SCHOOL_FROST = 4; + +const onDamage: unit_event_on_damage = (event: number, unit: Unit, attacker: Unit, damage: number, spellId: number, schoolMask: number): void => { + const fireSpellPower = unit.GetBaseSpellPower(SCHOOL_FIRE); + const frostSpellPower = unit.GetBaseSpellPower(SCHOOL_FROST); + + let damageModifier = 1; + + if (schoolMask & SCHOOL_FIRE) { + damageModifier += fireSpellPower / 1000; + } + + if (schoolMask & SCHOOL_FROST) { + damageModifier += frostSpellPower / 1000; + } + + const modifiedDamage = damage * damageModifier; + + unit.DealDamage(attacker, modifiedDamage, false, spellId, schoolMask); + + if (unit.GetHealthPct() <= 20) { + const healAmount = (fireSpellPower + frostSpellPower) * 0.1; + unit.SetHealth(unit.GetHealth() + healAmount); + unit.SendChatMessage(ChatMsg.CHAT_MSG_EMOTE, 0, `${unit.GetName()} is healed for ${healAmount} by the power of fire and frost!`); + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_DAMAGE, (...args) => onDamage(...args)); +``` +In this example, when a unit takes damage, the script retrieves the unit's base spell power for the Fire and Frost spell schools using `GetBaseSpellPower()`. It then modifies the incoming damage based on the spell power values. If the damage is of the Fire or Frost school (determined by checking the `schoolMask`), the damage is increased by a percentage proportional to the respective spell power. + +After dealing the modified damage to the attacker using `DealDamage()`, the script checks if the unit's health percentage is below or equal to 20%. If so, it heals the unit based on a combination of the Fire and Frost spell power values and sends an emote message indicating the amount of healing done. + +This example demonstrates how `GetBaseSpellPower()` can be used to retrieve the base spell power for different spell schools and utilize it to modify damage and perform additional actions based on the spell power values. + +## GetCharmGUID +Returns the GUID (Globally Unique Identifier) of the unit that is currently charming this unit. If the unit is not being charmed, it will return 0. + +### Parameters +None + +### Returns +charmerGuid: number - The GUID of the charmer unit, or 0 if the unit is not being charmed. + +### Example Usage +In this example, we'll create a script that checks if a player is being charmed by another unit. If the player is being charmed, the script will retrieve the GUID of the charmer and use it to get the charmer's name. The script will then send a message to the player with the name of the charmer. + +```typescript +const CheckCharm: player_event_on_update = (event: number, player: Player, diff: number) => { + const charmerGuid = player.GetCharmGUID(); + + if (charmerGuid !== 0) { + const charmer = player.GetMap().GetUnit(charmerGuid); + + if (charmer) { + const charmerName = charmer.GetName(); + player.SendBroadcastMessage(`You are being charmed by ${charmerName}!`); + + // If the charmer is a player, we can get their account name and GM level + if (charmer instanceof Player) { + const accountName = charmer.GetAccountName(); + const gmLevel = charmer.GetGMRank(); + player.SendBroadcastMessage(`Charmer's account name: ${accountName}, GM Level: ${gmLevel}`); + } + } else { + player.SendBroadcastMessage("You are being charmed, but the charmer is not in your map!"); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => CheckCharm(...args)); +``` + +In this script, we register a `PLAYER_EVENT_ON_UPDATE` event, which is triggered every server tick for each player. Inside the event handler, we first get the GUID of the player's charmer using `player.GetCharmGUID()`. If the returned GUID is not 0, it means the player is being charmed. + +We then use the `player.GetMap().GetUnit(charmerGuid)` method to get the actual charmer unit object. If the charmer is found, we retrieve its name using `charmer.GetName()` and send a message to the player informing them about the charmer. + +Additionally, if the charmer is also a player (checked using `charmer instanceof Player`), we retrieve the charmer's account name and GM level using `charmer.GetAccountName()` and `charmer.GetGMRank()` respectively, and send this information to the charmed player. + +If the charmer unit is not found in the player's map, we send a message to the player indicating that they are being charmed, but the charmer is not in their map. + +## GetCharmerGUID +Returns the GUID of the unit that is charming this unit. If the unit is not being charmed, it will return 0. + +### Parameters +None + +### Returns +charmerGuid: number - The GUID of the charmer unit, or 0 if the unit is not being charmed. + +### Example Usage +This example demonstrates how to check if a unit is being charmed and retrieve the GUID of the charmer. It also shows how to use the GUID to find the charmer unit and interact with it. + +```typescript +const OnUnitDeath: vehicle_event_on_passenger_removed = (event: number, vehicle: Vehicle, unit: Unit) => { + // Check if the removed passenger was being charmed + const charmerGuid = unit.GetCharmerGUID(); + if (charmerGuid !== 0) { + // Find the charmer unit using the GUID + const charmer = GetUnitByGUID(charmerGuid); + if (charmer) { + // Break the charm effect on the charmer + charmer.RemoveAurasDueToSpell(SPELL_CHARM); + + // Send a message to the charmer + if (charmer.IsPlayer()) { + const charmerPlayer = charmer.ToPlayer(); + charmerPlayer.SendBroadcastMessage("Your charm effect has been broken!"); + } + + // Deal damage to the charmer + const damage = unit.GetMaxHealth() * 0.25; // 25% of the charmed unit's max health + charmer.DealDamage(charmer, damage); + + // Apply a debuff to the charmer + charmer.AddAura(SPELL_CHARMER_DEBUFF, 30); // 30 seconds duration + } + } +}; + +RegisterVehicleEvent(VehicleEvents.VEHICLE_EVENT_ON_PASSENGER_REMOVED, OnUnitDeath); +``` + +In this example: +1. When a passenger is removed from a vehicle, the script checks if the removed unit was being charmed using `GetCharmerGUID()`. +2. If the unit was being charmed (charmerGuid !== 0), it retrieves the charmer unit using `GetUnitByGUID(charmerGuid)`. +3. If the charmer unit is found, the script performs the following actions: + - Removes the charm effect from the charmer using `RemoveAurasDueToSpell(SPELL_CHARM)`. + - Sends a broadcast message to the charmer if it's a player, informing them that the charm effect has been broken. + - Deals damage to the charmer equal to 25% of the charmed unit's maximum health using `DealDamage()`. + - Applies a debuff to the charmer using `AddAura(SPELL_CHARMER_DEBUFF, 30)` with a duration of 30 seconds. + +This example showcases how to utilize the `GetCharmerGUID()` method to retrieve the charmer's GUID and perform various actions based on that information, such as breaking the charm effect, sending messages, dealing damage, and applying debuffs. + +## GetClass +Returns the class ID of the [Unit]. The class ID is a unique identifier for each class in the game, such as Warrior, Paladin, Hunter, etc. + +### Parameters +This method does not take any parameters. + +### Returns +* number - The class ID of the [Unit]. + +### Example Usage +Here's an example of how to use the `GetClass` method to check if a unit is a Warrior and grant them a bonus to their strength stat: + +```typescript +const CLASS_WARRIOR = 1; +const STRENGTH_BONUS = 50; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const playerClass = player.GetClass(); + + if (playerClass === CLASS_WARRIOR) { + const currentStrength = player.GetStrength(); + const newStrength = currentStrength + STRENGTH_BONUS; + + player.SetStrength(newStrength); + + player.SendBroadcastMessage(`As a mighty Warrior, you have been granted a bonus of ${STRENGTH_BONUS} strength!`); + player.PlayDirectSound(8212); // Play a sound effect + player.CastSpell(player, 43223, true); // Cast a visual effect spell + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: + +1. We define constants for the Warrior class ID and the strength bonus value. +2. In the `OnLogin` event, we retrieve the player's class using `GetClass()`. +3. We check if the player's class is equal to the Warrior class ID. +4. If the player is a Warrior, we retrieve their current strength using `GetStrength()`. +5. We calculate the new strength value by adding the strength bonus. +6. We update the player's strength using `SetStrength()`. +7. We send a broadcast message to the player informing them of the bonus. +8. We play a sound effect using `PlayDirectSound()` and cast a visual effect spell using `CastSpell()`. + +This script will grant a bonus of 50 strength to Warriors when they log in, providing them with a small advantage in combat. The broadcast message, sound effect, and visual effect enhance the player's experience and make the bonus feel more impactful. + +## GetClassAsString +Returns the name of the [Unit]'s class in the given locale or default locale if not provided. + +### Parameters +* locale: [LocaleConstant](../enums/LocaleConstant.md) (optional) - The locale to return the class name in. If not provided, the default locale will be used. + +### Returns +* string - The name of the [Unit]'s class in the specified or default locale, or nil if the class is not found. + +### Example Usage +```typescript +const BOSS_RAZOR_ID = 8564; + +const RazorDialogueOnSpawn: creature_event_on_spawn = (event: CreatureEvents, creature: Creature) => { + const bossRazor = creature.ToCreature(); + if (!bossRazor || bossRazor.GetEntry() !== BOSS_RAZOR_ID) { + return; + } + + const className = bossRazor.GetClassAsString(LocaleConstant.LOCALE_enUS); + if (className) { + bossRazor.SendUnitYell(`Tremble before me, mortals! I am Razor, the mighty ${className}!`, 0); + } else { + bossRazor.SendUnitYell("Tremble before me, mortals! I am Razor, the mighty warrior!", 0); + } + + const chineseClassName = bossRazor.GetClassAsString(LocaleConstant.LOCALE_zhCN); + if (chineseClassName) { + bossRazor.SendUnitYell(`在我面前颤抖吧,凡人!我是剃刀,强大的${chineseClassName}!`, 0, Language.LANG_UNIVERSAL, nil, true); + } +}; + +RegisterCreatureEvent(BOSS_RAZOR_ID, CreatureEvents.CREATURE_EVENT_ON_SPAWN, RazorDialogueOnSpawn); +``` + +In this example, when the boss creature Razor spawns, it retrieves its class name in both English (enUS) and Chinese (zhCN) locales using the `GetClassAsString` method. If the class name is found, Razor yells a message incorporating the class name in the respective language. If the class name is not found for English, a default message is used instead. + +This script demonstrates how the `GetClassAsString` method can be used to retrieve localized class names for a unit, allowing for dynamic and localized dialogue or other interactions based on the unit's class. + +## GetClassMask +Returns the class mask of the unit. The class mask is a bitfield that represents the classes that the unit belongs to. Each bit in the mask corresponds to a specific class. For example, if the first bit (least significant bit) is set, it means the unit belongs to the Warrior class. If the third bit is set, the unit belongs to the Paladin class, and so on. + +### Parameters +This method does not take any parameters. + +### Returns +- `number`: The class mask of the unit. + +### Example Usage +In this example, we'll create a script that checks if a creature belongs to a specific class and awards bonus reputation to players who kill creatures of that class. + +```typescript +const BONUS_REPUTATION_FACTION_ID = 946; // Example faction ID +const BONUS_REPUTATION_AMOUNT = 100; // Example bonus reputation amount +const TARGET_CLASS_MASK = 0x8; // Example class mask for Rogue (8th bit set) + +const OnCreatureKill: player_event_On_Kill_Creature = (event: number, player: Player, creature: Creature) => { + // Get the class mask of the killed creature + const creatureClassMask = creature.GetClassMask(); + + // Check if the creature belongs to the target class + if ((creatureClassMask & TARGET_CLASS_MASK) !== 0) { + // Award bonus reputation to the player + const faction = player.GetFactionByID(BONUS_REPUTATION_FACTION_ID); + if (faction) { + player.SetFactionReputation(faction, player.GetReputationValue(faction) + BONUS_REPUTATION_AMOUNT); + player.SendBroadcastMessage(`You have been awarded ${BONUS_REPUTATION_AMOUNT} bonus reputation for killing a Rogue!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => OnCreatureKill(...args)); +``` + +In this script: + +1. We define constants for the bonus reputation faction ID, bonus reputation amount, and the target class mask (in this case, the Rogue class). + +2. We register the `OnCreatureKill` event handler using `RegisterPlayerEvent`. + +3. Inside the event handler, we get the class mask of the killed creature using `creature.GetClassMask()`. + +4. We check if the creature's class mask matches the target class mask using a bitwise AND operation. If the result is non-zero, it means the creature belongs to the target class. + +5. If the creature belongs to the target class, we retrieve the faction object using `player.GetFactionByID()` with the bonus reputation faction ID. + +6. If the faction object is found, we calculate the new reputation value by adding the bonus reputation amount to the player's current reputation value for that faction using `player.GetReputationValue()`. + +7. We update the player's reputation using `player.SetFactionReputation()` with the new reputation value. + +8. Finally, we send a broadcast message to the player informing them about the bonus reputation award. + +This script demonstrates how the `GetClassMask()` method can be used to determine the class of a unit and perform specific actions based on that information. + +## GetControllerGUID +Returns the GUID of the [Unit]'s charmer or owner. This method is useful for determining if a unit is being controlled by another entity, such as a player or a creature with mind control abilities. + +### Parameters +This method does not take any parameters. + +### Returns +- number: The GUID of the unit's charmer or owner. If the unit is not being controlled, the method will return 0. + +### Example Usage +In this example, we'll create an event that checks if a player is being mind controlled by another unit. If the player is being controlled, we'll display a message to the player and their controller, and then break the mind control effect. + +```typescript +const OnPlayerMindControlled: player_event_on_update = (event: number, player: Player, diff: number) => { + const controllerGUID = player.GetControllerGUID(); + + if (controllerGUID !== 0) { + const controller = player.GetMap().GetUnit(controllerGUID); + + if (controller) { + player.SendBroadcastMessage(`You are being mind controlled by ${controller.GetName()}!`); + controller.SendBroadcastMessage(`You are mind controlling ${player.GetName()}!`); + + // Break the mind control effect + player.RemoveAurasDueToSpell(605); // Mind Control spell ID + player.SendBroadcastMessage("You have broken free from the mind control!"); + controller.SendBroadcastMessage(`${player.GetName()} has broken free from your mind control!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => OnPlayerMindControlled(...args)); +``` + +In this script, we register a `PLAYER_EVENT_ON_UPDATE` event that triggers periodically for each player. Inside the event handler, we call the `GetControllerGUID()` method on the player object to check if they are being controlled by another unit. + +If the returned GUID is not 0, it means the player is being mind controlled. We then use the `GetMap().GetUnit(controllerGUID)` method to obtain the actual controller unit object. + +If the controller unit is found, we send messages to both the player and the controller using the `SendBroadcastMessage()` method, informing them about the mind control situation. + +Finally, we break the mind control effect by removing the Mind Control aura from the player using the `RemoveAurasDueToSpell()` method, passing the spell ID of the Mind Control spell (in this case, 605). We then send additional messages to the player and controller, indicating that the mind control has been broken. + +This example demonstrates how the `GetControllerGUID()` method can be used in conjunction with other methods and events to create interactive gameplay scenarios involving mind control mechanics. + +## GetControllerGUIDS +Returns the GUID of the Unit's charmer or owner. If the Unit is not possessed or owned, it returns the Unit's own GUID. + +### Parameters +None + +### Returns +controllerGUID: number - The GUID of the Unit's charmer, owner, or its own GUID. + +### Example Usage +This example demonstrates how to use GetControllerGUIDS to determine if a Unit is being controlled by another entity and perform different actions based on the controller's GUID. + +```typescript +const HandleUnitSpawn: creature_event_on_spawn = (event: number, creature: Creature): void => { + const controllerGUID = creature.GetControllerGUIDS(); + const creatureGUID = creature.GetGUID(); + + if (controllerGUID !== creatureGUID) { + // The creature is being controlled by another entity + const controller = GetUnitByGUID(controllerGUID); + + if (controller && controller.IsPlayer()) { + // The controller is a player + const player = controller.ToPlayer(); + player.SendBroadcastMessage(`You are controlling ${creature.GetName()}!`); + + // Set the creature's faction to match the player's faction + creature.SetFaction(player.GetFaction()); + } else if (controller && controller.IsCreature()) { + // The controller is another creature + const masterCreature = controller.ToCreature(); + masterCreature.SendUnitSay(`I am controlling ${creature.GetName()}!`, 0); + + // Make the controlled creature assist the master creature in combat + creature.SetAssistMode(true); + creature.SetTargetUnit(masterCreature.GetVictim()); + } + } else { + // The creature is not being controlled + creature.SendUnitSay("I am not being controlled by anyone.", 0); + + // Perform actions for an uncontrolled creature + // ... + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => HandleUnitSpawn(...args)); +``` + +In this example: +1. When a creature spawns, we retrieve its controller's GUID using `GetControllerGUIDS()`. +2. We compare the controller's GUID with the creature's own GUID to determine if it's being controlled. +3. If the creature is controlled by a player: + - We send a message to the player indicating they are controlling the creature. + - We set the creature's faction to match the player's faction. +4. If the creature is controlled by another creature: + - We make the controlled creature assist the master creature in combat. + - We set the controlled creature's target to the master creature's current target. +5. If the creature is not being controlled: + - We make the creature say a message indicating it's not being controlled. + - We can perform additional actions for an uncontrolled creature. + +This example showcases how `GetControllerGUIDS()` can be used to determine the controlling entity of a Unit and adapt the behavior of the Unit based on its controller. + +## GetCreatorGUID +Returns the GUID of the [Unit](./unit.md) that created this [Unit](./unit.md). This is useful for determining the owner of a pet, summon, or any other unit that was created by another unit. + +### Parameters +This method does not take any parameters. + +### Returns +number: The GUID of the creator [Unit](./unit.md). If the [Unit](./unit.md) has no creator, it returns 0. + +### Example Usage +In this example, we'll create a script that checks if a player's pet has been killed and notify the player about it. + +```typescript +const PET_KILLED = (event: number, killer: Unit, killed: Unit): void => { + // Check if the killed unit is a player's pet + if (killed.IsPet()) { + const creatorGUID = killed.GetCreatorGUID(); + // Find the player who owns the pet + const player = GetPlayerByGUID(creatorGUID); + if (player) { + // Notify the player that their pet has been killed + player.SendBroadcastMessage(`Your pet ${killed.GetName()} has been killed by ${killer.GetName()}!`); + // Despawn the pet's corpse after 5 seconds + killed.Despawn(5000); + // Respawn the pet in 2 minutes + player.SpawnPet(2 * MINUTE * IN_MILLISECONDS); + } + } +}; + +RegisterServerEvent(ServerEvents.CREATURE_ON_KILLED, (...args) => PET_KILLED(...args)); +``` + +In this script: +1. We register a listener for the `CREATURE_ON_KILLED` event. +2. When a creature is killed, we check if it's a player's pet using `IsPet()`. +3. If it's a pet, we get the creator's GUID using `GetCreatorGUID()`. +4. We find the player who owns the pet using `GetPlayerByGUID(creatorGUID)`. +5. If the player is found, we send them a message using `SendBroadcastMessage()` to notify them about their pet's death. +6. We despawn the pet's corpse after 5 seconds using `Despawn(5000)`. +7. We respawn the pet for the player after 2 minutes using `SpawnPet(2 * MINUTE * IN_MILLISECONDS)`. + +This script demonstrates how `GetCreatorGUID()` can be used to identify the owner of a pet and take actions based on that information. + +## GetCreatureType + +Returns the creature type of the unit based on the CreatureType enum. + +### Parameters + +None + +### Returns + +creatureType: [CreatureType](../enums/CreatureType.md) - The creature type of the unit. + +### Example Usage + +Here's an example of how to use the `GetCreatureType` method to determine if a unit is a specific creature type and perform different actions based on the result: + +```typescript +const OnUnitDeath: unit_event_on_unit_death = (event: number, unit: Unit, attacker: Unit) => { + const creatureType = unit.GetCreatureType(); + + switch (creatureType) { + case CreatureType.CREATURE_TYPE_BEAST: + // Perform actions specific to beasts + attacker.SendBroadcastMessage("You have slain a mighty beast!"); + attacker.CastSpell(attacker, 12345, true); // Cast a spell as a reward + break; + case CreatureType.CREATURE_TYPE_DEMON: + // Perform actions specific to demons + attacker.SendBroadcastMessage("You have vanquished a demonic foe!"); + attacker.AddItem(6789, 1); // Add a special item to the attacker's inventory + break; + case CreatureType.CREATURE_TYPE_HUMANOID: + // Perform actions specific to humanoids + attacker.SendBroadcastMessage("You have defeated a formidable humanoid opponent!"); + attacker.ModifyMoney(100); // Reward the attacker with gold + break; + default: + // Perform actions for other creature types or default behavior + attacker.SendBroadcastMessage("You have emerged victorious against your foe!"); + break; + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_UNIT_DEATH, (...args) => OnUnitDeath(...args)); +``` + +In this example, the `GetCreatureType` method is used within the `UNIT_EVENT_ON_UNIT_DEATH` event to determine the creature type of the unit that was killed. Based on the creature type, different actions are performed using a switch statement. + +- If the unit is a beast (`CREATURE_TYPE_BEAST`), the attacker receives a specific broadcast message and a spell is cast on them as a reward. +- If the unit is a demon (`CREATURE_TYPE_DEMON`), the attacker receives a different broadcast message and a special item is added to their inventory. +- If the unit is a humanoid (`CREATURE_TYPE_HUMANOID`), the attacker receives another broadcast message and is rewarded with gold using the `ModifyMoney` method. +- For any other creature type, a default broadcast message is sent to the attacker. + +This example demonstrates how the `GetCreatureType` method can be used to create dynamic and specialized behavior based on the creature type of the unit. + +## GetCritterGUID +Retrieves the GUID (Globally Unique Identifier) of the critter that the unit is currently controlling or has summoned. + +### Parameters +This method does not take any parameters. + +### Returns +* number - The GUID of the critter. If the unit does not have a critter, it returns 0. + +### Example Usage +This script demonstrates how to retrieve the critter GUID and use it to perform actions on the critter, such as setting its position and orientation. + +```typescript +const SUMMON_CRITTER_SPELL_ID = 123456; + +const OnPlayerCastSpell: player_event_on_cast_spell = (event: number, player: Player, spell: number, skipCheck?: boolean) => { + if (spell === SUMMON_CRITTER_SPELL_ID) { + const critterGUID = player.GetCritterGUID(); + + if (critterGUID !== 0) { + const critter = player.GetMap().GetWorldObject(critterGUID); + + if (critter && critter.IsCreature()) { + const critterCreature = critter.ToCreature(); + + // Set the critter's position and orientation to match the player + const playerPosition = player.GetPosition(); + const playerOrientation = player.GetOrientation(); + critterCreature.Relocate(playerPosition.x, playerPosition.y, playerPosition.z, playerOrientation); + + // Make the critter perform an emote + critterCreature.PerformEmote(10); // Emote ID 10 represents a happy emote + + // Set the critter's follow target to the player + critterCreature.SetFollowTarget(player.GetGUID()); + + player.SendBroadcastMessage("Your critter is now following you!"); + } else { + player.SendBroadcastMessage("Failed to retrieve the critter."); + } + } else { + player.SendBroadcastMessage("You do not have a critter summoned."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CAST_SPELL, (...args) => OnPlayerCastSpell(...args)); +``` + +In this example, when a player casts a specific spell (identified by `SUMMON_CRITTER_SPELL_ID`), the script retrieves the critter GUID using `GetCritterGUID()`. If a critter is found, it performs the following actions: + +1. Retrieves the critter as a WorldObject using `GetMap().GetWorldObject(critterGUID)`. +2. Checks if the WorldObject is a Creature using `IsCreature()` and converts it to a Creature using `ToCreature()`. +3. Sets the critter's position and orientation to match the player's using `Relocate()`. +4. Makes the critter perform a happy emote using `PerformEmote()`. +5. Sets the critter's follow target to the player using `SetFollowTarget()`. +6. Sends a broadcast message to the player indicating that the critter is now following them. + +If the critter is not found or if the player does not have a critter summoned, appropriate messages are sent to the player. + +This example showcases how to use `GetCritterGUID()` to interact with the critter and perform various actions based on the retrieved GUID. + +## GetCurrentSpell +Returns the currently casted spell of the specified type. This can be useful for determining if the unit is currently casting a spell, and if so, which spell it is. + +### Parameters +* spellType: [CurrentSpellTypes](../enums/CurrentSpellTypes.md) - The type of spell to retrieve. + +### Returns +[Spell](./spell.md) - The currently casted spell of the specified type, or nil if no spell of that type is being casted. + +### Example Usage +```typescript +const SPELL_FIREBALL = 133; +const SPELL_FROSTBOLT = 116; + +const onUnitSpellCast: unit_event_on_spell_cast = (event: number, unit: Unit, spell: Spell): void => { + const currentSpell = unit.GetCurrentSpell(CurrentSpellTypes.CURRENT_GENERIC_SPELL); + + if (currentSpell) { + const spellId = currentSpell.GetEntry(); + + switch (spellId) { + case SPELL_FIREBALL: + unit.SendChatMessage(ChatMsg.CHAT_MSG_SAY, Language.LANG_UNIVERSAL, "I am casting Fireball!"); + break; + case SPELL_FROSTBOLT: + unit.SendChatMessage(ChatMsg.CHAT_MSG_SAY, Language.LANG_UNIVERSAL, "I am casting Frostbolt!"); + break; + default: + unit.SendChatMessage(ChatMsg.CHAT_MSG_SAY, Language.LANG_UNIVERSAL, `I am casting a generic spell with ID ${spellId}`); + break; + } + } else { + unit.SendChatMessage(ChatMsg.CHAT_MSG_SAY, Language.LANG_UNIVERSAL, "I am not casting any generic spell at the moment."); + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_SPELL_CAST, (...args) => onUnitSpellCast(...args)); +``` + +In this example, we register a script for the `UNIT_EVENT_ON_SPELL_CAST` event. When a unit starts casting a spell, we retrieve the currently casted generic spell using `unit.GetCurrentSpell(CurrentSpellTypes.CURRENT_GENERIC_SPELL)`. + +If a spell is being casted, we get its entry ID using `currentSpell.GetEntry()`. We then use a switch statement to check if the spell ID matches any of the specific spells we're interested in (Fireball and Frostbolt in this case). If a match is found, we make the unit say a specific message using `unit.SendChatMessage()`. If no match is found, we make the unit say a generic message that includes the spell ID. + +If no generic spell is being casted, we make the unit say a message indicating that they are not casting any generic spell at the moment. + +This script demonstrates how you can use `GetCurrentSpell()` to detect and respond to specific spells being casted by a unit. + +## GetDisplayId +Returns the current display ID of the unit. The display ID is an identifier that determines the visual appearance of the unit, such as its model, texture, and animations. + +### Returns +displayId: number - The current display ID of the unit. + +### Example Usage +Here's an example of how to use the `GetDisplayId` method to check if a unit is using a specific display ID and perform actions based on the result: + +```typescript +const BEAR_DISPLAY_ID = 1234; +const CAT_DISPLAY_ID = 5678; + +const onUnitSpawn: creature_event_on_spawn = (event: number, creature: Creature) => { + const displayId = creature.GetDisplayId(); + + switch (displayId) { + case BEAR_DISPLAY_ID: + // Perform actions specific to units with the bear display ID + creature.SetScale(1.5); + creature.SetFaction(1); // Alliance faction + creature.SendUnitSay("Roar! I'm a mighty bear!", 0); + break; + case CAT_DISPLAY_ID: + // Perform actions specific to units with the cat display ID + creature.SetScale(0.8); + creature.SetFaction(2); // Horde faction + creature.SendUnitSay("Meow! I'm a stealthy cat!", 0); + break; + default: + // Perform actions for units with other display IDs + creature.SendUnitSay("I have a unique appearance!", 0); + break; + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => onUnitSpawn(...args)); +``` + +In this example: + +1. We define constants `BEAR_DISPLAY_ID` and `CAT_DISPLAY_ID` to represent specific display IDs. + +2. Inside the `onUnitSpawn` event handler, we retrieve the display ID of the spawned creature using `creature.GetDisplayId()`. + +3. We use a `switch` statement to perform different actions based on the display ID: + - If the display ID matches `BEAR_DISPLAY_ID`, we set the creature's scale to 1.5, set its faction to Alliance, and make it say "Roar! I'm a mighty bear!" using `creature.SendUnitSay()`. + - If the display ID matches `CAT_DISPLAY_ID`, we set the creature's scale to 0.8, set its faction to Horde, and make it say "Meow! I'm a stealthy cat!" using `creature.SendUnitSay()`. + - For any other display ID, we make the creature say "I have a unique appearance!" using `creature.SendUnitSay()`. + +4. Finally, we register the `onUnitSpawn` event handler for the `CREATURE_EVENT_ON_SPAWN` event using `RegisterCreatureEvent()`. + +This example demonstrates how to retrieve the display ID of a unit and perform different actions based on the specific display ID. It showcases a more complex usage scenario where the display ID is used to determine the visual appearance and behavior of the unit. + +## GetFaction +Returns the faction ID of the unit. The faction ID is a unique identifier for each faction in the game, and it determines the unit's alignment and relationship with other factions. + +### Parameters +This method does not take any parameters. + +### Returns +faction: number - The faction ID of the unit. + +### Example Usage +In this example, we will create a script that checks the faction of a unit when it is attacked by a player. If the unit belongs to a specific faction, the player will receive a bonus item. + +```typescript +const BONUS_ITEM_ENTRY = 12345; +const BONUS_ITEM_COUNT = 1; +const TARGET_FACTION_ID = 123; + +const OnPlayerAttackUnit: player_event_on_attack = (event: number, player: Player, unitVictim: Unit) => { + // Check if the attacked unit belongs to the desired faction + if (unitVictim.GetFaction() === TARGET_FACTION_ID) { + // Generate a random number between 0 and 99 + const randomNumber = Math.floor(Math.random() * 100); + + // 20% chance to receive the bonus item + if (randomNumber < 20) { + // Add the bonus item to the player's inventory + const bonusItem = player.AddItem(BONUS_ITEM_ENTRY, BONUS_ITEM_COUNT); + + if (bonusItem) { + // Send a message to the player + player.SendBroadcastMessage(`You received a bonus item for attacking a unit of the desired faction!`); + } else { + // Send an error message to the player if adding the item fails + player.SendBroadcastMessage(`Failed to add the bonus item to your inventory.`); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ATTACK, (...args) => OnPlayerAttackUnit(...args)); +``` + +In this script: +1. We define the constants for the bonus item entry, count, and the target faction ID. +2. We register the `PLAYER_EVENT_ON_ATTACK` event to trigger the `OnPlayerAttackUnit` callback function whenever a player attacks a unit. +3. Inside the callback function, we check if the attacked unit's faction matches the desired faction ID using the `GetFaction()` method. +4. If the faction matches, we generate a random number between 0 and 99. +5. If the random number is less than 20 (representing a 20% chance), we add the bonus item to the player's inventory using the `AddItem()` method. +6. If the item is successfully added, we send a broadcast message to the player informing them about receiving the bonus item. +7. If adding the item fails (e.g., due to a full inventory), we send an error message to the player. + +This script demonstrates how the `GetFaction()` method can be used to determine the faction of a unit and perform specific actions based on that information. In this case, players have a chance to receive a bonus item when attacking units of a particular faction. + +## GetFriendlyUnitsInRange +Returns a table containing friendly [Unit](./unit.md)'s within the given range of the [Unit](./unit.md). + +### Parameters +* range?: number - (Optional) The range to search for friendly units. If not provided, the default range is used. + +### Returns +* table: number - A table containing the GUIDs of the friendly units within the specified range. + +### Example Usage +This example demonstrates how to use the `GetFriendlyUnitsInRange` method to find friendly units near a player and apply a buff to them. + +```typescript +const BUFF_SPELL_ID = 12345; +const BUFF_RANGE = 20; + +const BuffNearbyAllies: player_event_on_login = (event: number, player: Player) => { + // Get the friendly units within the specified range + const friendlyUnits = player.GetFriendlyUnitsInRange(BUFF_RANGE); + + // Iterate through the friendly units + for (const guid of friendlyUnits) { + // Create a Unit object from the GUID + const unit = Unit.GetUnit(player, guid); + + // Check if the unit is valid and not the player itself + if (unit && unit.GetGUID() !== player.GetGUID()) { + // Check if the unit already has the buff + if (!unit.HasAura(BUFF_SPELL_ID)) { + // Cast the buff spell on the friendly unit + player.CastSpell(unit, BUFF_SPELL_ID, false); + } + } + } + + // Send a message to the player + player.SendBroadcastMessage(`You have buffed ${friendlyUnits.length} nearby allies!`); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => BuffNearbyAllies(...args)); +``` + +In this example: +1. We define constants for the buff spell ID (`BUFF_SPELL_ID`) and the range to search for friendly units (`BUFF_RANGE`). +2. We register a player event handler for the `PLAYER_EVENT_ON_LOGIN` event. +3. Inside the event handler, we call `GetFriendlyUnitsInRange` on the player object, passing the `BUFF_RANGE` as an argument. This returns a table containing the GUIDs of friendly units within the specified range. +4. We iterate through the table of GUIDs using a `for...of` loop. +5. For each GUID, we create a `Unit` object using `Unit.GetUnit` and passing the player and the GUID as arguments. +6. We check if the unit is valid and not the player itself by comparing the GUIDs. +7. If the unit is valid and doesn't already have the buff (checked using `HasAura`), we cast the buff spell on the unit using `player.CastSpell`. +8. Finally, we send a broadcast message to the player informing them about the number of allies they have buffed. + +This example showcases how `GetFriendlyUnitsInRange` can be used to find nearby friendly units and interact with them, such as applying buffs or performing other actions. + +## GetGender +Returns the gender of the unit. + +### Parameters +This method does not take any parameters. + +### Returns +gender: number - The gender of the unit (0 = Male, 1 = Female, 2 = None). + +### Example Usage +This example demonstrates how to use the `GetGender()` method to determine the gender of a unit and apply different effects based on the gender. + +```typescript +const SPELL_MALE_BUFF = 12345; +const SPELL_FEMALE_BUFF = 54321; + +const OnUnitSpawn: map_event_on_creature_create = (event: number, creature: Creature) => { + const gender = creature.GetGender(); + + switch (gender) { + case 0: // Male + creature.CastSpell(creature, SPELL_MALE_BUFF, true); + creature.SetDisplayId(1234); // Set male display ID + break; + case 1: // Female + creature.CastSpell(creature, SPELL_FEMALE_BUFF, true); + creature.SetDisplayId(5678); // Set female display ID + break; + case 2: // None + // Handle units with no gender + break; + } + + // Customize additional properties based on gender + if (gender === 0) { + creature.SetScale(1.2); // Increase scale for males + creature.SetUInt32Value(UnitFields.UNIT_FIELD_ATTACK_POWER, 500); // Set higher attack power for males + } else if (gender === 1) { + creature.SetScale(0.9); // Decrease scale for females + creature.SetUInt32Value(UnitFields.UNIT_FIELD_ATTACK_POWER, 400); // Set lower attack power for females + } +}; + +RegisterMapEvent(MapEvents.MAP_EVENT_ON_CREATURE_CREATE, (...args) => OnUnitSpawn(...args)); +``` + +In this example, when a creature is spawned on the map, the `GetGender()` method is used to determine its gender. Based on the gender, different spells are cast on the creature, and different display IDs are set to visually differentiate between male and female creatures. + +Additionally, the example demonstrates how to customize other properties based on the gender, such as setting a larger scale and higher attack power for male creatures, and a smaller scale and lower attack power for female creatures. + +This example showcases how the `GetGender()` method can be used in combination with other methods and properties to create gender-specific behavior and appearance for units in the game. + +## GetHealth +Returns the current health of the [Unit]. + +### Parameters +None + +### Returns +health: number - The current health of the [Unit]. + +### Example Usage +This example demonstrates how to retrieve the current health of a unit and perform different actions based on the health percentage. + +```typescript +const healthCheckInterval = 1000; // Check health every 1 second + +const healthChecker: world_event_on_update = (event: number, diff: number) => { + const player = GetPlayersInWorld()[0]; // Get the first player in the world + if (!player) return; + + const target = player.GetSelection(); + if (!target) return; + + const maxHealth = target.GetMaxHealth(); + const currentHealth = target.GetHealth(); + const healthPercentage = (currentHealth / maxHealth) * 100; + + if (healthPercentage <= 20) { + // If health is 20% or below, send a warning message to the player + player.SendBroadcastMessage(`Warning: ${target.GetName()}'s health is critically low!`); + } else if (healthPercentage <= 50) { + // If health is 50% or below, send a notification to the player + player.SendBroadcastMessage(`Notice: ${target.GetName()}'s health is below 50%.`); + } else if (healthPercentage >= 90) { + // If health is 90% or above, send a positive message to the player + player.SendBroadcastMessage(`${target.GetName()} is in excellent health!`); + } +}; + +RegisterWorldEvent(WorldEvents.WORLD_EVENT_ON_UPDATE, (...args) => healthChecker(...args)); +``` + +In this example: +1. We define a `healthCheckInterval` constant to determine how often we want to check the health of a unit (in this case, every 1 second). + +2. We create a `healthChecker` function that will be triggered on each world update event. + +3. Inside the `healthChecker` function: + - We retrieve the first player in the world using `GetPlayersInWorld()[0]`. If no player is found, we return. + - We get the selected target of the player using `player.GetSelection()`. If no target is selected, we return. + - We retrieve the maximum health and current health of the target using `target.GetMaxHealth()` and `target.GetHealth()`, respectively. + - We calculate the health percentage using the formula: `(currentHealth / maxHealth) * 100`. + - We check the health percentage and perform different actions based on the conditions: + - If the health is 20% or below, we send a warning message to the player indicating that the target's health is critically low. + - If the health is 50% or below, we send a notification to the player indicating that the target's health is below 50%. + - If the health is 90% or above, we send a positive message to the player indicating that the target is in excellent health. + +4. Finally, we register the `healthChecker` function to be triggered on each world update event using `RegisterWorldEvent(WorldEvents.WORLD_EVENT_ON_UPDATE, ...)`. + +This example showcases how you can utilize the `GetHealth()` method to monitor the health of a unit and perform different actions based on the health percentage. You can customize the conditions and actions according to your specific requirements. + +## GetHealthPct + +Returns the current health percentage of the unit. + +### Parameters + +This method does not take any parameters. + +### Returns + +* number - The current health percentage of the unit as a value between 0 and 100. + +### Example Usage + +In this example, we'll create a script that notifies the player when their target's health drops below 50% and grants them a temporary damage boost. + +```typescript +const TARGET_HEALTH_THRESHOLD = 50; +const DAMAGE_BOOST_AURA = 123456; +const DAMAGE_BOOST_DURATION = 10; // In seconds + +const onDamage: creature_event_on_damage_taken = (event: number, creature: Creature, attacker: Unit, damage: number) => { + if (attacker.IsPlayer()) { + const player = attacker.ToPlayer(); + const targetHealth = creature.GetHealthPct(); + + if (targetHealth < TARGET_HEALTH_THRESHOLD && !player.HasAura(DAMAGE_BOOST_AURA)) { + player.SendBroadcastMessage(`Your target is now below ${TARGET_HEALTH_THRESHOLD}% health!`); + player.AddAura(DAMAGE_BOOST_AURA, DAMAGE_BOOST_DURATION); + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_DAMAGE_TAKEN, (event: number, creature: Creature, attacker: Unit, damage: number) => { + onDamage(event, creature, attacker, damage); +}); +``` + +In this script: + +1. We define constants for the target health threshold (50%), the damage boost aura ID, and the duration of the damage boost (10 seconds). + +2. We create a function called `onDamage` that will be triggered whenever a creature takes damage. + +3. Inside the `onDamage` function, we check if the attacker is a player using the `IsPlayer()` method. + +4. If the attacker is a player, we retrieve the player object using the `ToPlayer()` method. + +5. We get the current health percentage of the target creature using the `GetHealthPct()` method. + +6. If the target's health is below the defined threshold (50%) and the player doesn't already have the damage boost aura, we proceed with the following steps: + - Send a broadcast message to the player informing them that their target is now below the threshold. + - Apply the damage boost aura to the player using the `AddAura()` method, specifying the aura ID and duration. + +7. Finally, we register the `onDamage` function to be triggered whenever a creature takes damage using the `RegisterCreatureEvent()` function with the `CREATURE_EVENT_ON_DAMAGE_TAKEN` event. + +With this script, whenever a player attacks a creature and brings its health below 50%, they will receive a notification and a temporary damage boost aura to help them finish off the target more quickly. + +## GetLevel +Retrieves the current level of the Unit. + +### Parameters +None + +### Returns +level: number - The current level of the Unit. + +### Example Usage +Here's an example of how to use the `GetLevel()` method to scale the damage dealt by a creature based on the player's level: + +```typescript +const SCALING_FACTOR = 0.1; + +const DamageDealt: unit_event_on_dealt_damage = (event: number, unit: Unit, damage: number, victim: Unit) => { + if (unit.IsCreature() && victim.IsPlayer()) { + const creatureLevel = unit.GetLevel(); + const playerLevel = victim.GetLevel(); + + if (playerLevel > creatureLevel) { + const levelDifference = playerLevel - creatureLevel; + const scaledDamage = damage * (1 + levelDifference * SCALING_FACTOR); + + unit.DealDamage(victim, scaledDamage, false, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, null, false); + return scaledDamage; + } + } + + return damage; +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_DEALT_DAMAGE, (...args) => DamageDealt(...args)); +``` + +In this example, we register a script for the `UNIT_EVENT_ON_DEALT_DAMAGE` event. When a creature deals damage to a player, we retrieve the creature's level using `unit.GetLevel()` and the player's level using `victim.GetLevel()`. + +If the player's level is higher than the creature's level, we calculate the level difference and scale the damage based on a scaling factor (`SCALING_FACTOR`). The scaled damage is then dealt to the player using `unit.DealDamage()` with the appropriate parameters. + +By utilizing the `GetLevel()` method, we can dynamically adjust the damage dealt by creatures based on the player's level, creating a more challenging and engaging experience for higher-level players. + +Note: Make sure to replace `DIRECT_DAMAGE` and `SPELL_SCHOOL_MASK_NORMAL` with the appropriate constants based on your specific use case. + +## GetMaxHealth +Returns the maximum health of the unit. This can be used to calculate the percentage of health the unit has, or to check if the unit is at full health. + +### Parameters +None + +### Returns +number - The maximum health of the unit. + +### Example Usage +This script will check if the player is below 50% health when they enter combat. If they are, it will heal them for 50% of their max health and send them a message. + +```typescript +const HEAL_PERCENT = 50; + +const OnEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + const playerHealth = player.GetHealth(); + const playerMaxHealth = player.GetMaxHealth(); + const healthPercent = (playerHealth / playerMaxHealth) * 100; + + if (healthPercent < 50) { + const healAmount = Math.floor(playerMaxHealth * (HEAL_PERCENT / 100)); + player.SetHealth(playerHealth + healAmount); + + player.SendBroadcastMessage(`You were healed for ${healAmount} health.`); + player.SendBroadcastMessage(`Your current health is now ${player.GetHealth()}/${playerMaxHealth}.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => OnEnterCombat(...args)); +``` + +In this example, we first calculate the player's current health percentage by dividing their current health by their max health and multiplying by 100. We then check if this percentage is below 50%. + +If the player's health is below 50%, we calculate the amount to heal them by multiplying their max health by the `HEAL_PERCENT` constant (which is set to 50 in this example) divided by 100. We then add this heal amount to the player's current health using `player.SetHealth()`. + +Finally, we send the player two messages using `player.SendBroadcastMessage()`. The first message tells them how much they were healed for, and the second message tells them their current health and max health. + +This script showcases how `GetMaxHealth()` can be used in combination with other methods like `GetHealth()` and `SetHealth()` to create more complex behaviors based on the unit's current health state. + +## GetMaxPower +Returns the maximum power amount for the given power type. This can be used to determine the maximum amount of a specific power type, such as mana, rage, or energy, that a unit can have. + +### Parameters +* type: number - The power type to get the maximum value for. The power types are defined in the Powers enum: + ```typescript + enum Powers + { + POWER_MANA = 0, + POWER_RAGE = 1, + POWER_FOCUS = 2, + POWER_ENERGY = 3, + POWER_HAPPINESS = 4, + POWER_RUNE = 5, + POWER_RUNIC_POWER = 6, + MAX_POWERS = 7, + POWER_ALL = 127, // default for class? + POWER_HEALTH = 0xFFFFFFFE // (-2 as signed value) + }; + ``` + +### Returns +number - The maximum power amount for the specified power type. + +### Example Usage +```typescript +const POWER_MANA = 0; +const POWER_RAGE = 1; +const POWER_ENERGY = 3; + +const CheckUnitPower: unit_event_on_spawn = (event: number, unit: Unit) => { + const maxMana = unit.GetMaxPower(POWER_MANA); + const maxRage = unit.GetMaxPower(POWER_RAGE); + const maxEnergy = unit.GetMaxPower(POWER_ENERGY); + + console.log(`Unit ${unit.GetName()} spawned with the following max power values:`); + console.log(`Max Mana: ${maxMana}`); + console.log(`Max Rage: ${maxRage}`); + console.log(`Max Energy: ${maxEnergy}`); + + // Adjust the unit's power based on certain conditions + if (unit.GetEntry() === 12345) { + unit.SetPower(POWER_MANA, maxMana * 0.5); // Set mana to 50% of max + } else if (unit.GetEntry() === 67890) { + unit.SetPower(POWER_RAGE, maxRage * 0.75); // Set rage to 75% of max + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_SPAWN, (...args) => CheckUnitPower(...args)); +``` + +In this example, when a unit spawns, the script retrieves the maximum power values for mana, rage, and energy using the `GetMaxPower` method. It then logs these values to the console. + +Additionally, based on certain unit entry conditions (in this case, specific unit IDs), the script adjusts the unit's power levels. For example, if the unit's entry is 12345, it sets the unit's mana to 50% of its maximum value. Similarly, if the unit's entry is 67890, it sets the unit's rage to 75% of its maximum value. + +This demonstrates how `GetMaxPower` can be used in conjunction with other methods like `GetEntry`, `SetPower`, and `GetName` to retrieve and manipulate a unit's power values based on specific conditions or requirements. + +## GetMountId +Returns the model ID of the mount currently used by the unit. + +### Parameters +None + +### Returns +modelId: number - The model ID of the mount. If the unit is not mounted, it returns 0. + +### Example Usage +Here's an example of how to use `GetMountId()` to check if a player is mounted on a specific mount and grant them a bonus: + +```typescript +const SWIFT_WHITE_HAWKSTRIDER_MODEL_ID = 19483; +const MOUNT_SPEED_BONUS = 10; + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + const mountId = player.GetMountId(); + + if (mountId === SWIFT_WHITE_HAWKSTRIDER_MODEL_ID) { + // Player is mounted on a Swift White Hawkstrider + player.SendBroadcastMessage("You are mounted on a Swift White Hawkstrider! Granting speed bonus."); + + // Increase the player's movement speed by the bonus amount + const currentSpeed = player.GetSpeed(UnitMoveType.MOVE_RUN); + const newSpeed = currentSpeed + (MOUNT_SPEED_BONUS / 100); + player.SetSpeed(UnitMoveType.MOVE_RUN, newSpeed); + + // Increase the player's mounted movement speed by the bonus amount + const currentMountedSpeed = player.GetSpeed(UnitMoveType.MOVE_FLIGHT); + const newMountedSpeed = currentMountedSpeed + (MOUNT_SPEED_BONUS / 100); + player.SetSpeed(UnitMoveType.MOVE_FLIGHT, newMountedSpeed); + + player.SendBroadcastMessage(`Your movement speed has been increased by ${MOUNT_SPEED_BONUS}% while mounted on the Swift White Hawkstrider!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example: +1. We define the model ID of the Swift White Hawkstrider mount and the speed bonus percentage we want to apply. +2. When a player logs in, we use `GetMountId()` to retrieve the model ID of their current mount. +3. We check if the mount ID matches the Swift White Hawkstrider's model ID. +4. If the player is mounted on a Swift White Hawkstrider, we send them a broadcast message informing them about the speed bonus. +5. We calculate the new movement speed by adding the speed bonus to the player's current running speed using `GetSpeed()` and `SetSpeed()`. +6. We also calculate the new mounted movement speed by adding the speed bonus to the player's current flight speed. +7. Finally, we send another broadcast message to the player, informing them about the specific speed bonus they received. + +This script showcases how `GetMountId()` can be used to identify a player's mount and apply specific bonuses or effects based on the mount they are using. + +## GetMovementType +Returns the current movement type for the Unit. This can be used to determine how the unit is moving or if it is stationary. + +### Returns +[MovementGeneratorType](../MovementGeneratorType.md): The current movement type of the unit. + +### Example Usage +This example demonstrates how to use the `GetMovementType` method to determine if a creature is idle or moving. If the creature is idle, it will be commanded to move to a random point within 10 yards of its current position. + +```typescript +const IDLE_MOTION_TYPE = 0; +const RANDOM_MOTION_TYPE = 1; + +const HandleCreatureMovement: creature_event_on_update = (event: CreatureEvents, creature: Creature, diff: number) => { + // Check if the creature is idle + if (creature.GetMovementType() === IDLE_MOTION_TYPE) { + // Generate a random point within 10 yards of the creature's current position + const randomPoint = creature.GetNearPoint(creature, 10, Math.Random() * 2 * Math.PI); + + // Command the creature to move to the random point + creature.MoveTo(randomPoint.x, randomPoint.y, randomPoint.z, RANDOM_MOTION_TYPE); + + // Print a debug message + console.log(`Creature ${creature.GetName()} is idle. Moving to random point (${randomPoint.x}, ${randomPoint.y}, ${randomPoint.z}).`); + } else { + // Print the current movement type of the creature + const movementType = creature.GetMovementType(); + console.log(`Creature ${creature.GetName()} is moving with movement type ${movementType}.`); + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => HandleCreatureMovement(...args)); +``` + +In this example: +1. We define constants for the `IDLE_MOTION_TYPE` and `RANDOM_MOTION_TYPE` movement types. +2. Inside the `HandleCreatureMovement` function, we check if the creature's current movement type is `IDLE_MOTION_TYPE` using the `GetMovementType` method. +3. If the creature is idle, we generate a random point within 10 yards of the creature's current position using the `GetNearPoint` method. +4. We command the creature to move to the random point using the `MoveTo` method, specifying the `RANDOM_MOTION_TYPE` as the movement type. +5. We print a debug message indicating that the creature is idle and is being moved to a random point. +6. If the creature is not idle, we retrieve the current movement type using `GetMovementType` and print a debug message indicating the creature's current movement type. + +This example demonstrates how `GetMovementType` can be used to determine a unit's movement state and take appropriate actions based on that state. + +## GetNativeDisplayId +Returns the native display ID of the unit. This is the original display ID that the unit was spawned with, and it remains constant throughout the unit's lifetime. + +### Parameters +None + +### Returns +displayId: number - The native display ID of the unit. + +### Example Usage +Create a script that checks if a player has a specific item in their inventory. If they do, transform the player's appearance to match the native display ID of a random creature in the game world. + +```typescript +const ITEM_ENTRY = 12345; // Replace with the desired item entry ID + +const onItemUse: player_event_on_use_item = (event: number, player: Player, item: Item, gameObject: GameObject, target: Unit): void => { + if (item.GetEntry() === ITEM_ENTRY) { + const creatures: Unit[] = player.GetCreaturesInRange(100, -1); + if (creatures.length > 0) { + const randomCreature: Unit = creatures[Math.floor(Math.random() * creatures.length)]; + const nativeDisplayId: number = randomCreature.GetNativeDisplayId(); + + player.SetDisplayId(nativeDisplayId); + player.SendBroadcastMessage(`You have been transformed into a creature with display ID ${nativeDisplayId}!`); + } else { + player.SendBroadcastMessage("No creatures found nearby to transform into."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => onItemUse(...args)); +``` + +In this example: +1. We define the entry ID of the item that triggers the transformation (`ITEM_ENTRY`). +2. When a player uses an item, the `onItemUse` event is triggered. +3. We check if the used item's entry ID matches the desired item entry (`ITEM_ENTRY`). +4. If it does, we retrieve all creatures within a 100-yard range of the player using `GetCreaturesInRange()`. +5. If creatures are found, we randomly select one of them. +6. We retrieve the native display ID of the selected creature using `GetNativeDisplayId()`. +7. We set the player's display ID to the native display ID of the creature using `SetDisplayId()`, effectively transforming the player's appearance. +8. We send a broadcast message to the player informing them about the transformation and the display ID they have been transformed into. +9. If no creatures are found nearby, we send a message to the player indicating that no transformation could be performed. + +This script provides an interactive way for players to transform their appearance based on the native display IDs of creatures in the game world, adding an element of surprise and variety to their gameplay experience. + +## GetOwner +Returns the [Unit](./unit.md) that owns this [Unit](./unit.md). If the [Unit](./unit.md) has no owner, nil is returned. + +### Parameters +None + +### Returns +owner: [Unit](./unit.md) or nil - The [Unit](./unit.md) that owns this [Unit](./unit.md), or nil if no owner exists. + +### Example Usage +This example demonstrates how to use the `GetOwner` method to check if a unit is owned by a player and grant bonus damage if so. + +```typescript +const OWNER_DAMAGE_BONUS = 0.25; + +const OnDamage: unit_event_on_damage = (event: number, unit: Unit, attacker: Unit, damage: number) => { + const owner = attacker.GetOwner(); + + if (owner && owner.IsPlayer()) { + const player = owner.ToPlayer(); + const bonusDamage = damage * OWNER_DAMAGE_BONUS; + + unit.DealDamage(attacker, bonusDamage, true); + unit.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_RAID_BOSS_EMOTE, 0, `${player.GetName()} dealt ${bonusDamage} bonus damage!`); + + const remainingHealth = unit.GetHealthPct(); + if (remainingHealth <= 25 && !unit.HasAura(ENRAGE_AURA)) { + unit.AddAura(ENRAGE_AURA, -1); + unit.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_RAID_BOSS_EMOTE, 0, `${unit.GetName()} becomes enraged!`); + } + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_DAMAGE, OnDamage); +``` + +In this example: +1. We define a constant `OWNER_DAMAGE_BONUS` to represent the bonus damage percentage. +2. In the `OnDamage` event handler, we retrieve the attacker's owner using `GetOwner()`. +3. We check if the owner exists and is a player using `IsPlayer()`. +4. If the attacker is owned by a player, we calculate the bonus damage based on the original damage and the `OWNER_DAMAGE_BONUS`. +5. We deal the bonus damage to the unit using `DealDamage()` and send a chat message to the player informing them of the bonus damage dealt. +6. We check the unit's remaining health percentage using `GetHealthPct()`. If it's below 25% and the unit doesn't have the enrage aura, we add the aura using `AddAura()` and send a chat message indicating that the unit becomes enraged. + +This example showcases how `GetOwner()` can be used to determine if a unit is owned by a player and apply specific logic based on that information, such as granting bonus damage and triggering special effects when certain conditions are met. + +## GetOwnerGUID +Returns the GUID (Globally Unique Identifier) of the unit's owner. This method is useful for determining the owner of a pet, totem, or other controlled unit. + +### Parameters +This method does not take any parameters. + +### Returns +- `number` - The GUID of the unit's owner. If the unit has no owner, it returns 0. + +### Example Usage +Here's an example of how to use `GetOwnerGUID()` to check if a unit is a player's pet and grant the player a buff if their pet dies: + +```typescript +const BUFF_ENRAGE_ENTRY = 12880; +const BUFF_ENRAGE_DURATION = 30000; + +const OnPetDeath: creature_event_on_died = (event: number, creature: Creature, killer: Unit) => { + const ownerGUID = creature.GetOwnerGUID(); + + if (ownerGUID !== 0) { + const owner = creature.GetMap().GetPlayer(ownerGUID); + + if (owner) { + // Check if the pet belonged to a player + const isPlayerPet = owner.IsPlayer(); + + if (isPlayerPet) { + // Apply the enrage buff to the player + owner.AddAura(BUFF_ENRAGE_ENTRY, BUFF_ENRAGE_DURATION); + + // Send a message to the player + owner.SendBroadcastMessage(`Your pet has died! You have been granted Enrage for ${BUFF_ENRAGE_DURATION / 1000} seconds.`); + } + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_DIED, (...args) => OnPetDeath(...args)); +``` + +In this example: +1. When a creature dies, the `OnPetDeath` event handler is triggered. +2. It retrieves the owner's GUID using `GetOwnerGUID()`. +3. If the owner's GUID is not 0 (meaning the creature has an owner), it attempts to get the owner as a player using `GetMap().GetPlayer(ownerGUID)`. +4. If the owner is found and is a player (checked using `IsPlayer()`), it means the dead creature was a player's pet. +5. The script then applies the "Enrage" buff to the player using `AddAura()` with the specified entry and duration. +6. Finally, it sends a message to the player informing them about their pet's death and the granted buff. + +This example demonstrates how `GetOwnerGUID()` can be used in conjunction with other methods to implement custom behavior based on the ownership of a unit. + +## GetPetGUID +Returns the GUID of the pet belonging to the unit. This method is useful for identifying and interacting with a unit's pet, such as checking if the pet exists, retrieving pet stats, or performing actions on the pet. + +### Parameters +This method does not take any parameters. + +### Returns +- number: The GUID of the unit's pet. If the unit does not have a pet, the method will return 0. + +### Example Usage +In this example, we'll create a script that checks if a player has a pet and if the pet's health is below 50%. If the condition is met, the script will heal the pet for a certain amount. + +```typescript +const HEAL_AMOUNT = 1000; + +const CheckPetHealth: player_event_on_update = (event: number, player: Player, diff: number) => { + const petGUID = player.GetPetGUID(); + + if (petGUID !== 0) { + const pet = player.GetMap().GetPetOrVehicle(petGUID); + + if (pet) { + const petHealthPct = pet.GetHealthPct(); + + if (petHealthPct < 50) { + pet.SetHealth(pet.GetHealth() + HEAL_AMOUNT); + player.SendBroadcastMessage(`Your pet's health was below 50%. It has been healed for ${HEAL_AMOUNT} health.`); + } + } + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => CheckPetHealth(...args)); +``` + +In this script: +1. We define a constant `HEAL_AMOUNT` to specify the amount of health to heal the pet. +2. Inside the `CheckPetHealth` function, we first retrieve the player's pet GUID using `player.GetPetGUID()`. +3. We check if the pet GUID is not 0, indicating that the player has a pet. +4. If the player has a pet, we use `player.GetMap().GetPetOrVehicle(petGUID)` to retrieve the actual pet object. +5. We calculate the pet's current health percentage using `pet.GetHealthPct()`. +6. If the pet's health percentage is below 50%, we heal the pet using `pet.SetHealth(pet.GetHealth() + HEAL_AMOUNT)`. +7. Finally, we send a broadcast message to the player informing them that their pet has been healed. + +This script demonstrates how to use the `GetPetGUID()` method to identify a player's pet and perform actions based on the pet's state. You can customize the script further by modifying the health threshold, heal amount, or adding additional conditions or actions as needed. + +## GetPower +Returns the current power amount for the specified power type of the unit. + +### Parameters +* type: number - The power type to retrieve the value for. Refer to the Powers enum for possible values. + +### Returns +number - The current power amount for the specified power type. + +### Example Usage +Here's an example of how to use the `GetPower` method to retrieve the current mana and energy of a unit and perform actions based on the values: + +```typescript +const POWER_MANA = 0; +const POWER_ENERGY = 3; + +const OnUnitSpellCast: unit_event_on_spell_cast = (event: number, unit: Unit, spell: number): void => { + const manaPower = unit.GetPower(POWER_MANA); + const energyPower = unit.GetPower(POWER_ENERGY); + + // Check if the unit has enough mana to cast the spell + if (manaPower < 100) { + unit.SendUnitWhisper("Not enough mana to cast the spell!", 0); + unit.InterruptSpell(); + return; + } + + // Check if the unit is a druid and has enough energy for a special ability + if (unit.GetClass() === Classes.CLASS_DRUID && energyPower < 50) { + unit.SendUnitWhisper("Not enough energy for the druid ability!", 0); + unit.InterruptSpell(); + return; + } + + // Consume 10% of the unit's mana on spell cast + const manaConsumption = manaPower * 0.1; + unit.SetPower(POWER_MANA, manaPower - manaConsumption); + + unit.SendUnitWhisper(`Spell cast successfully! Mana consumed: ${manaConsumption}`, 0); +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_SPELL_CAST, (...args) => OnUnitSpellCast(...args)); +``` + +In this example: +1. We define constants for the `POWER_MANA` and `POWER_ENERGY` power types based on the Powers enum. +2. Inside the `OnUnitSpellCast` event handler, we retrieve the current mana and energy power values of the unit using `GetPower`. +3. We check if the unit has enough mana to cast the spell. If not, we interrupt the spell and send a whisper message to the unit. +4. If the unit is a druid (checked using `GetClass`), we additionally check if it has enough energy for a special ability. If not, we interrupt the spell and send a whisper message. +5. If the checks pass, we consume 10% of the unit's mana by calculating the mana consumption and updating the mana power using `SetPower`. +6. Finally, we send a whisper message to the unit indicating that the spell was cast successfully and the amount of mana consumed. + +This example demonstrates how to use `GetPower` to retrieve different power values of a unit and make decisions based on those values, such as interrupting spells or performing class-specific actions. + +## GetPowerPct + +Returns the current power percentage for the specified power type of the unit. + +### Parameters +* type: number - The power type to query the percentage for. Refer to the Powers enum for valid power types. + +### Returns +* number - The power percentage as a value between 0 and 100. + +### Example Usage +Monitor a player's mana percentage and trigger an event when it drops below a certain threshold: + +```typescript +const POWER_TYPE_MANA = 0; +const LOW_MANA_THRESHOLD = 20; + +const OnPlayerManaTick: player_event_on_update = (event: number, player: Player, diff: number) => { + const manaPct = player.GetPowerPct(POWER_TYPE_MANA); + + if (manaPct <= LOW_MANA_THRESHOLD) { + // Trigger a low mana warning for the player + player.SendBroadcastMessage(`Warning: Your mana is low (${manaPct}%)!`); + + // Regenerate a small amount of mana + const maxMana = player.GetMaxPower(POWER_TYPE_MANA); + const regenAmount = maxMana * 0.05; // Regenerate 5% of max mana + player.SetPower(POWER_TYPE_MANA, player.GetPower(POWER_TYPE_MANA) + regenAmount); + + // Apply a mana regeneration buff to the player + const MANA_REGEN_BUFF_ID = 12345; + player.AddAura(MANA_REGEN_BUFF_ID, player); + + // Notify the player about the applied buff + player.SendBroadcastMessage("A mana regeneration buff has been applied to help you recover."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => OnPlayerManaTick(...args)); +``` + +In this example, we register a handler for the `PLAYER_EVENT_ON_UPDATE` event to monitor the player's mana percentage. Inside the event handler, we perform the following steps: + +1. Get the player's current mana percentage using `GetPowerPct(POWER_TYPE_MANA)`. +2. Check if the mana percentage is below the defined threshold (`LOW_MANA_THRESHOLD`). +3. If the mana is low, send a warning message to the player using `SendBroadcastMessage()`. +4. Calculate a small amount of mana to regenerate based on a percentage of the player's maximum mana. +5. Set the player's mana to the current value plus the regeneration amount using `SetPower()`. +6. Apply a mana regeneration buff to the player using `AddAura()` with a predefined buff ID. +7. Notify the player about the applied buff using `SendBroadcastMessage()`. + +This script demonstrates how to utilize the `GetPowerPct()` method to monitor a player's mana level and take actions based on the percentage value. It showcases sending messages to the player, regenerating mana, applying buffs, and interacting with the player's powers. + +## GetPowerType +Returns the current power type of the unit as an enum value. + +### Parameters +None + +### Returns +[Powers](../Globals/Powers.md) - The current power type of the unit. + +### Example Usage +Get the power type of the unit and modify the behavior based on the power type. +```typescript +function ApplyCustomPowerRegen(unit: Unit): void { + const powerType = unit.GetPowerType(); + + switch (powerType) { + case Powers.POWER_MANA: + // Apply custom mana regeneration + const manaRegen = unit.GetStat(UnitFields.STAT_SPIRIT) * 0.05; + unit.SetFloatValue(UnitFields.UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, manaRegen); + break; + case Powers.POWER_RAGE: + // Apply custom rage decay + const rageDecay = 1.5; + unit.SetFloatValue(UnitFields.UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER, -rageDecay); + break; + case Powers.POWER_ENERGY: + // Apply custom energy regeneration + const energyRegen = 10; + unit.SetFloatValue(UnitFields.UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER, energyRegen); + break; + // Add more cases for other power types as needed + default: + break; + } +} + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_SPAWN, (unit: Unit) => { + ApplyCustomPowerRegen(unit); +}); +``` +In this example, we define a function called `ApplyCustomPowerRegen` that takes a `Unit` as a parameter. Inside the function, we call `GetPowerType()` to get the current power type of the unit. + +Based on the power type, we apply different modifications to the unit's power regeneration or decay. For example, if the unit's power type is `POWER_MANA`, we calculate a custom mana regeneration value based on the unit's spirit stat and set it using `SetFloatValue()`. Similarly, for `POWER_RAGE`, we apply a custom rage decay value, and for `POWER_ENERGY`, we set a custom energy regeneration value. + +We then register the `ApplyCustomPowerRegen` function to be called whenever a unit spawns using the `UNIT_EVENT_ON_SPAWN` event. This ensures that the custom power regeneration or decay is applied to units as soon as they spawn in the world. + +This example demonstrates how you can use `GetPowerType()` to retrieve the power type of a unit and perform different actions based on the power type. You can extend this example to handle more power types and apply custom modifications as needed for your specific gameplay mechanics. + +## GetRace + +Returns the race ID of the [Unit](./unit.md). Race IDs are defined in the `ChrRaces.dbc` file and can be used to determine the race of a player, creature, or other unit. + +### Parameters + +This method does not take any parameters. + +### Returns + +* number - The race ID of the unit. + +### Example Usage + +Here's an example of how to use the `GetRace` method to adjust the reward of a quest based on the player's race: + +```typescript +const QUEST_ENTRY = 1234; +const HUMAN_RACE_ID = 1; +const ORC_RACE_ID = 2; + +const OnQuestComplete: player_event_on_quest_complete = (event: number, player: Player, quest: number) => { + if (quest === QUEST_ENTRY) { + const raceId = player.GetRace(); + + if (raceId === HUMAN_RACE_ID) { + // Reward for human players + player.AddItem(1234, 1); // Give an extra item to human players + player.ModifyMoney(100); // Give additional gold to human players + } else if (raceId === ORC_RACE_ID) { + // Reward for orc players + player.AddItem(5678, 1); // Give a different item to orc players + player.ModifyMoney(50); // Give less gold to orc players + } else { + // Default reward for other races + player.ModifyMoney(75); // Give the default amount of gold + } + + player.SendBroadcastMessage("You have completed the quest and received your reward!"); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_QUEST_COMPLETE, (...args) => OnQuestComplete(...args)); +``` + +In this example, when a player completes a specific quest (with ID `1234`), the script checks the player's race using the `GetRace` method. Based on the race ID, it determines the appropriate reward for the player. Human players receive an extra item and additional gold, while orc players receive a different item and less gold. Players of other races receive the default reward of a certain amount of gold. Finally, a broadcast message is sent to the player to notify them of the quest completion and the reward received. + +This example demonstrates how the `GetRace` method can be used to customize quest rewards based on the player's race, providing a more tailored experience for different races in the game. + +## GetRaceAsString +Returns the name of the unit's race in the specified locale or the default locale if not provided. + +### Parameters +* locale?: [LocaleConstant](./constants.md#localeconstant) - (Optional) The locale in which to return the race name. If not provided, the default locale will be used. + +### Returns +* string - The name of the unit's race in the specified or default locale, or nil if the race is not found. + +### Example Usage +```typescript +// Get the race name of a unit in different locales +const unit = player.GetSelection(); +if (unit) { + const defaultRaceName = unit.GetRaceAsString(); + const chineseRaceName = unit.GetRaceAsString(LocaleConstant.LOCALE_zhCN); + const frenchRaceName = unit.GetRaceAsString(LocaleConstant.LOCALE_frFR); + + player.SendBroadcastMessage(`Default race name: ${defaultRaceName}`); + player.SendBroadcastMessage(`Chinese race name: ${chineseRaceName}`); + player.SendBroadcastMessage(`French race name: ${frenchRaceName}`); + + // Check if the race name exists in a specific locale + const locale = LocaleConstant.LOCALE_esES; + const raceNameInLocale = unit.GetRaceAsString(locale); + if (raceNameInLocale) { + player.SendBroadcastMessage(`Race name in ${LocaleConstant[locale]}: ${raceNameInLocale}`); + } else { + player.SendBroadcastMessage(`Race name not found in ${LocaleConstant[locale]}`); + } +} else { + player.SendBroadcastMessage("No unit selected."); +} +``` + +In this example, we retrieve the selected unit using `player.GetSelection()`. If a unit is selected, we demonstrate retrieving the race name in different locales: + +1. We get the race name in the default locale using `unit.GetRaceAsString()` without specifying a locale. +2. We get the race name in Chinese locale using `unit.GetRaceAsString(LocaleConstant.LOCALE_zhCN)`. +3. We get the race name in French locale using `unit.GetRaceAsString(LocaleConstant.LOCALE_frFR)`. + +We then send the retrieved race names to the player using `player.SendBroadcastMessage()`. + +Additionally, we check if the race name exists in a specific locale (Spanish in this example) using `unit.GetRaceAsString(LocaleConstant.LOCALE_esES)`. If the race name is found, we send it to the player. Otherwise, we send a message indicating that the race name was not found in that locale. + +This example demonstrates how to retrieve the race name of a unit in different locales and how to handle cases where the race name may not be available in a specific locale. + +## GetRaceMask +Returns the race mask of the unit. The race mask is a bitmask that represents the races that the unit belongs to. Each bit in the mask corresponds to a specific race. This can be useful for checking if a unit belongs to a certain race or races. + +### Parameters +This method does not take any parameters. + +### Returns +- number: The race mask of the unit. + +### Example Usage +Here's an example of how to use the `GetRaceMask` method to check if a unit belongs to a specific race: + +```typescript +const RACE_MASK_ORC = 0x2; +const RACE_MASK_TROLL = 0x8; + +const OnUnitDeath: creature_event_on_just_died = (event: number, creature: Creature, killer: Unit) => { + const raceMask = killer.GetRaceMask(); + + if ((raceMask & RACE_MASK_ORC) !== 0) { + // The killer belongs to the Orc race + creature.SendUnitSay("You filthy Orc! You will pay for this!", 0); + } else if ((raceMask & RACE_MASK_TROLL) !== 0) { + // The killer belongs to the Troll race + creature.SendUnitSay("Troll scum! My death will be avenged!", 0); + } else { + // The killer belongs to a different race + creature.SendUnitSay("You may have defeated me, but my spirit will live on!", 0); + } + + // Additional logic for handling the creature's death + // ... +}; + +RegisterCreatureEvent(12345, CreatureEvents.CREATURE_EVENT_ON_JUST_DIED, (...args) => OnUnitDeath(...args)); +``` + +In this example, the `OnUnitDeath` event handler is registered for a specific creature with entry ID 12345. When the creature dies, the event handler is triggered, and it checks the race of the killer unit using the `GetRaceMask` method. + +The race mask is compared with predefined constants (`RACE_MASK_ORC` and `RACE_MASK_TROLL`) using bitwise operations to determine if the killer belongs to the Orc or Troll race. Based on the race, the creature sends a different message using the `SendUnitSay` method. + +This example demonstrates how the `GetRaceMask` method can be used in combination with other methods and game events to create dynamic behavior based on the race of the units involved. + +Note: The actual values of the race mask constants (`RACE_MASK_ORC` and `RACE_MASK_TROLL`) may vary depending on the specific game version and configuration. Make sure to use the correct values for your server setup. + +## GetSpeed +Returns the [Unit]'s speed of the given [UnitMoveType]. + +### Parameters +* type: [UnitMoveType](./unitmovetype.md) - The type of movement speed to retrieve. + +### Returns +* number - The speed of the [Unit] for the specified [UnitMoveType]. + +### Example Usage +This example adjusts a player's speed based on their level and the type of movement they are performing. + +```typescript +const PLAYER_LEVEL_THRESHOLD = 50; +const SPEED_MULTIPLIER_BELOW_THRESHOLD = 1.2; +const SPEED_MULTIPLIER_ABOVE_THRESHOLD = 1.5; + +const AdjustPlayerSpeed: player_event_on_update_interval = (event: number, player: Player, diff: number) => { + const playerLevel = player.GetLevel(); + const speedMultiplier = playerLevel < PLAYER_LEVEL_THRESHOLD ? SPEED_MULTIPLIER_BELOW_THRESHOLD : SPEED_MULTIPLIER_ABOVE_THRESHOLD; + + const currentWalkSpeed = player.GetSpeed(UnitMoveType.MOVE_WALK); + const currentRunSpeed = player.GetSpeed(UnitMoveType.MOVE_RUN); + const currentSwimSpeed = player.GetSpeed(UnitMoveType.MOVE_SWIM); + const currentFlightSpeed = player.GetSpeed(UnitMoveType.MOVE_FLIGHT); + + player.SetSpeed(UnitMoveType.MOVE_WALK, currentWalkSpeed * speedMultiplier); + player.SetSpeed(UnitMoveType.MOVE_RUN, currentRunSpeed * speedMultiplier); + player.SetSpeed(UnitMoveType.MOVE_SWIM, currentSwimSpeed * speedMultiplier); + player.SetSpeed(UnitMoveType.MOVE_FLIGHT, currentFlightSpeed * speedMultiplier); + + player.SendNotification(`Your speed has been adjusted based on your level. Current multiplier: ${speedMultiplier}`); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE_INTERVAL, (...args) => AdjustPlayerSpeed(...args)); +``` + +In this example: +1. We define constants for the player level threshold and the speed multipliers for players below and above the threshold. +2. We register a player event that triggers at a specified interval using `PLAYER_EVENT_ON_UPDATE_INTERVAL`. +3. Inside the event handler, we retrieve the player's current level using `player.GetLevel()`. +4. We determine the speed multiplier based on the player's level by comparing it with the defined threshold. +5. We retrieve the player's current speeds for different movement types using `player.GetSpeed()` with the respective [UnitMoveType](./unitmovetype.md) values. +6. We adjust the player's speeds by multiplying the current speeds with the determined speed multiplier using `player.SetSpeed()`. +7. Finally, we send a notification to the player informing them about the speed adjustment and the current multiplier. + +This example demonstrates how to retrieve and modify a player's movement speeds based on their level, providing a more dynamic gameplay experience. + +## GetStandState +Returns the current stand state of the unit. The stand state represents the unit's posture or stance, such as standing, sitting, or lying down. + +### Parameters +This method does not take any parameters. + +### Returns +state: number - The current stand state of the unit, represented as a numeric value. + +The possible stand state values are: +- 0: UNIT_STAND_STATE_STAND (Standing) +- 1: UNIT_STAND_STATE_SIT (Sitting) +- 2: UNIT_STAND_STATE_SIT_CHAIR (Sitting in a chair) +- 3: UNIT_STAND_STATE_SLEEP (Sleeping) +- 4: UNIT_STAND_STATE_SIT_LOW_CHAIR (Sitting in a low chair) +- 5: UNIT_STAND_STATE_SIT_MEDIUM_CHAIR (Sitting in a medium chair) +- 6: UNIT_STAND_STATE_SIT_HIGH_CHAIR (Sitting in a high chair) +- 7: UNIT_STAND_STATE_DEAD (Dead) +- 8: UNIT_STAND_STATE_KNEEL (Kneeling) + +### Example Usage +Create a script that checks the stand state of the player's target and performs different actions based on the state. + +```typescript +const onPlayerTargetUnit: player_event_on_target = (event: number, player: Player, target: Unit) => { + const standState = target.GetStandState(); + + switch (standState) { + case 0: // Standing + player.SendBroadcastMessage(`Your target, ${target.GetName()}, is standing.`); + break; + case 1: // Sitting + player.SendBroadcastMessage(`Your target, ${target.GetName()}, is sitting.`); + player.CastSpell(target, 12345, true); // Cast a spell on the sitting target + break; + case 3: // Sleeping + player.SendBroadcastMessage(`Your target, ${target.GetName()}, is sleeping. Shhh!`); + player.AddAura(23456, target); // Add a sleep debuff to the sleeping target + break; + case 7: // Dead + player.SendBroadcastMessage(`Your target, ${target.GetName()}, is dead.`); + player.CastSpell(target, 34567, true); // Cast a resurrection spell on the dead target + break; + default: + player.SendBroadcastMessage(`Your target, ${target.GetName()}, is in an unusual state.`); + break; + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_TARGET, (...args) => onPlayerTargetUnit(...args)); +``` + +In this example, when a player targets a unit, the script checks the stand state of the target using `GetStandState()`. Depending on the stand state, different actions are taken: +- If the target is standing, a message is sent to the player indicating the target's state. +- If the target is sitting, a message is sent, and a spell with ID 12345 is cast on the target. +- If the target is sleeping, a message is sent, and a sleep debuff with ID 23456 is added to the target. +- If the target is dead, a message is sent, and a resurrection spell with ID 34567 is cast on the target. +- For any other stand state, a default message is sent to the player. + +This script demonstrates how `GetStandState()` can be used to determine the current posture of a unit and perform specific actions based on that state. + +## GetStat +Retrieves the value of a specific stat for the unit. + +### Parameters +* statType: number - The ID of the stat to retrieve. Possible values: + * 0 - UNIT_MOD_STAT_STRENGTH + * 1 - UNIT_MOD_STAT_AGILITY + * 2 - UNIT_MOD_STAT_STAMINA + * 3 - UNIT_MOD_STAT_INTELLECT + * 4 - UNIT_MOD_STAT_SPIRIT + +### Returns +* number - The current value of the specified stat for the unit. + +### Example Usage +```typescript +const UNIT_MOD_STAT_STRENGTH = 0; +const UNIT_MOD_STAT_AGILITY = 1; +const UNIT_MOD_STAT_STAMINA = 2; +const UNIT_MOD_STAT_INTELLECT = 3; +const UNIT_MOD_STAT_SPIRIT = 4; + +const ApplyCustomStatModifier = (unit: Unit) => { + const className = unit.GetClass(); + let statModifier = 1; + + switch (className) { + case 1: // Warrior + statModifier = unit.GetStat(UNIT_MOD_STAT_STRENGTH) * 0.05; + break; + case 2: // Paladin + statModifier = (unit.GetStat(UNIT_MOD_STAT_STRENGTH) + unit.GetStat(UNIT_MOD_STAT_INTELLECT)) * 0.025; + break; + case 3: // Hunter + statModifier = unit.GetStat(UNIT_MOD_STAT_AGILITY) * 0.05; + break; + case 4: // Rogue + statModifier = unit.GetStat(UNIT_MOD_STAT_AGILITY) * 0.05; + break; + case 5: // Priest + statModifier = unit.GetStat(UNIT_MOD_STAT_INTELLECT) * 0.05; + break; + // Add other class cases as needed + } + + unit.SetModifierValue(UnitMods.UNIT_MOD_DAMAGE_MAINHAND, BASE_VALUE, unit.GetModifierValue(UnitMods.UNIT_MOD_DAMAGE_MAINHAND, BASE_VALUE) * statModifier); + unit.SetModifierValue(UnitMods.UNIT_MOD_DAMAGE_OFFHAND, BASE_VALUE, unit.GetModifierValue(UnitMods.UNIT_MOD_DAMAGE_OFFHAND, BASE_VALUE) * statModifier); +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_SPAWN, ApplyCustomStatModifier); +``` + +In this example, we define a function `ApplyCustomStatModifier` that takes a `Unit` object as a parameter. The function retrieves the class of the unit using `GetClass()` and then applies a custom stat modifier based on the class. + +The stat modifier is calculated by multiplying a specific stat value (strength for warriors and paladins, agility for hunters and rogues, intellect for priests) by a percentage factor. The `GetStat()` method is used to retrieve the value of the desired stat based on the provided stat type constants. + +Finally, the calculated stat modifier is applied to the unit's main hand and off-hand damage values using `SetModifierValue()`. + +The `RegisterUnitEvent` function is used to register the `ApplyCustomStatModifier` function to be called whenever a unit spawns (using the `UNIT_EVENT_ON_SPAWN` event). + +This example demonstrates how to use `GetStat()` to retrieve specific stat values for a unit and apply custom modifications based on those values. + +## GetUnfriendlyUnitsInRange +Returns a table containing unfriendly [Unit](./unit.md)'s within the given range of the [Unit](./unit.md). + +### Parameters +* range: number - (Optional) The range to search for unfriendly units. If not provided, the default range is the [Unit](./unit.md)'s current combat reach. + +### Returns +* table: table - A table containing the unfriendly [Unit](./unit.md)'s found within the specified range. + +### Example Usage +This example demonstrates how to use the `GetUnfriendlyUnitsInRange` method to find nearby enemy units and cast a spell on them. + +```typescript +const SPELL_ARCANE_EXPLOSION = 1449; +const ARCANE_EXPLOSION_RANGE = 10; + +const CastArcaneExplosion: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + const unfriendlyUnits = player.GetUnfriendlyUnitsInRange(ARCANE_EXPLOSION_RANGE); + + if (unfriendlyUnits.length >= 3) { + player.CastSpell(player, SPELL_ARCANE_EXPLOSION, true); + player.SendBroadcastMessage("Casting Arcane Explosion on nearby enemies!"); + + for (const unit of unfriendlyUnits) { + const unitName = unit.GetName(); + const distance = player.GetDistance(unit); + player.SendBroadcastMessage(`Found enemy: ${unitName} at distance: ${distance} yards`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => CastArcaneExplosion(...args)); +``` + +In this example: +1. We define constants for the Arcane Explosion spell ID and its range. +2. Inside the `CastArcaneExplosion` function, we use `GetUnfriendlyUnitsInRange` to find all unfriendly units within the specified range. +3. If there are 3 or more unfriendly units nearby, we cast Arcane Explosion on the player, which will damage all nearby enemies. +4. We send a broadcast message to the player indicating that Arcane Explosion is being cast. +5. We iterate over the unfriendly units and send a broadcast message to the player with the name and distance of each enemy unit. +6. Finally, we register the `CastArcaneExplosion` function to be called whenever the player enters combat using the `PLAYER_EVENT_ON_ENTER_COMBAT` event. + +This example showcases how `GetUnfriendlyUnitsInRange` can be used to dynamically respond to the presence of multiple enemy units and take appropriate actions, such as casting area-of-effect spells or notifying the player about nearby threats. + +## GetVehicle +Returns the vehicle that the unit is currently controlling. + +### Parameters +None + +### Returns +[Vehicle](./vehicle.md) or `undefined` - The vehicle the unit is currently controlling or `undefined` if the unit is not controlling a vehicle. + +### Example Usage +This example demonstrates how to check if a player is currently controlling a vehicle and if so, get the vehicle's entry ID. + +```typescript +const OnPlayerEnterVehicle: player_event_on_enter_vehicle = (event: number, player: Player, vehicle: Vehicle) => { + const controlledVehicle = player.GetVehicle(); + + if (controlledVehicle) { + const vehicleEntry = controlledVehicle.GetEntry(); + switch (vehicleEntry) { + case 30234: // Wintergrasp Siege Engine + SendSystemMessage(player, "You are now controlling a Wintergrasp Siege Engine!"); + break; + case 33060: // Salvaged Demolisher + SendSystemMessage(player, "You are now controlling a Salvaged Demolisher!"); + break; + case 33109: // Salvaged Siege Engine + SendSystemMessage(player, "You are now controlling a Salvaged Siege Engine!"); + break; + default: + SendSystemMessage(player, `You are now controlling a vehicle with entry ID: ${vehicleEntry}`); + break; + } + } else { + SendSystemMessage(player, "You are not controlling any vehicle."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_VEHICLE, (...args) => OnPlayerEnterVehicle(...args)); +``` + +In this example, when a player enters a vehicle, the script checks if the player is controlling a vehicle using the `GetVehicle()` method. If the player is controlling a vehicle, the script retrieves the vehicle's entry ID using the `GetEntry()` method of the returned [Vehicle](./vehicle.md) object. + +Based on the vehicle's entry ID, the script sends a specific message to the player informing them about the type of vehicle they are controlling. If the vehicle's entry ID doesn't match any of the specified cases, a generic message is sent with the vehicle's entry ID. + +If the player is not controlling any vehicle, the script sends a message indicating that the player is not controlling any vehicle. + +This example showcases how to utilize the `GetVehicle()` method to determine if a unit is controlling a vehicle and retrieve information about the controlled vehicle for further processing or interaction within the script. + +## GetVehicleKit +Returns the [Vehicle](./vehicle.md) methods associated with the [Unit]. This allows you to access and manipulate the vehicle's properties and behavior. + +### Parameters +None + +### Returns +[Vehicle](./vehicle.md) - The vehicle methods associated with the unit. + +### Example Usage +In this example, we'll create a script that automatically repairs a player's vehicle when they enter it, and sets its health to full. + +```typescript +const onEnterVehicle: vehicle_event_on_enter = (event: number, vehicle: Vehicle, passenger: Unit, seatId: number) => { + if (passenger instanceof Player) { + const vehicleKit = passenger.GetVehicleKit(); + if (vehicleKit) { + const maxHealth = vehicleKit.GetBase().GetMaxHealth(); + const currentHealth = vehicleKit.GetBase().GetHealth(); + + if (currentHealth < maxHealth) { + vehicleKit.GetBase().SetHealth(maxHealth); + passenger.SendBroadcastMessage("Your vehicle has been fully repaired!"); + } + + const seats = vehicleKit.GetAvailableSeatCount(); + for (let i = 0; i < seats; i++) { + const passenger = vehicleKit.GetPassenger(i); + if (passenger) { + passenger.SendBroadcastMessage("Welcome aboard!"); + } + } + } + } +}; + +RegisterVehicleEvent(VehicleEvents.VEHICLE_EVENT_ON_ENTER, (...args) => onEnterVehicle(...args)); +``` + +In this script: +1. We register a callback function `onEnterVehicle` to the `VEHICLE_EVENT_ON_ENTER` event. +2. When a passenger enters a vehicle, we check if the passenger is a player using `instanceof Player`. +3. If the passenger is a player, we get the vehicle methods using `passenger.GetVehicleKit()`. +4. We check if the vehicle exists by checking if `vehicleKit` is truthy. +5. If the vehicle exists, we get its maximum health using `vehicleKit.GetBase().GetMaxHealth()` and current health using `vehicleKit.GetBase().GetHealth()`. +6. If the current health is less than the maximum health, we set the vehicle's health to full using `vehicleKit.GetBase().SetHealth(maxHealth)` and send a message to the player informing them that their vehicle has been repaired. +7. We get the number of available seats in the vehicle using `vehicleKit.GetAvailableSeatCount()`. +8. We iterate over each seat and check if there's a passenger in it using `vehicleKit.GetPassenger(i)`. +9. If there's a passenger in the seat, we send them a welcome message using `passenger.SendBroadcastMessage()`. + +This script demonstrates how to use the `GetVehicleKit()` method to access and manipulate a unit's vehicle properties, such as repairing the vehicle and interacting with passengers. + +## GetVictim +Returns the current victim target of the [Unit]. If the unit is not in combat or does not have a target, this method will return `nil`. + +### Parameters +None + +### Returns +[Unit](./unit.md) | nil - Returns the [Unit] that is being attacked by this unit, or `nil` if no valid target exists. + +### Example Usage +This example demonstrates how to use `GetVictim()` in a script that checks if a creature's health percentage is below a certain threshold, and if so, it will cast a self-heal spell on itself. + +```typescript +const CREATURE_ENTRY_ID = 1234; +const HEALTH_THRESHOLD = 30; +const SELF_HEAL_SPELL_ID = 5678; + +const CreatureHealthCheck: creature_event_on_update = (event: number, creature: Creature, diff: number) => { + const victim = creature.GetVictim(); + + if (victim) { + const healthPct = creature.GetHealthPct(); + + if (healthPct <= HEALTH_THRESHOLD) { + const spellInfo = GetSpellInfo(SELF_HEAL_SPELL_ID); + + if (spellInfo && creature.HasSpell(SELF_HEAL_SPELL_ID)) { + creature.CastSpell(creature, SELF_HEAL_SPELL_ID, false); + creature.MonsterSay(`I'm healing myself! My health is at ${healthPct}%`, 0); + } else { + console.log(`Creature ${CREATURE_ENTRY_ID} does not have the self-heal spell ${SELF_HEAL_SPELL_ID}`); + } + } + } +}; + +RegisterCreatureEvent(CREATURE_ENTRY_ID, CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => CreatureHealthCheck(...args)); +``` + +In this example: + +1. We define constants for the creature entry ID, health threshold percentage, and the self-heal spell ID. +2. We create a function `CreatureHealthCheck` that will be triggered on the `CREATURE_EVENT_ON_UPDATE` event for the specified creature entry ID. +3. Inside the function, we use `creature.GetVictim()` to get the current victim target of the creature. +4. If a valid victim exists, we check the creature's current health percentage using `creature.GetHealthPct()`. +5. If the health percentage is below or equal to the defined `HEALTH_THRESHOLD`, we proceed to check if the creature has the self-heal spell using `creature.HasSpell(SELF_HEAL_SPELL_ID)`. +6. If the creature has the spell, we cast it on the creature itself using `creature.CastSpell(creature, SELF_HEAL_SPELL_ID, false)` and make the creature say a message indicating its current health percentage. +7. If the creature does not have the self-heal spell, we log a message to the console. + +This example showcases how `GetVictim()` can be used in combination with other methods like `GetHealthPct()`, `HasSpell()`, and `CastSpell()` to create a script that makes a creature cast a self-heal spell when its health drops below a certain threshold while in combat with a victim target. + +## HandleStatModifier + +Modifies a specific stat of the [Unit] by applying or removing a modifier of a specified type and value. + +### Parameters +- `stat`: [StatModType](../enums/StatModType.md) - The stat to modify (e.g., STAT_MOD_STRENGTH, STAT_MOD_AGILITY, etc.). +- `type`: [StatModifierType](../enums/StatModifierType.md) - The type of modifier to apply (e.g., FLAT_MOD, PCT_MOD, etc.). +- `value`: number - The value to apply to the stat. Positive values will increase the stat, while negative values will decrease it. +- `apply`: boolean (optional, default: false) - Whether the modifier should be applied (true) or removed (false). + +### Returns +- boolean: Whether the stat modification was successful. + +### Example Usage +```typescript +const BLESSING_OF_KINGS_SPELL_ID = 25898; +const BLESSING_OF_KINGS_STAT_PCT_MOD = 10; + +const ApplyBlessingOfKings: player_event_on_login = (event: number, player: Player) => { + const blessingOfKings = player.GetAura(BLESSING_OF_KINGS_SPELL_ID); + + if (!blessingOfKings) { + // Apply Blessing of Kings if the player doesn't have it + if (player.CastSpell(player, BLESSING_OF_KINGS_SPELL_ID, true)) { + // Modify the player's stats by 10% when Blessing of Kings is applied + const stats = [StatModType.STAT_MOD_STRENGTH, StatModType.STAT_MOD_AGILITY, StatModType.STAT_MOD_STAMINA, StatModType.STAT_MOD_INTELLECT, StatModType.STAT_MOD_SPIRIT]; + for (const stat of stats) { + player.HandleStatModifier(stat, StatModifierType.PCT_MOD, BLESSING_OF_KINGS_STAT_PCT_MOD, true); + } + } + } else { + // Remove the stat modifiers if Blessing of Kings is removed + if (blessingOfKings.GetStackAmount() === 1 && player.RemoveAura(BLESSING_OF_KINGS_SPELL_ID)) { + const stats = [StatModType.STAT_MOD_STRENGTH, StatModType.STAT_MOD_AGILITY, StatModType.STAT_MOD_STAMINA, StatModType.STAT_MOD_INTELLECT, StatModType.STAT_MOD_SPIRIT]; + for (const stat of stats) { + player.HandleStatModifier(stat, StatModifierType.PCT_MOD, BLESSING_OF_KINGS_STAT_PCT_MOD, false); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => ApplyBlessingOfKings(...args)); +``` + +In this example, when a player logs in, the script checks if the player has the Blessing of Kings aura. If not, it casts Blessing of Kings on the player and applies a 10% modifier to the player's strength, agility, stamina, intellect, and spirit stats using the `HandleStatModifier` method. If the player already has Blessing of Kings and it is removed, the script removes the stat modifiers accordingly. + +## HasAura +Determines whether the unit has a specific aura active by checking for the aura's spell ID. + +### Parameters +- spell: number - The spell ID of the aura to check for. + +### Returns +- boolean - Returns true if the unit has the specified aura active, false otherwise. + +### Example Usage +In this example, we'll create a script that checks if a player has the "Blessing of Kings" aura when they enter combat. If they don't have the aura, we'll apply it to them and send them a message. + +```typescript +const BLESSING_OF_KINGS_SPELL_ID = 25898; + +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + if (!player.HasAura(BLESSING_OF_KINGS_SPELL_ID)) { + const blessingOfKings = player.AddAura(BLESSING_OF_KINGS_SPELL_ID, player); + if (blessingOfKings) { + player.SendBroadcastMessage("You have been blessed with the Blessing of Kings!"); + } else { + player.SendBroadcastMessage("Failed to apply Blessing of Kings. Please report this issue."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script: +1. We define the spell ID for "Blessing of Kings" as a constant. +2. When the player enters combat, we use the `HasAura()` method to check if the player already has the "Blessing of Kings" aura active. +3. If the player doesn't have the aura, we use the `AddAura()` method to apply the aura to the player. +4. If the aura is successfully applied, we send a message to the player informing them that they have received the Blessing of Kings. +5. If the aura fails to apply, we send an error message to the player, asking them to report the issue. +6. Finally, we register the `onEnterCombat` function to be called whenever the `PLAYER_EVENT_ON_ENTER_COMBAT` event is triggered. + +By using the `HasAura()` method, we can easily check if a unit has a specific aura active and take appropriate actions based on the result. + +## HasUnitState +Returns a boolean value indicating whether the unit has a specific unit state flag set. + +### Parameters +- state: number - The unit state flag to check. Refer to the UnitState enum for possible values. + +### Returns +- boolean - Returns true if the unit has the specified unit state flag set, false otherwise. + +### Example Usage +Suppose you want to create a script that checks if a unit is confused and then removes the confused state from the unit. + +```typescript +const UnitState = { + UNIT_STATE_CONFUSED: 0x00000001, + // ... other unit states +}; + +function RemoveConfusion(unit: Unit): void { + if (unit.HasUnitState(UnitState.UNIT_STATE_CONFUSED)) { + // Remove the confused state from the unit + unit.ClearUnitState(UnitState.UNIT_STATE_CONFUSED); + + // You can also perform additional actions here, such as: + // - Sending a message to the unit + unit.SendUnitWhisper("You are no longer confused!", 0); + + // - Applying a beneficial spell or effect to the unit + const spellId = 12345; // Replace with the actual spell ID + unit.CastSpell(unit, spellId, true); + + // - Modifying the unit's movement speed or other attributes + const movementSpeed = 1.5; // Increase movement speed by 50% + unit.SetSpeed(UnitMoveType.MOVE_RUN, movementSpeed); + + // - Triggering a visual effect or animation on the unit + const effectId = 567; // Replace with the actual effect ID + unit.PlayDirectSound(effectId); + + // - Logging the event or performing further checks + console.log(`Removed confusion from unit ${unit.GetName()}`); + } +} + +// Usage: Call the RemoveConfusion function with a unit object +const targetUnit = GetUnit(123); // Replace with the actual unit retrieval logic +RemoveConfusion(targetUnit); +``` + +In this example, the `HasUnitState` method is used to check if the unit has the `UNIT_STATE_CONFUSED` flag set. If the unit is indeed confused, the script proceeds to remove the confused state using the `ClearUnitState` method. + +Additionally, the script demonstrates various other actions that can be performed on the unit after removing the confused state, such as sending a whisper message, casting a beneficial spell, modifying movement speed, playing a visual effect, and logging the event. + +Remember to replace the placeholder values (e.g., spell ID, effect ID) with the actual values relevant to your specific use case. + +By utilizing the `HasUnitState` method, you can create more complex scripts that check for specific unit states and perform appropriate actions based on the unit's current state. + +## HealthAbovePct +Returns a boolean value indicating whether the [Unit]'s current health is above the specified percentage of their maximum health. + +### Parameters +* healthpct: number - The health percentage to check against (0-100) + +### Returns +* boolean - True if the [Unit]'s current health is above the specified percentage, false otherwise + +### Example Usage +In this example, we'll create a script that will check if a player's target is below 20% health. If the target is a creature and below 20% health, the creature will flee for assistance. + +```typescript +const FLEE_FOR_ASSISTANCE_SPELL_ID = 8599; + +const OnHitUnit: player_event_on_hit_unit = (event: number, player: Player, target: Unit) => { + if (target.IsCreature()) { + const creature = target.ToCreature(); + + if (!creature.HealthAbovePct(20)) { + // Check if the creature is already fleeing + if (!creature.HasAura(FLEE_FOR_ASSISTANCE_SPELL_ID)) { + // Creature's health is below 20%, cast Flee For Assistance + creature.CastSpell(creature, FLEE_FOR_ASSISTANCE_SPELL_ID, true); + + // Say a random flee message + const fleeMessages = [ + "I need backup!", + "Help me, brothers!", + "I can't take this alone!", + "I'm outta here!" + ]; + const randomMessage = fleeMessages[Math.floor(Math.random() * fleeMessages.length)]; + creature.SendUnitSay(randomMessage, 0); + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_HIT_UNIT, (...args) => OnHitUnit(...args)); +``` + +In this script: +1. We define the spell ID for the "Flee For Assistance" ability, which causes creatures to run away and seek help from nearby allies. +2. In the `OnHitUnit` event, we check if the player's target is a creature using `target.IsCreature()`. +3. If the target is a creature, we use `HealthAbovePct(20)` to check if the creature's health is below 20%. +4. If the creature's health is below 20% and it doesn't already have the "Flee For Assistance" aura (checked using `HasAura()`), we proceed to cast the spell on the creature using `CastSpell()`. +5. We then select a random flee message from an array of predefined messages and make the creature say it using `SendUnitSay()`. + +This script adds a dynamic element to creature behavior, making them flee and call for help when they are near death, enhancing the overall gameplay experience. + +## HealthBelowPct +Returns true if the [Unit]'s current health is below the specified percentage of their maximum health. + +### Parameters +* healthpct: number - The health percentage to check against. Value between 0 and 100. + +### Returns +* boolean - True if the [Unit]'s health is below the specified percentage, false otherwise. + +### Example Usage +In this example, we'll create a script that checks if the player's health drops below 20% during combat. If it does, the script will heal the player for a percentage of their maximum health and send them a message. + +```typescript +const HEAL_PERCENT = 0.3; + +const checkHealth: player_event_on_damage = (event: number, player: Player, attacker: Unit, damage: number, spell: Spell) => { + const healthPct = 20; + + if (player.HealthBelowPct(healthPct)) { + const maxHealth = player.GetMaxHealth(); + const healAmount = Math.floor(maxHealth * HEAL_PERCENT); + + player.SetHealth(player.GetHealth() + healAmount); + player.SendBroadcastMessage(`You have been healed for ${healAmount} health!`); + + const logMessage = `Player ${player.GetName()} was healed for ${healAmount} health when below ${healthPct}% health.`; + console.log(logMessage); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DAMAGE, (...args) => checkHealth(...args)); +``` + +In this script: +1. We define a constant `HEAL_PERCENT` to determine the percentage of the player's maximum health to heal. +2. In the `checkHealth` function, we check if the player's health is below 20% using the `HealthBelowPct` method. +3. If the condition is true, we calculate the player's maximum health and the heal amount based on the `HEAL_PERCENT`. +4. We set the player's health to their current health plus the heal amount using the `SetHealth` method. +5. We send a message to the player informing them of the heal using the `SendBroadcastMessage` method. +6. We log a message to the console for debugging purposes. +7. Finally, we register the `checkHealth` function to the `PLAYER_EVENT_ON_DAMAGE` event to execute the script whenever the player takes damage. + +This script demonstrates how to use the `HealthBelowPct` method to check if a unit's health falls below a certain percentage and perform actions based on that condition. + +## InterruptSpell +Interrupts the unit's spell state, casting, etc. If the spell is not interruptible, the method will return without interrupting the spell. + +### Parameters +* spellType: number - The type of spell to interrupt. Possible values: + * 0 - Current autorepeat spell + * 1 - Current channeled spell + * 2 - Current generic spell + * 3 - Current autorepeat spell, current channeled spell, and current generic spell +* delayed: boolean (optional) - If 'true', the method will wait for the next spell update to interrupt the spell. Default value is 'false'. + +### Example Usage +Interrupt a boss's channeled spell when a certain condition is met: +```typescript +const BOSS_ENTRY = 12345; +const CHANNELED_SPELL_ID = 54321; + +const onSpellCast: creature_event_on_spell_cast = (event: number, creature: Creature, target: Unit, spellId: number): void => { + if (creature.GetEntry() === BOSS_ENTRY && spellId === CHANNELED_SPELL_ID) { + const healthPercent = creature.GetHealthPct(); + if (healthPercent <= 30) { + creature.InterruptSpell(1); + creature.SendUnitYell("My channeling has been interrupted!", 0); + creature.CastSpell(creature, 98765, true); // Cast a special ability after the interruption + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPELL_CAST, (...args) => onSpellCast(...args)); +``` + +In this example, when the boss creature starts casting a specific channeled spell (identified by `CHANNELED_SPELL_ID`), the script checks the boss's health percentage. If the health is at or below 30%, the script interrupts the channeled spell using `creature.InterruptSpell(1)`. The boss then yells and casts a special ability as a response to the interruption. + +This script showcases how to use the `InterruptSpell` method in a more complex scenario, where the interruption is triggered by a specific condition (boss's health) and is followed by additional actions (yelling and casting another spell). + +## IsAlive +Returns a boolean value indicating whether the unit is currently alive or not. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is alive, `false` otherwise. + +### Example Usage +In this example, we create a script that checks if the player is alive before attempting to cast a spell. If the player is not alive, it will send a message to the player indicating that they cannot cast spells while dead. + +```typescript +const SPELL_ID = 12345; // Replace with the desired spell ID + +const OnPlayerCastSpell: player_event_on_cast_spell = (event: number, player: Player, spell: Spell): void => { + if (!player.IsAlive()) { + player.SendBroadcastMessage("You cannot cast spells while dead!"); + player.InterruptSpell(CurrentSpellTypes.CURRENT_AUTOREPEAT_SPELL); + player.InterruptSpell(CurrentSpellTypes.CURRENT_CHANNELED_SPELL); + player.InterruptSpell(CurrentSpellTypes.CURRENT_GENERIC_SPELL); + player.InterruptSpell(CurrentSpellTypes.CURRENT_MELEE_SPELL); + player.InterruptSpell(CurrentSpellTypes.CURRENT_SPELL); + return; + } + + // Additional logic for when the player is alive and casting a spell + // ... +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CAST_SPELL, (...args) => OnPlayerCastSpell(...args)); +``` + +In this script: +1. We define the `OnPlayerCastSpell` function that takes the event type, player, and spell as parameters. +2. Inside the function, we first check if the player is alive using the `IsAlive()` method. +3. If the player is not alive, we send a broadcast message to the player indicating that they cannot cast spells while dead. +4. We then interrupt all the spells that the player might be casting using the `InterruptSpell()` method for various spell types. +5. If the player is alive, the script continues with any additional logic you want to implement when the player is casting a spell. +6. Finally, we register the `OnPlayerCastSpell` function to be triggered whenever the `PLAYER_EVENT_ON_CAST_SPELL` event occurs using the `RegisterPlayerEvent()` function. + +This script ensures that players cannot cast spells while they are dead and provides appropriate feedback to the player when they attempt to do so. + +## IsArmorer +This method checks if the Unit is an armorer NPC that can repair equipment. + +### Parameters +None + +### Returns +boolean - Returns `true` if the Unit is an armorer, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsArmorer()` method to check if a creature is an armorer and provide a repair service to players. + +```typescript +const ARMORER_ENTRY = 12345; // Replace with the actual entry of the armorer NPC + +const onGossipHello: creature_event_on_gossip_hello = (event: number, player: Player, creature: Creature) => { + if (creature.GetEntry() === ARMORER_ENTRY && creature.IsArmorer()) { + player.GossipMenuAddItem(0, "I would like to repair my equipment.", 0, 1); + player.GossipSendMenu(1, creature.GetGUID()); + } else { + player.GossipSendMenu(2, creature.GetGUID()); + } +}; + +const onGossipSelect: creature_event_on_gossip_select = (event: number, player: Player, creature: Creature, sender: number, action: number) => { + if (creature.GetEntry() === ARMORER_ENTRY && action === 1) { + player.GossipClearMenu(); + + const repairCost = player.DurabilityRepairAll(true, 0, false); + if (repairCost <= 0) { + player.GossipMenuAddItem(0, "You have no damaged equipment to repair.", 0, 2); + } else if (player.GetMoney() < repairCost) { + player.GossipMenuAddItem(0, "You don't have enough money to repair your equipment.", 0, 2); + } else { + player.ModifyMoney(-repairCost); + player.DurabilityRepairAll(false, 0, false); + player.GossipMenuAddItem(0, "Your equipment has been repaired.", 0, 2); + } + + player.GossipSendMenu(1, creature.GetGUID()); + } else { + player.GossipComplete(); + } +}; + +RegisterCreatureEvent(ARMORER_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, (...args) => onGossipHello(...args)); +RegisterCreatureEvent(ARMORER_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_SELECT, (...args) => onGossipSelect(...args)); +``` + +In this example, when a player interacts with an armorer NPC (identified by its entry), the script checks if the creature is indeed an armorer using the `IsArmorer()` method. If it is, the player is presented with a gossip option to repair their equipment. + +When the player selects the repair option, the script calculates the repair cost using `DurabilityRepairAll()` with the `cost` parameter set to `true`. If the player has no damaged equipment or insufficient funds, appropriate messages are displayed. Otherwise, the player's money is deducted, and their equipment is repaired using `DurabilityRepairAll()` with the `cost` parameter set to `false`. + +This example demonstrates how the `IsArmorer()` method can be used in conjunction with other methods to create a functional repair service provided by an armorer NPC. + +## IsAttackingPlayer +Returns true if the [Unit] is currently attacking a player, false otherwise. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - true if the [Unit] is attacking a player, false otherwise. + +### Example Usage +This example demonstrates how to use the `IsAttackingPlayer` method to check if a creature is attacking a player and if so, cast a spell on the player. + +```typescript +const CREATURE_ENTRY = 1234; +const SPELL_ID = 5678; + +const CreatureAttackStart: creature_event_on_enter_combat = (event: number, creature: Creature, target: Unit) => { + if (creature.GetEntry() === CREATURE_ENTRY && target.IsPlayer()) { + const player = target.ToPlayer(); + if (creature.IsAttackingPlayer()) { + creature.CastSpell(player, SPELL_ID, true); + creature.SendUnitWhisper("You dare attack me, mortal? Feel my wrath!", player); + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_ENTER_COMBAT, (...args) => CreatureAttackStart(...args)); +``` + +In this example: +1. We define constants for the creature entry and the spell ID that we want to use. +2. We register a creature event handler for the `CREATURE_EVENT_ON_ENTER_COMBAT` event. +3. In the event handler, we first check if the creature that entered combat has the entry we're interested in and if the target is a player. +4. If the creature is attacking a player (checked using `IsAttackingPlayer`), we cast a spell on the player using `CastSpell` and send a whisper to the player using `SendUnitWhisper`. + +This script can be useful for creating custom creature behaviors when they enter combat with players, such as casting specific spells or sending taunting messages. + +## IsAuctioneer +Returns true if the [Unit] is an auctioneer NPC. + +### Parameters +None + +### Returns +boolean - Returns `true` if the [Unit] is an auctioneer, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsAuctioneer()` method to create an auctioneer NPC that provides additional functionality to players. + +```typescript +const AUCTIONEER_ENTRY = 12345; // Replace with the actual auctioneer NPC entry ID + +const OnGossipHello: npc_event_on_gossip_hello = (event: number, player: Player, creature: Creature) => { + if (creature.GetEntry() === AUCTIONEER_ENTRY && creature.IsAuctioneer()) { + player.GossipMenuAddItem(0, "Show my auction sales", 0, 1); + player.GossipMenuAddItem(0, "Collect unsold items", 0, 2); + player.GossipMenuAddItem(0, "Collect auction proceeds", 0, 3); + player.GossipSendMenu(1, creature.GetGUID()); + } +}; + +const OnGossipSelect: npc_event_on_gossip_select = (event: number, player: Player, creature: Creature, sender: number, action: number) => { + if (creature.GetEntry() === AUCTIONEER_ENTRY && creature.IsAuctioneer()) { + if (action === 1) { + // Show the player's auction sales + // Implementation details omitted for brevity + player.GossipComplete(); + } else if (action === 2) { + // Collect unsold items for the player + // Implementation details omitted for brevity + player.GossipComplete(); + } else if (action === 3) { + // Collect auction proceeds for the player + // Implementation details omitted for brevity + player.GossipComplete(); + } + } +}; + +RegisterCreatureEvent(AUCTIONEER_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, OnGossipHello); +RegisterCreatureEvent(AUCTIONEER_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_SELECT, OnGossipSelect); +``` + +In this example: + +1. We define the auctioneer NPC entry ID in the `AUCTIONEER_ENTRY` constant. + +2. In the `OnGossipHello` event handler, we check if the creature interacted with is an auctioneer using the `IsAuctioneer()` method. + +3. If the creature is an auctioneer, we add gossip menu items for showing auction sales, collecting unsold items, and collecting auction proceeds. + +4. We register the `OnGossipHello` event handler for the auctioneer NPC. + +5. In the `OnGossipSelect` event handler, we handle the selected gossip menu item based on the `action` parameter. + +6. Depending on the selected action, we perform the corresponding functionality (showing auction sales, collecting unsold items, or collecting auction proceeds). + +7. Finally, we register the `OnGossipSelect` event handler for the auctioneer NPC. + +This example showcases how the `IsAuctioneer()` method can be used to create custom functionality for auctioneer NPCs, providing additional features to players interacting with them. + +## IsBanker +Returns true if the [Unit] is a banker NPC. + +### Parameters +None + +### Returns +boolean - True if the unit is a banker, false otherwise. + +### Example Usage +This example demonstrates how to use the `IsBanker` method to check if a unit is a banker and provide a custom interaction based on the result. + +```typescript +const GOLD_AMOUNT = 100; + +const OnGossipHello: unit_event_on_gossip_hello = (event: number, player: Player, creature: Creature) => { + if (creature.IsBanker()) { + player.GossipMenuAddItem(0, "Deposit " + GOLD_AMOUNT + " gold", 1, 0); + player.GossipMenuAddItem(0, "Check balance", 2, 0); + player.GossipSendMenu(1, creature); + } else { + player.GossipMenuAddItem(0, "I need to find a banker", 3, 0); + player.GossipSendMenu(2, creature); + } +}; + +const OnGossipSelect: unit_event_on_gossip_select = (event: number, player: Player, creature: Creature, sender: number, action: number) => { + if (creature.IsBanker()) { + if (action === 0) { + player.GossipClearMenu(); + player.GossipSendMenu(1, creature); + } else if (action === 1) { + if (player.GetCoinage() >= GOLD_AMOUNT * 10000) { + player.ModifyMoney(-GOLD_AMOUNT * 10000); + player.SendBroadcastMessage("You have deposited " + GOLD_AMOUNT + " gold."); + } else { + player.SendBroadcastMessage("You don't have enough gold to deposit."); + } + player.GossipComplete(); + } else if (action === 2) { + player.SendBroadcastMessage("Your current balance is: " + player.GetCoinage() / 10000 + " gold."); + player.GossipComplete(); + } + } else { + if (action === 3) { + player.SendBroadcastMessage("You can find a banker in any major city."); + player.GossipComplete(); + } + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_GOSSIP_HELLO, (...args) => OnGossipHello(...args)); +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_GOSSIP_SELECT, (...args) => OnGossipSelect(...args)); +``` + +In this example: +1. When a player interacts with an NPC using the `UNIT_EVENT_ON_GOSSIP_HELLO` event, the script checks if the NPC is a banker using the `IsBanker` method. +2. If the NPC is a banker, the player is presented with options to deposit a fixed amount of gold or check their balance. +3. If the NPC is not a banker, the player is given an option to ask for directions to find a banker. +4. When the player selects an option using the `UNIT_EVENT_ON_GOSSIP_SELECT` event, the script handles the corresponding action based on the selected option and whether the NPC is a banker. +5. If the player chooses to deposit gold and has sufficient funds, the specified amount is deducted from their character using `ModifyMoney`, and a success message is displayed. +6. If the player chooses to check their balance, their current gold balance is retrieved using `GetCoinage` and displayed as a message. +7. If the player interacts with a non-banker NPC and selects the option to find a banker, a message is displayed directing them to major cities. + +This example showcases how the `IsBanker` method can be used in combination with other methods and events to create a custom banking interaction within the game. + +## IsBattleMaster +This method checks if the unit is a battle master NPC. Battle masters are special NPCs that allow players to join battlegrounds or arenas. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the unit is a battle master, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsBattleMaster()` method to identify battle master NPCs and provide a custom interaction for players. + +```typescript +const WARSONG_GULCH_BATTLEMASTER_ENTRY = 2302; +const ARATHI_BASIN_BATTLEMASTER_ENTRY = 857; + +const OnGossipHello: creature_event_on_gossip_hello = (event: number, creature: Creature, player: Player): boolean => { + if (creature.IsBattleMaster()) { + const creatureEntry = creature.GetEntry(); + + switch (creatureEntry) { + case WARSONG_GULCH_BATTLEMASTER_ENTRY: + player.GossipMenuAddItem(0, "Tell me more about Warsong Gulch.", 0, 1); + break; + case ARATHI_BASIN_BATTLEMASTER_ENTRY: + player.GossipMenuAddItem(0, "I'd like to know more about Arathi Basin.", 0, 2); + break; + default: + player.GossipMenuAddItem(0, "What battlegrounds are available?", 0, 3); + break; + } + + player.GossipSendMenu(1, creature, 0); + return true; + } + + // Default gossip for non-battle master NPCs + player.GossipMenuAddItem(0, "Hello there!", 0, 4); + player.GossipSendMenu(1, creature, 0); + return true; +}; + +const OnGossipSelect: creature_event_on_gossip_select = (event: number, creature: Creature, player: Player, sender: number, intid: number, code: string, menu_id: number): boolean => { + if (intid === 1) { + player.SendBroadcastMessage("Warsong Gulch is a 10 vs 10 capture the flag battleground located in Ashenvale and the Barrens."); + } else if (intid === 2) { + player.SendBroadcastMessage("Arathi Basin is a 15 vs 15 resource-gathering battleground located in Arathi Highlands."); + } else if (intid === 3) { + player.SendBroadcastMessage("Available battlegrounds: Warsong Gulch, Arathi Basin, Alterac Valley, and Eye of the Storm."); + } else { + player.SendBroadcastMessage("Hello, adventurer! How can I assist you today?"); + } + + player.GossipComplete(); + return true; +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, (...args) => OnGossipHello(...args)); +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_GOSSIP_SELECT, (...args) => OnGossipSelect(...args)); +``` + +In this example, when a player interacts with an NPC, the `OnGossipHello` function is called. It checks if the NPC is a battle master using the `IsBattleMaster()` method. If true, it adds specific gossip options based on the NPC's entry ID. For known battle masters, it provides options to learn more about the specific battleground. For unknown battle masters, it provides a generic option to inquire about available battlegrounds. + +When the player selects a gossip option, the `OnGossipSelect` function is called. Based on the selected option (`intid`), it sends a broadcast message to the player with information about the chosen battleground or a default message for non-battleground-related options. + +This example showcases how the `IsBattleMaster()` method can be used to create custom interactions and provide relevant information to players when interacting with battle master NPCs. + +## IsCasting +This method returns a boolean value indicating whether the unit is currently casting a spell. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is casting a spell, `false` otherwise. + +### Example Usage +In this example, we'll create a script that checks if a creature is casting a spell when it enters combat with a player. If the creature is casting, we'll interrupt the spell and make the creature say "My spell was interrupted!". + +```typescript +const CREATURE_ENTRY = 1234; // Replace with the desired creature entry ID + +const onEnterCombat: creature_event_on_enter_combat = (event: number, creature: Creature, target: Unit) => { + if (creature.GetEntry() === CREATURE_ENTRY) { + if (creature.IsCasting()) { + creature.InterruptSpell(); + creature.SendUnitSay("My spell was interrupted!", 0); + + // You can also perform additional actions here, such as: + // - Apply a debuff to the creature + // - Increase the creature's movement speed + // - Make the creature cast a different spell + // - Summon additional creatures to assist the interrupted creature + + const debuffSpellId = 12345; // Replace with the desired debuff spell ID + creature.CastSpell(creature, debuffSpellId, true); + + const movementSpeedIncrease = 50; // 50% movement speed increase + creature.SetSpeed(UnitMoveType.MOVE_RUN, creature.GetSpeed(UnitMoveType.MOVE_RUN) * (1 + movementSpeedIncrease / 100), true); + + const newSpellId = 54321; // Replace with the desired spell ID for the creature to cast + creature.CastSpell(target, newSpellId, false); + + const summonedCreatureEntry = 5678; // Replace with the desired summoned creature entry ID + const summonedCreatureCount = 2; + for (let i = 0; i < summonedCreatureCount; i++) { + creature.SummonCreature(summonedCreatureEntry, creature.GetX(), creature.GetY(), creature.GetZ(), creature.GetO(), TempSummonType.TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + } + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this example: +1. We define the `CREATURE_ENTRY` constant with the desired creature entry ID. +2. We create an event handler function `onEnterCombat` for the `CREATURE_EVENT_ON_ENTER_COMBAT` event. +3. Inside the event handler, we check if the creature's entry matches the desired entry ID. +4. If the creature is casting a spell (checked using `creature.IsCasting()`), we interrupt the spell using `creature.InterruptSpell()`. +5. We make the creature say "My spell was interrupted!" using `creature.SendUnitSay()`. +6. Additionally, we perform some optional actions: + - Apply a debuff to the creature using `creature.CastSpell()` with `true` as the third argument to cast the spell instantly. + - Increase the creature's movement speed by 50% using `creature.SetSpeed()`. + - Make the creature cast a different spell on the target using `creature.CastSpell()` with `false` as the third argument to cast the spell with a cast time. + - Summon two additional creatures to assist the interrupted creature using `creature.SummonCreature()`. +7. Finally, we register the event handler using `RegisterCreatureEvent()`. + +This example showcases how the `IsCasting()` method can be used in combination with other methods and game events to create dynamic and interactive creature behaviors in response to spell casting situations. + +## IsCharmed +Returns true if the unit is currently under the influence of a mind control effect, false otherwise. + +### Parameters +None + +### Returns +boolean - true if the unit is charmed, false otherwise + +### Example Usage +Periodically check if the player has been mind controlled by an enemy and if so, break the charm effect and send them back to their previous location. + +```typescript +let previousLocation: {map: number, x: number, y: number, z: number, o: number}; + +const checkCharm: player_event_on_update = (event: number, player: Player, diff: number) => { + if (player.IsCharmed()) { + if (!previousLocation) { + // Store the player's current location before breaking the charm + previousLocation = { + map: player.GetMapId(), + x: player.GetX(), + y: player.GetY(), + z: player.GetZ(), + o: player.GetO() + }; + } + + // Break the charm effect + player.RemoveAurasDueToSpell(605); // Mind Control spell ID + + // Teleport the player back to their previous location + player.Teleport( + previousLocation.map, + previousLocation.x, + previousLocation.y, + previousLocation.z, + previousLocation.o + ); + + // Notify the player + player.SendBroadcastMessage("You have been freed from mind control!"); + } else { + // Reset the stored location when the player is not charmed + previousLocation = null; + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, checkCharm); +``` + +In this example, we register a `PLAYER_EVENT_ON_UPDATE` event handler to periodically check if the player is charmed using the `IsCharmed()` method. + +If the player is indeed charmed, we first store their current location (if we haven't already) before breaking the charm effect. We then use the stored location to teleport the player back to where they were before being mind controlled. Finally, we send a message to the player notifying them that they have been freed. + +When the player is no longer charmed, we reset the stored location to `null` so that it can be stored again the next time they are mind controlled. + +This script helps to prevent players from being griefed or stuck in an undesirable location after being mind controlled by an enemy player or NPC. + +## IsDead +Returns a boolean value indicating whether the unit is currently dead or alive. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is dead, `false` otherwise. + +### Example Usage +Here's an example of how to use the `IsDead()` method to check if a unit is dead and perform actions based on the result: + +```typescript +const OnUnitDeath: creature_event_on_just_died = (event: number, creature: Creature, killer: Unit) => { + const creatureId = creature.GetEntry(); + + // Check if the creature is a specific boss + if (creatureId === BOSS_ID) { + // Get all players in the map + const players = creature.GetMap().GetPlayers(); + + // Iterate over each player + for (const player of players) { + // Check if the player is alive + if (!player.IsDead()) { + // Reward the player with a special item + const rewardItem = player.AddItem(REWARD_ITEM_ID, 1); + + // Check if the item was successfully added to the player's inventory + if (rewardItem) { + player.SendBroadcastMessage(`Congratulations! You have been rewarded with a special item for defeating the boss.`); + } else { + player.SendBroadcastMessage(`Your inventory is full. Please make space and talk to an NPC to claim your reward.`); + } + } + } + + // Spawn a special NPC at the boss's location + const bossLocation = creature.GetLocation(); + creature.GetMap().SpawnCreature(SPECIAL_NPC_ID, bossLocation.x, bossLocation.y, bossLocation.z, bossLocation.o); + } +}; + +RegisterCreatureEvent(BOSS_ID, CreatureEvents.CREATURE_EVENT_ON_JUST_DIED, OnUnitDeath); +``` + +In this example: +1. We register a creature event handler for the `CREATURE_EVENT_ON_JUST_DIED` event of a specific boss creature. +2. When the boss dies, we retrieve all players in the map using `creature.GetMap().GetPlayers()`. +3. We iterate over each player and check if they are alive using `player.IsDead()`. +4. If the player is alive, we reward them with a special item using `player.AddItem(REWARD_ITEM_ID, 1)`. +5. We check if the item was successfully added to the player's inventory. If so, we send them a congratulatory message using `player.SendBroadcastMessage()`. If the inventory is full, we send a message instructing them to make space and claim the reward from an NPC. +6. After rewarding the players, we spawn a special NPC at the boss's location using `creature.GetMap().SpawnCreature()`. + +This example demonstrates how the `IsDead()` method can be used in combination with other methods and events to create dynamic gameplay experiences based on the life state of units. + +## IsDying +Returns a boolean value indicating whether the unit is currently dying. + +### Returns +boolean - True if the unit is dying, false otherwise. + +### Example Usage +In this example, we'll create a script that checks if a creature is dying and, if so, spawns a new creature and increases the player's experience. + +```typescript +const CREATURE_ENTRY = 1234; +const SPAWN_CREATURE_ENTRY = 5678; +const BONUS_EXPERIENCE = 1000; + +const OnCreatureDeath: creature_event_on_died = (event: number, creature: Creature, killer: Unit) => { + if (creature.GetEntry() === CREATURE_ENTRY) { + if (creature.IsDying()) { + const position = creature.GetPosition(); + const orientation = creature.GetOrientation(); + const spawned = creature.SummonCreature(SPAWN_CREATURE_ENTRY, position.x, position.y, position.z, orientation, 2, 60000); + + if (spawned) { + spawned.SendUnitYell("I have been summoned from the depths!", 0); + } + + if (killer instanceof Player) { + killer.GiveXP(BONUS_EXPERIENCE, creature); + killer.SendBroadcastMessage(`You have been awarded ${BONUS_EXPERIENCE} bonus experience for slaying the creature!`); + } + } + } +}; + +RegisterCreatureEvent(CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_DIED, (...args) => OnCreatureDeath(...args)); +``` + +In this script: +1. We define constants for the creature entry, the entry of the creature to spawn, and the amount of bonus experience to award. +2. We register a `CREATURE_EVENT_ON_DIED` event for the specified creature entry. +3. When the creature dies, we check if its entry matches the one we're interested in. +4. If it does, we use `IsDying()` to check if the creature is currently in the process of dying. +5. If the creature is dying, we get its position and orientation. +6. We use `SummonCreature()` to spawn a new creature at the same position and orientation, with a despawn time of 60000ms (1 minute). +7. If the spawned creature is successfully created, we make it yell a message using `SendUnitYell()`. +8. We check if the killer is a player using the `instanceof` operator. +9. If the killer is a player, we award them bonus experience using `GiveXP()` and send them a broadcast message informing them of the bonus. + +This script demonstrates how `IsDying()` can be used in combination with other methods and events to create interesting gameplay mechanics and interactions. + +## IsFullHealth +Returns true if the unit, whether an NPC or player, is at full health. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is at full health, `false` otherwise. + +### Example Usage +In this example, we'll create a script that will check if the player is at full health when they kill a creature. If they are not at full health, they will receive a 10% healing effect. + +```typescript +const HEAL_PERCENT = 10; + +const OnCreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + if (!player.IsFullHealth()) { + const maxHealth = player.GetMaxHealth(); + const healAmount = maxHealth * (HEAL_PERCENT / 100); + + player.SetHealth(player.GetHealth() + healAmount); + + player.SendBroadcastMessage(`You have been healed for ${healAmount} health for killing the ${creature.GetName()} while not at full health.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => OnCreatureKill(...args)); +``` + +In this script: +1. We define a constant `HEAL_PERCENT` that represents the percentage of the player's maximum health they will be healed for if they kill a creature while not at full health. +2. In the `OnCreatureKill` event handler, we first check if the player is at full health using the `IsFullHealth()` method. +3. If the player is not at full health, we calculate the amount of healing they should receive based on their maximum health and the `HEAL_PERCENT` constant. +4. We then update the player's current health using `SetHealth()` by adding the calculated heal amount to their current health. +5. Finally, we send a message to the player using `SendBroadcastMessage()` to inform them of the healing effect they received for killing the creature while not at full health. + +This script demonstrates how the `IsFullHealth()` method can be used in combination with other methods and game events to create dynamic gameplay experiences for players. + +## IsGossip +Returns a boolean value indicating whether the unit is able to show a gossip window. + +### Returns +boolean - Returns `true` if the unit can show a gossip window; otherwise, returns `false`. + +### Example Usage +This example demonstrates how to use the `IsGossip()` method to determine if a creature can show a gossip window and perform different actions based on the result. + +```typescript +const GOSSIP_MENU_ID = 1234; +const GOSSIP_ITEM_ID = 5678; + +const onGossipHello: GossipHello = (event, player, creature) => { + if (creature.IsGossip()) { + // The creature can show a gossip window + player.PrepareGossipMenu(creature, GOSSIP_MENU_ID); + player.SendPreparedGossip(creature); + } else { + // The creature cannot show a gossip window + creature.Say("I have nothing to say to you.", Language.LANG_UNIVERSAL); + } +}; + +const onGossipSelect: GossipSelect = (event, player, creature, sender, action) => { + if (action === GOSSIP_ITEM_ID) { + // Handle the selected gossip option + if (creature.IsGossip()) { + // The creature can still show a gossip window + player.GossipMenuAddItem(GossipOptionIcon.GOSSIP_ICON_CHAT, "Tell me more.", GOSSIP_MENU_ID, GOSSIP_ITEM_ID); + player.SendPreparedGossip(creature); + } else { + // The creature can no longer show a gossip window + player.CloseGossip(); + creature.Say("I'm afraid I can't help you anymore.", Language.LANG_UNIVERSAL); + } + } +}; + +RegisterCreatureGossipEvent(CREATURE_ENTRY, GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => onGossipHello(...args)); +RegisterCreatureGossipEvent(CREATURE_ENTRY, GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => onGossipSelect(...args)); +``` + +In this example: +1. When a player interacts with a creature, the `onGossipHello` event is triggered. +2. The script checks if the creature can show a gossip window using `creature.IsGossip()`. + - If the creature can show a gossip window, it prepares the gossip menu using `player.PrepareGossipMenu()` and sends it to the player using `player.SendPreparedGossip()`. + - If the creature cannot show a gossip window, it says a message to the player using `creature.Say()`. +3. When the player selects a gossip option, the `onGossipSelect` event is triggered. +4. The script checks if the selected action matches the desired gossip item ID (`GOSSIP_ITEM_ID`). + - If the action matches and the creature can still show a gossip window, it adds a new gossip item using `player.GossipMenuAddItem()` and sends the updated gossip menu to the player. + - If the action matches but the creature can no longer show a gossip window, it closes the gossip window using `player.CloseGossip()` and says a message to the player. + +This example showcases how `IsGossip()` can be used to conditionally display gossip options and handle different scenarios based on the creature's ability to show a gossip window. + +## IsGuildMaster +This method returns true if the [Unit](./unit.md) is a guild master of a guild. + +### Parameters +None + +### Returns +boolean - Returns true if the [Unit](./unit.md) is a guild master, false otherwise. + +### Example Usage +This example shows how to check if a player is a guild master and grant them a special item if they are. + +```typescript +// Item entry for the special guild master item +const GUILD_MASTER_ITEM_ENTRY = 12345; + +// Function to handle the player login event +const OnLogin: player_event_on_login = (event: number, player: Player) => { + // Check if the player is a guild master + if (player.IsGuildMaster()) { + // Check if the player already has the special guild master item + if (!player.HasItem(GUILD_MASTER_ITEM_ENTRY)) { + // Add the special guild master item to the player's inventory + player.AddItem(GUILD_MASTER_ITEM_ENTRY, 1); + + // Send a message to the player + player.SendBroadcastMessage("As a guild master, you have been granted a special item!"); + } + } +} + +// Register the player login event +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example, when a player logs in, the script checks if the player is a guild master using the `IsGuildMaster()` method. If the player is a guild master and doesn't already have the special guild master item, the script adds the item to the player's inventory using the `AddItem()` method and sends a message to the player using the `SendBroadcastMessage()` method. + +By using the `IsGuildMaster()` method, you can easily identify players who are guild masters and provide them with special benefits or functionality in your mod. + +## IsInAccessiblePlaceFor +This method checks if the [Unit] is in an accessible place for the given [WorldObject] within a specified radius. It is commonly used to determine if a [Creature] can reach a specific [Unit] before executing certain actions or initiating combat. + +### Parameters +- `obj`: [WorldObject](./world-object.md) - The [WorldObject] to check accessibility for, typically a [Creature]. +- `radius`: number - The maximum distance in yards to consider for accessibility. + +### Returns +- `boolean` - Returns `true` if the [Unit] is accessible to the [WorldObject] within the specified radius, `false` otherwise. + +### Example Usage +In this example, we have a script that controls the behavior of a guardian creature. When a player enters the creature's visibility range, the creature checks if the player is within an accessible range before engaging in combat or performing other actions. + +```typescript +const GUARDIAN_ENTRY = 12345; +const ENGAGE_RADIUS = 10; + +const GuardianAI: creature_event_on_update = (event: number, creature: Creature, diff: number) => { + if (!creature.IsInCombat()) { + const nearestPlayer = creature.GetNearestPlayer(50); + + if (nearestPlayer) { + if (creature.IsInAccessiblePlaceFor(nearestPlayer, ENGAGE_RADIUS)) { + // Player is within accessible range, engage in combat + creature.AttackStart(nearestPlayer); + + // Perform other actions or apply buffs + creature.CastSpell(creature, 12345, true); + creature.Say("Intruder detected! Engaging in combat!", 0); + } else { + // Player is not within accessible range, move towards them + creature.MoveTo(nearestPlayer.GetX(), nearestPlayer.GetY(), nearestPlayer.GetZ(), ENGAGE_RADIUS); + } + } + } +} + +RegisterCreatureEvent(GUARDIAN_ENTRY, CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => GuardianAI(...args)); +``` + +In this script, the guardian creature periodically checks for the nearest player within a visibility range of 50 yards. If a player is found, the creature uses the `IsInAccessiblePlaceFor` method to determine if the player is within an accessible range defined by `ENGAGE_RADIUS`. + +If the player is accessible, the creature engages in combat using `AttackStart`, casts a spell on itself, and sends a message to the player. If the player is not within accessible range, the creature moves towards the player's location using `MoveTo` to close the distance. + +By utilizing the `IsInAccessiblePlaceFor` method, the creature can make intelligent decisions based on the accessibility of its target, ensuring realistic behavior and preventing situations where the creature gets stuck or cannot reach the player due to obstacles or terrain limitations. + +## IsInCombat +Returns a boolean value indicating whether the unit is currently in combat or not. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the unit is in combat, `false` otherwise. + +### Example Usage +Here's an example of how to use the `IsInCombat` method in a script that rewards players with bonus gold and experience if they defeat an elite creature while in combat with other elite creatures nearby. + +```typescript +const ELITE_CREATURE_ENTRY = 1234; +const BONUS_GOLD = 100; +const BONUS_XP = 500; + +const OnCreatureKill: creature_event_on_kill = (event: number, creature: Creature, killer: Unit) => { + if (creature.GetEntry() === ELITE_CREATURE_ENTRY && killer instanceof Player) { + const player = killer as Player; + + // Check if the player is in combat with other elite creatures + const nearbyCreatures = creature.GetCreaturesInRange(50, ELITE_CREATURE_ENTRY); + let isInCombatWithElites = false; + + for (const nearbyCreature of nearbyCreatures) { + if (nearbyCreature.IsInCombat() && nearbyCreature.IsElite()) { + isInCombatWithElites = true; + break; + } + } + + if (isInCombatWithElites) { + // Reward the player with bonus gold and experience + player.ModifyMoney(BONUS_GOLD); + player.GiveXP(BONUS_XP, true); + player.SendBroadcastMessage(`You have been rewarded with ${BONUS_GOLD} gold and ${BONUS_XP} experience for defeating an elite creature while in combat with other elite creatures!`); + } + } +}; + +RegisterCreatureEvent(ELITE_CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_KILL, (...args) => OnCreatureKill(...args)); +``` + +In this example: +1. We define constants for the elite creature entry, bonus gold amount, and bonus experience amount. +2. We register a creature event handler for the `CREATURE_EVENT_ON_KILL` event of the specified elite creature entry. +3. Inside the event handler, we first check if the killer is a player using the `instanceof` operator. +4. We retrieve nearby creatures within a range of 50 yards that have the same elite creature entry. +5. We iterate over the nearby creatures and check if any of them are in combat and are elite using the `IsInCombat()` and `IsElite()` methods. +6. If the player is in combat with other elite creatures, we reward them with bonus gold using `ModifyMoney()` and bonus experience using `GiveXP()`. +7. Finally, we send a broadcast message to the player informing them about the bonus rewards they received. + +This script demonstrates how the `IsInCombat` method can be used in combination with other methods and conditions to create engaging gameplay mechanics and reward players for their achievements. + +## IsInWater +Returns true if the unit is currently in water. + +### Parameters +None + +### Returns +boolean - True if the unit is in water, false otherwise. + +### Example Usage +This example demonstrates how to use the `IsInWater()` method to check if a player is in water and apply a buff if they are. + +```typescript +const SWIM_SPEED_BUFF_ID = 97; +const SWIM_SPEED_BUFF_DURATION = 60 * 1000; // 1 minute in milliseconds + +const HandlePlayerMovement: player_event_on_update = (event: number, player: Player, diff: number) => { + // Check if the player is in water + if (player.IsInWater()) { + // Check if the player already has the swim speed buff + if (!player.HasAura(SWIM_SPEED_BUFF_ID)) { + // Apply the swim speed buff to the player + player.AddAura(SWIM_SPEED_BUFF_ID, SWIM_SPEED_BUFF_DURATION); + player.SendBroadcastMessage("You feel a surge of energy as you enter the water!"); + } + } else { + // Check if the player has the swim speed buff + if (player.HasAura(SWIM_SPEED_BUFF_ID)) { + // Remove the swim speed buff from the player + player.RemoveAura(SWIM_SPEED_BUFF_ID); + player.SendBroadcastMessage("The surge of energy fades as you leave the water."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => HandlePlayerMovement(...args)); +``` + +In this example: +1. We define constants for the swim speed buff ID and duration. +2. We register a `player_event_on_update` event to handle player movement. +3. Inside the event handler, we check if the player is in water using `player.IsInWater()`. +4. If the player is in water and doesn't already have the swim speed buff, we apply the buff using `player.AddAura()` and send a broadcast message to the player. +5. If the player is not in water and has the swim speed buff, we remove the buff using `player.RemoveAura()` and send a broadcast message to the player. + +This script will apply a swim speed buff to the player whenever they enter water, and remove the buff when they leave the water. The buff duration is set to 1 minute, but you can adjust it as needed. + +## IsInnkeeper +This method checks if the given [Unit](./unit.md) is an innkeeper NPC. Innkeeper NPCs can provide various services to players, such as allowing them to bind their hearthstone to the innkeeper's location or providing rested experience. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns true if the [Unit](./unit.md) is an innkeeper, false otherwise. + +### Example Usage +This example demonstrates how to use the `IsInnkeeper` method to create a script that allows players to bind their hearthstone to an innkeeper's location and receive a special item as a reward. + +```typescript +const INNKEEPER_ENTRY = 1234; // Replace with the actual innkeeper's entry ID +const SPECIAL_ITEM_ENTRY = 5678; // Replace with the actual special item's entry ID + +const onGossipHello: player_event_on_gossip_hello = (event: number, player: Player, unit: Unit) => { + if (unit.IsInnkeeper()) { + player.GossipMenuAddItem(0, "Bind my hearthstone here", 0, 1); + player.GossipMenuAddItem(0, "I'm just browsing", 0, 2); + player.GossipSendMenu(1, unit.GetGUID()); + } +}; + +const onGossipSelect: player_event_on_gossip_select = (event: number, player: Player, unit: Unit, sender: number, action: number) => { + if (unit.GetEntry() === INNKEEPER_ENTRY) { + if (action === 1) { + player.SetBindPoint(unit.GetMapId(), unit.GetX(), unit.GetY(), unit.GetZ()); + player.SendBindPointUpdate(); + + const item = player.AddItem(SPECIAL_ITEM_ENTRY, 1); + if (item) { + player.SendAreaTriggerMessage("You have bound your hearthstone to this location and received a special item!"); + } else { + player.SendAreaTriggerMessage("You have bound your hearthstone to this location, but your inventory is full. Please make room and talk to the innkeeper again to receive your special item."); + } + + player.GossipComplete(); + } else if (action === 2) { + player.SendAreaTriggerMessage("Safe travels!"); + player.GossipComplete(); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, (...args) => onGossipHello(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_SELECT, (...args) => onGossipSelect(...args)); +``` + +In this example: +1. When a player interacts with an innkeeper NPC (identified by `INNKEEPER_ENTRY`), the script checks if the unit is indeed an innkeeper using the `IsInnkeeper` method. +2. If the unit is an innkeeper, the script adds two gossip options: one to bind the player's hearthstone and receive a special item, and another to simply browse. +3. When the player selects the "Bind my hearthstone here" option, the script sets the player's bind point to the innkeeper's location using `SetBindPoint` and `SendBindPointUpdate`. +4. The script then attempts to add the special item (identified by `SPECIAL_ITEM_ENTRY`) to the player's inventory using `AddItem`. If successful, the player receives a message confirming the binding and the item. If the player's inventory is full, they receive a message asking them to make room and talk to the innkeeper again. +5. If the player selects the "I'm just browsing" option, they receive a simple farewell message. + +This script showcases how the `IsInnkeeper` method can be used in conjunction with other methods and events to create a more immersive and interactive experience for players when dealing with innkeeper NPCs. + +## IsMounted +Returns a boolean value indicating whether the unit is currently mounted on a mount or vehicle. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is mounted, `false` otherwise. + +### Example Usage +This example demonstrates how to check if a player is mounted and apply a speed bonus if they are. + +```typescript +const SPEED_BONUS = 1.5; + +const onPlayerLogin: player_event_on_login = (event: number, player: Player) => { + if (player.IsMounted()) { + // Get the player's current speed + const currentSpeed = player.GetSpeed(UnitMoveType.MOVE_RUN); + + // Calculate the speed bonus + const speedBonus = currentSpeed * SPEED_BONUS; + + // Apply the speed bonus to the player + player.SetSpeed(UnitMoveType.MOVE_RUN, speedBonus); + + // Inform the player about the speed bonus + player.SendBroadcastMessage(`You receive a ${SPEED_BONUS}x speed bonus while mounted!`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => onPlayerLogin(...args)); +``` + +In this example: +1. We define a constant `SPEED_BONUS` to represent the speed bonus multiplier. +2. Inside the `onPlayerLogin` event handler, we check if the player is mounted using `player.IsMounted()`. +3. If the player is mounted: + - We get the player's current running speed using `player.GetSpeed(UnitMoveType.MOVE_RUN)`. + - We calculate the speed bonus by multiplying the current speed with the `SPEED_BONUS`. + - We apply the speed bonus to the player using `player.SetSpeed(UnitMoveType.MOVE_RUN, speedBonus)`. + - We send a broadcast message to the player informing them about the speed bonus they received. +4. Finally, we register the `onPlayerLogin` event handler using `RegisterPlayerEvent`. + +This script enhances the gameplay experience by providing a temporary speed boost to mounted players, encouraging them to utilize mounts for faster travel. + +Note: The speed bonus multiplier and the specific implementation can be adjusted based on the desired balance and gameplay mechanics of your server. + +## IsOnVehicle +Returns true if the [Unit] is currently on a [Vehicle]. + +### Parameters +None + +### Returns +boolean - True if the [Unit] is on a [Vehicle], false otherwise. + +### Example Usage +This example demonstrates how to check if a player is on a vehicle and apply a buff to the vehicle if they are. + +```typescript +const VEHICLE_BUFF_ENTRY = 12345; + +const onVehicleEnter: vehicle_event_on_enter = (event: number, vehicle: Vehicle, passenger: Unit, seat: number) => { + if (passenger instanceof Player) { + if (passenger.IsOnVehicle()) { + const vehicleCreature = vehicle.GetBase(); + if (vehicleCreature instanceof Creature) { + vehicleCreature.AddAura(VEHICLE_BUFF_ENTRY, vehicleCreature); + vehicleCreature.SendChatMessage(ChatMsg.CHAT_MSG_MONSTER_SAY, 0, "The passenger has empowered the vehicle!"); + } + } + } +}; + +RegisterVehicleEvent(VehicleEvents.VEHICLE_EVENT_ON_ENTER, (...args) => onVehicleEnter(...args)); +``` + +In this example: +1. We define a constant `VEHICLE_BUFF_ENTRY` with the entry ID of the buff we want to apply to the vehicle. +2. We register a `VEHICLE_EVENT_ON_ENTER` event handler using `RegisterVehicleEvent`. +3. In the event handler function `onVehicleEnter`, we first check if the passenger is a player using `passenger instanceof Player`. +4. If the passenger is a player, we use `passenger.IsOnVehicle()` to check if the player is currently on a vehicle. +5. If the player is on a vehicle, we retrieve the vehicle's base creature using `vehicle.GetBase()`. +6. We check if the vehicle's base is a creature using `vehicleCreature instanceof Creature`. +7. If the vehicle's base is a creature, we add the specified buff to the vehicle using `vehicleCreature.AddAura(VEHICLE_BUFF_ENTRY, vehicleCreature)`. +8. Finally, we make the vehicle's creature say a message using `vehicleCreature.SendChatMessage(ChatMsg.CHAT_MSG_MONSTER_SAY, 0, "The passenger has empowered the vehicle!")`. + +This example showcases how to use the `IsOnVehicle()` method to determine if a unit (in this case, a player) is currently on a vehicle and perform actions based on that condition. It also demonstrates interacting with the vehicle and its base creature to apply buffs and send chat messages. + +## IsPvPFlagged +This method checks if the [Unit] is flagged for PvP combat. Players can be flagged for PvP by either toggling their PvP flag, entering a PvP zone, or attacking another player flagged for PvP. When a unit is PvP flagged, they are open to attacks from players of the opposite faction. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is flagged for PvP, `false` otherwise. + +### Example Usage +In this example, we will create a script that rewards players with bonus honor points when they kill a player that is PvP flagged in the world. + +```typescript +const BONUS_HONOR_POINTS = 10; + +const OnPVPKill: player_event_on_kill_player = (event: number, killer: Player, killed: Player) => { + // Check if the killed player was PvP flagged + if (killed.IsPvPFlagged()) { + // Reward the killer with bonus honor points + killer.ModifyHonorPoints(BONUS_HONOR_POINTS); + + // Send a message to the killer + killer.SendBroadcastMessage(`You have been awarded ${BONUS_HONOR_POINTS} bonus honor points for killing a PvP flagged player!`); + + // Get the killer's current honor points + const currentHonorPoints = killer.GetHonorPoints(); + + // Check if the killer has reached a certain threshold of honor points + if (currentHonorPoints >= 1000) { + // Reward the killer with an additional item + const BONUS_ITEM_ENTRY = 12345; + killer.AddItem(BONUS_ITEM_ENTRY, 1); + + // Send another message to the killer + killer.SendBroadcastMessage(`You have been awarded a bonus item for reaching ${currentHonorPoints} honor points!`); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_PLAYER, (...args) => OnPVPKill(...args)); +``` + +In this script, we first check if the killed player was PvP flagged using the `IsPvPFlagged()` method. If they were, we reward the killer with a set amount of bonus honor points using the `ModifyHonorPoints()` method and send them a message using `SendBroadcastMessage()`. + +We then check the killer's current honor points using `GetHonorPoints()` and see if they have reached a certain threshold (in this case, 1000 points). If they have, we reward them with an additional bonus item using `AddItem()` and send them another message. + +This script encourages world PvP by rewarding players for killing PvP flagged enemies, while also providing additional rewards for reaching certain milestones. + +## IsQuestGiver +This method checks if the unit is a quest giver. It is useful to determine if the player can interact with the unit to receive or turn in quests. + +### Parameters +This method does not take any parameters. + +### Returns +* boolean - Returns `true` if the unit is a quest giver, `false` otherwise. + +### Example Usage +In this example, we create a script that listens for the `GOSSIP_EVENT_ON_HELLO` event. When a player interacts with a unit, it checks if the unit is a quest giver. If the unit is a quest giver, it displays a message to the player indicating that they can receive or turn in quests. If the unit is not a quest giver, it displays a different message. + +```typescript +const OnGossipHello: gossip_event_on_hello = (event: number, player: Player, unit: Unit) => { + if (unit.IsQuestGiver()) { + player.SendBroadcastMessage(`Welcome, ${player.GetName()}! I have quests available for you.`); + + // Check if the player has any completed quests to turn in + const completedQuests = player.GetQuestStatus().filter(quest => quest.status === QuestStatus.COMPLETE); + + if (completedQuests.length > 0) { + player.SendBroadcastMessage(`You have ${completedQuests.length} completed quest(s) ready to turn in!`); + } + + // Check if the player is eligible for any new quests + const availableQuests = unit.GetQuestList().filter(quest => player.CanTakeQuest(quest.entry)); + + if (availableQuests.length > 0) { + player.SendBroadcastMessage(`There are ${availableQuests.length} new quest(s) available for you!`); + } + + // Add gossip menu options for quest interaction + player.GossipMenuAddItem(0, "I would like to turn in a quest.", 0, 0); + player.GossipMenuAddItem(0, "I am looking for a new quest.", 0, 0); + player.GossipSendMenu(player.GetGUID(), unit.GetEntry()); + } else { + player.SendBroadcastMessage(`Greetings, ${player.GetName()}! I'm afraid I don't have any quests for you.`); + player.GossipComplete(); + } +}; + +RegisterUnitEvent(UnitEvents.GOSSIP_EVENT_ON_HELLO, (...args) => OnGossipHello(...args)); +``` + +In this script, we utilize additional methods and properties to enhance the functionality: +- `player.GetQuestStatus()` retrieves the player's current quest statuses. +- `player.CanTakeQuest(entry)` checks if the player is eligible to accept a specific quest. +- `unit.GetQuestList()` retrieves the list of quests offered by the unit. +- `player.GossipMenuAddItem()` adds options to the gossip menu for quest interaction. +- `player.GossipSendMenu()` sends the gossip menu to the player. +- `player.GossipComplete()` closes the gossip interaction if the unit is not a quest giver. + +This example demonstrates how to use the `IsQuestGiver()` method in conjunction with other quest-related methods and gossip functionality to create a more interactive and informative quest giver interaction. + +## IsRooted +Returns a boolean value indicating whether the unit is currently rooted or not. A rooted unit is unable to move and may have other restrictions applied. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the unit is currently rooted, `false` otherwise. + +### Example Usage +In this example, we create a script that checks if the player is rooted when they enter combat. If the player is rooted, we remove the root effect and apply a speed boost to help them escape. + +```typescript +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + if (player.IsRooted()) { + // Remove the root effect + player.RemoveAurasByType(AuraType.SPELL_AURA_MOD_ROOT); + + // Apply a speed boost to help the player escape + const SPEED_BOOST_SPELL_ID = 12345; + const SPEED_BOOST_DURATION = 5000; // 5 seconds + player.AddAura(SPEED_BOOST_SPELL_ID, SPEED_BOOST_DURATION); + + // Send a message to the player + player.SendBroadcastMessage("You have been unrooted and granted a temporary speed boost!"); + + // Log the event + console.log(`Player ${player.GetName()} was rooted when entering combat with ${enemy.GetName()}. Root removed and speed boost applied.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script: +1. We register a callback function for the `PLAYER_EVENT_ON_ENTER_COMBAT` event. +2. When the player enters combat, we check if they are rooted using the `IsRooted()` method. +3. If the player is rooted: + - We remove the root effect by removing all auras of type `SPELL_AURA_MOD_ROOT` using `RemoveAurasByType()`. + - We apply a speed boost aura to the player using `AddAura()`, specifying the spell ID and duration. + - We send a message to the player informing them about the root removal and speed boost using `SendBroadcastMessage()`. + - We log the event details using `console.log()`. + +This script demonstrates how you can use the `IsRooted()` method to check if a unit is rooted and take appropriate actions based on the result. In this case, we remove the root effect and apply a temporary speed boost to help the player escape combat when they are rooted. + +## IsServiceProvider +This method checks if the unit is a service provider, such as a vendor, trainer, or auctioneer. It is useful for determining if the player can interact with the unit to access certain services. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is a service provider, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsServiceProvider` method to create a custom interaction system for service providers. When a player interacts with a unit, the script checks if the unit is a service provider and displays a custom dialogue based on the type of service provider. + +```typescript +const GOSSIP_ICON_VENDOR = 1; +const GOSSIP_ICON_TRAINER = 2; +const GOSSIP_ICON_AUCTIONEER = 3; + +const OnGossipHello: player_event_on_gossip_hello = (event: number, player: Player, unit: Unit): void => { + if (unit.IsServiceProvider()) { + if (unit.IsVendor()) { + player.GossipMenuAddItem(GOSSIP_ICON_VENDOR, "Show me your wares.", 0, 1); + } + if (unit.IsTrainer()) { + player.GossipMenuAddItem(GOSSIP_ICON_TRAINER, "I seek training.", 0, 2); + } + if (unit.IsAuctioneer()) { + player.GossipMenuAddItem(GOSSIP_ICON_AUCTIONEER, "I want to browse the auction house.", 0, 3); + } + player.GossipSendMenu(1, unit.GetObjectGuid()); + } else { + player.GossipSendMenu(0, unit.GetObjectGuid()); + } +}; + +const OnGossipSelect: player_event_on_gossip_select = (event: number, player: Player, unit: Unit, sender: number, action: number): void => { + if (action == 1) { + player.SendListInventory(unit.GetObjectGuid()); + } else if (action == 2) { + player.SendTrainerList(unit.GetObjectGuid()); + } else if (action == 3) { + player.SendAuctionMenu(unit.GetObjectGuid()); + } + player.GossipComplete(); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, (...args) => OnGossipHello(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_SELECT, (...args) => OnGossipSelect(...args)); +``` + +In this example: +1. When the player interacts with a unit (triggering the `PLAYER_EVENT_ON_GOSSIP_HELLO` event), the script checks if the unit is a service provider using the `IsServiceProvider` method. +2. If the unit is a service provider, the script further checks the specific type of service provider (vendor, trainer, or auctioneer) and adds corresponding gossip menu items using `player.GossipMenuAddItem`. +3. The gossip menu is sent to the player using `player.GossipSendMenu`. +4. When the player selects a gossip option (triggering the `PLAYER_EVENT_ON_GOSSIP_SELECT` event), the script handles the selected action based on the `action` parameter. +5. Depending on the selected action, the player is sent the appropriate inventory list, trainer list, or auction menu using `player.SendListInventory`, `player.SendTrainerList`, or `player.SendAuctionMenu`, respectively. +6. Finally, the gossip interaction is completed using `player.GossipComplete`. + +This example showcases how the `IsServiceProvider` method can be used in combination with other methods and events to create a custom interaction system for service providers in your mod. + +## IsSpiritGuide +This method checks if the unit is a spirit guide. Spirit guides are typically found in graveyards and are responsible for resurrecting players. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the unit is a spirit guide, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsSpiritGuide()` method to identify spirit guide units and perform specific actions based on that information. + +```typescript +const GRAVEYARD_ZONE_ID = 12; // Example graveyard zone ID + +const OnPlayerGhostUpdate: player_event_on_update = (event: number, player: Player, diff: number) => { + if (player.IsDead()) { + const nearbyUnits = player.GetUnitsInRange(10); // Get nearby units within 10 yards + + for (const unit of nearbyUnits) { + if (unit.IsSpiritGuide()) { + const spiritGuide = unit as Creature; + const graveyard = spiritGuide.GetNearestGraveyard(); + + if (graveyard && graveyard.GetZoneId() === GRAVEYARD_ZONE_ID) { + // Perform specific actions for the spirit guide in the desired graveyard + player.SendBroadcastMessage("You have found the spirit guide in the target graveyard!"); + player.ResurrectPlayer(1.0); // Resurrect the player with full health + player.TeleportTo(graveyard.GetMapId(), graveyard.GetPositionX(), graveyard.GetPositionY(), graveyard.GetPositionZ(), 0); // Teleport the player to the graveyard + break; + } + } + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => OnPlayerGhostUpdate(...args)); +``` + +In this example: +1. We define a constant `GRAVEYARD_ZONE_ID` to represent the desired graveyard zone ID. +2. Inside the `OnPlayerGhostUpdate` event handler, we check if the player is dead using the `IsDead()` method. +3. If the player is dead, we retrieve nearby units within a 10-yard range using the `GetUnitsInRange()` method. +4. We iterate over the nearby units and check if each unit is a spirit guide using the `IsSpiritGuide()` method. +5. If a unit is a spirit guide, we cast it to a `Creature` type to access specific methods. +6. We retrieve the nearest graveyard to the spirit guide using the `GetNearestGraveyard()` method. +7. If the nearest graveyard exists and its zone ID matches the desired `GRAVEYARD_ZONE_ID`, we perform specific actions: + - Send a broadcast message to the player indicating they have found the spirit guide in the target graveyard. + - Resurrect the player with full health using the `ResurrectPlayer()` method. + - Teleport the player to the graveyard location using the `TeleportTo()` method. +8. Finally, we register the `OnPlayerGhostUpdate` event handler for the `PLAYER_EVENT_ON_UPDATE` event using the `RegisterPlayerEvent()` function. + +This example showcases how the `IsSpiritGuide()` method can be used in combination with other methods and game events to create a script that identifies spirit guides and performs specific actions when a player is near a spirit guide in a desired graveyard. + +## IsSpiritHealer +Returns true if the [Unit] is a spirit healer, false otherwise. + +### Parameters +None + +### Returns +boolean - True if the unit is a spirit healer, false otherwise. + +### Example Usage +This example demonstrates how to use the `IsSpiritHealer` method to check if a unit is a spirit healer and perform specific actions based on the result. + +```typescript +const SpiritHealerAura: ManagedAuraScript = { + OnApply: (aura: Aura): void => { + const caster = aura.GetCaster(); + if (!caster) { + return; + } + + if (caster.IsSpiritHealer()) { + const target = aura.GetTarget(); + if (target && target.ToPlayer()) { + const player = target.ToPlayer(); + player.ResurrectPlayer(0.5); + player.TeleportTo(player.GetMapId(), player.GetX(), player.GetY(), player.GetZ(), player.GetO()); + player.SpawnCorpseBones(); + } + } + }, + + OnRemove: (aura: Aura): void => { + // Additional actions when the aura is removed + }, + + OnPeriodicTick: (aura: Aura): void => { + // Additional actions on each periodic tick of the aura + } +}; + +RegisterAura(12345, SpiritHealerAura); +``` + +In this example, a custom aura script is registered for the aura with ID 12345. When the aura is applied to a unit, the script checks if the caster of the aura is a spirit healer using the `IsSpiritHealer` method. + +If the caster is a spirit healer and the target of the aura is a player, the script performs the following actions: +1. Resurrects the player with 50% health using the `ResurrectPlayer` method. +2. Teleports the player to their current location using the `TeleportTo` method. +3. Spawns the player's corpse bones using the `SpawnCorpseBones` method. + +This example showcases how the `IsSpiritHealer` method can be used in conjunction with other methods and game events to create custom functionality related to spirit healers and player resurrection. + +## IsSpiritService +Returns true if the [Unit] is a spirit guide or spirit healer. Spirit guides and spirit healers are special NPCs that can resurrect dead players and help them return to their corpse. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is a spirit guide or spirit healer, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsSpiritService()` method to identify spirit guides or spirit healers and provide a custom interaction when a player interacts with them. + +```typescript +const SPIRIT_HEALER_ENTRY = 6491; + +const OnGossipHello: on_gossip_hello = (event: any, player: Player, creature: Creature) => { + if (creature.GetEntry() === SPIRIT_HEALER_ENTRY && creature.IsSpiritService()) { + player.GossipMenuAddItem(0, "Resurrect me, please!", 0, 1); + player.GossipMenuAddItem(0, "Can you guide me to my corpse?", 0, 2); + player.GossipSendMenu(player.GetGUID(), creature.GetGUID()); + } else { + player.GossipSendMenu(player.GetGUID(), creature.GetGUID()); + } +}; + +const OnGossipSelect: on_gossip_select = (event: any, player: Player, creature: Creature, sender: number, action: number) => { + if (creature.GetEntry() === SPIRIT_HEALER_ENTRY && creature.IsSpiritService()) { + if (action === 1) { + player.ResurrectPlayer(0.5); + player.SpellCastDirected(player.GetGUID(), 48171, true); + player.GossipComplete(); + } else if (action === 2) { + const corpseX = player.GetCorpseX(); + const corpseY = player.GetCorpseY(); + const corpseZ = player.GetCorpseZ(); + const corpseMapId = player.GetCorpseMapId(); + + player.TeleportTo(corpseMapId, corpseX, corpseY, corpseZ, 0); + player.GossipComplete(); + } + } +}; + +RegisterCreatureEvent(SPIRIT_HEALER_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, OnGossipHello); +RegisterCreatureEvent(SPIRIT_HEALER_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_SELECT, OnGossipSelect); +``` + +In this example: +1. We define the entry ID of the spirit healer NPC as `SPIRIT_HEALER_ENTRY`. +2. In the `OnGossipHello` event, we check if the creature interacted with is a spirit healer using `creature.IsSpiritService()`. +3. If it is a spirit healer, we add custom gossip options for resurrecting the player and guiding them to their corpse using `player.GossipMenuAddItem()`. +4. In the `OnGossipSelect` event, we handle the selected gossip option. + - If the player chooses to resurrect, we use `player.ResurrectPlayer()` to resurrect them with 50% health and cast a resurrection visual spell using `player.SpellCastDirected()`. + - If the player chooses to be guided to their corpse, we retrieve the coordinates and map ID of their corpse using `player.GetCorpseX()`, `player.GetCorpseY()`, `player.GetCorpseZ()`, and `player.GetCorpseMapId()`, and then teleport the player to those coordinates using `player.TeleportTo()`. +5. Finally, we register the gossip events for the spirit healer NPC using `RegisterCreatureEvent()`. + +This example showcases how `IsSpiritService()` can be used to identify spirit healers and implement custom functionality for interacting with them, providing players with options to resurrect or find their corpse. + +## IsStandState +Returns a boolean value indicating whether the unit is currently in a standing state. + +### Parameters +None + +### Returns +boolean - `true` if the unit is standing, `false` otherwise. + +### Example Usage +This example demonstrates how to check if a player is standing and perform different actions based on their stance. + +```typescript +const OnPlayerCastSpell: player_event_on_spell_cast = (event: number, player: Player, spell: Spell) => { + const SPELL_ID_FIREBALL = 133; + const SPELL_ID_FROSTBOLT = 116; + + if (spell.GetEntry() === SPELL_ID_FIREBALL || spell.GetEntry() === SPELL_ID_FROSTBOLT) { + if (player.IsStandState()) { + player.SendBroadcastMessage("You cast a powerful spell while standing tall!"); + player.CastSpell(player, 23768, true); // Cast "Reflexes" spell on the player + player.AddAura(48161, player); // Add "Power Infusion" aura to the player + player.CastSpell(spell.GetTarget(), spell, true); // Cast the original spell on the target + } else { + player.SendBroadcastMessage("You cast a spell while in a non-standing state."); + player.CastSpell(spell.GetTarget(), spell, true); // Cast the original spell on the target + player.AddAura(12544, player); // Add "Frost Armor" aura to the player + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SPELL_CAST, (...args) => OnPlayerCastSpell(...args)); +``` + +In this example: +1. We define a callback function `OnPlayerCastSpell` that is triggered whenever a player casts a spell. +2. We check if the spell being cast is either "Fireball" (ID: 133) or "Frostbolt" (ID: 116). +3. If the spell matches, we use `player.IsStandState()` to determine if the player is currently standing. +4. If the player is standing: + - We send a broadcast message to the player indicating they cast a powerful spell while standing. + - We cast the "Reflexes" spell (ID: 23768) on the player using `player.CastSpell()`. + - We add the "Power Infusion" aura (ID: 48161) to the player using `player.AddAura()`. + - We cast the original spell on the target using `player.CastSpell()`. +5. If the player is not standing: + - We send a broadcast message to the player indicating they cast a spell in a non-standing state. + - We cast the original spell on the target using `player.CastSpell()`. + - We add the "Frost Armor" aura (ID: 12544) to the player using `player.AddAura()`. +6. Finally, we register the `OnPlayerCastSpell` callback function to the `PLAYER_EVENT_ON_SPELL_CAST` event using `RegisterPlayerEvent()`. + +This script allows you to differentiate between spells cast while standing and spells cast in other stances, providing different effects and messages based on the player's stance. + +## IsStopped +Returns true if the [Unit] is not moving. This can be useful for checking if a unit is currently stationary or in motion. + +### Parameters +None + +### Returns +boolean - True if the unit is not moving, false otherwise. + +### Example Usage +Here's an example of how you can use the `IsStopped()` method to create a script that tracks a player's movement and grants them a buff if they remain stationary for a certain duration: + +```typescript +const STATIONARY_BUFF_ID = 12345; // Replace with the actual buff ID +const STATIONARY_DURATION = 5 * 1000; // 5 seconds in milliseconds + +let stationaryTimer: number | null = null; + +const OnPlayerMoved: player_event_on_move = (event: number, player: Player, moveType: PlayerMoveType, movementInfo: MovementInfo) => { + if (player.IsStopped()) { + if (!stationaryTimer) { + // Player has stopped moving, start the timer + stationaryTimer = setTimeout(() => { + if (player.IsStopped()) { + // Player is still stationary after the specified duration + player.AddAura(STATIONARY_BUFF_ID, player); + player.SendBroadcastMessage("You have been granted a buff for remaining stationary!"); + } + stationaryTimer = null; + }, STATIONARY_DURATION); + } + } else { + if (stationaryTimer) { + // Player has started moving, cancel the timer + clearTimeout(stationaryTimer); + stationaryTimer = null; + } + player.RemoveAura(STATIONARY_BUFF_ID); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_MOVE, (...args) => OnPlayerMoved(...args)); +``` + +In this example: +1. We define constants for the buff ID (`STATIONARY_BUFF_ID`) and the duration (`STATIONARY_DURATION`) that the player needs to remain stationary to receive the buff. + +2. We create a variable `stationaryTimer` to keep track of the timer. + +3. We register the `OnPlayerMoved` event handler using `RegisterPlayerEvent` with the `PLAYER_EVENT_ON_MOVE` event. + +4. Inside the event handler, we check if the player is stopped using `player.IsStopped()`. + +5. If the player is stopped and there is no active timer, we start a new timer using `setTimeout`. The timer will execute the callback function after the specified `STATIONARY_DURATION`. + +6. If the player is still stationary after the duration, we add the stationary buff to the player using `player.AddAura` and send a broadcast message to notify them. + +7. If the player starts moving while the timer is active, we cancel the timer using `clearTimeout` and remove the stationary buff using `player.RemoveAura`. + +This script encourages players to remain stationary for a certain duration to receive a beneficial buff. You can customize the buff ID and duration to suit your mod's gameplay mechanics. + +## IsTabardDesigner +This method checks if the [Unit] is a tabard designer NPC. Tabard designers are special NPCs that allow players to create and customize their guild tabards. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the [Unit] is a tabard designer, `false` otherwise. + +### Example Usage +This example demonstrates how to use the `IsTabardDesigner()` method to create a custom interaction with a tabard designer NPC. When a player interacts with the NPC, it will check if the player is in a guild. If the player is in a guild and is the guild leader, it will allow them to customize their guild tabard. If the player is not in a guild or is not the guild leader, it will display an appropriate message. + +```typescript +const TABARD_DESIGNER_ENTRY = 28776; + +const OnGossipHello: GossipHello = (event, player, object) => { + if (object.IsTabardDesigner()) { + if (player.IsInGuild()) { + const guildId = player.GetGuildId(); + const guild = new Guild(guildId); + + if (player.GetGUID() === guild.GetLeaderGUID()) { + // Player is the guild leader, allow them to customize the tabard + player.GossipMenuAddItem(0, "Customize Guild Tabard", 0, 1); + player.GossipSendMenu(DEFAULT_GOSSIP_MESSAGE, object.GetGUID()); + } else { + // Player is not the guild leader + player.GossipSetText("Only the guild leader can customize the guild tabard."); + player.GossipSendMenu(DEFAULT_GOSSIP_MESSAGE, object.GetGUID()); + } + } else { + // Player is not in a guild + player.GossipSetText("You must be in a guild to customize a tabard."); + player.GossipSendMenu(DEFAULT_GOSSIP_MESSAGE, object.GetGUID()); + } + } else { + // Handle regular gossip for non-tabard designer NPCs + player.GossipSetText("Hello, how can I assist you today?"); + player.GossipSendMenu(DEFAULT_GOSSIP_MESSAGE, object.GetGUID()); + } +}; + +RegisterGameObjectGossipEvent(TABARD_DESIGNER_ENTRY, GossipEvents.GOSSIP_EVENT_ON_HELLO, OnGossipHello); +``` + +In this example, when a player interacts with a tabard designer NPC, the script checks if the player is in a guild using `player.IsInGuild()`. If the player is in a guild, it retrieves the guild ID using `player.GetGuildId()` and creates a new `Guild` object. It then checks if the player is the guild leader by comparing the player's GUID with the guild leader's GUID using `player.GetGUID()` and `guild.GetLeaderGUID()`. + +If the player is the guild leader, it adds a gossip menu item allowing them to customize the guild tabard. If the player is not the guild leader or is not in a guild, it displays an appropriate message using `player.GossipSetText()`. + +Finally, it registers the `OnGossipHello` event for the tabard designer NPC entry using `RegisterGameObjectGossipEvent()`. + +## IsTaxi +This method returns a boolean value indicating whether the [Unit](./unit.md) is a taxi master NPC or not. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is a taxi master, `false` otherwise. + +### Example Usage +This example demonstrates how to create a custom taxi system that allows players to use a specific item to unlock special taxi routes. + +```typescript +// Item entry for the special taxi unlock item +const TAXI_UNLOCK_ITEM_ENTRY = 12345; + +// Function to handle gossip select for taxi master +function onGossipSelect(event: number, player: Player, creature: Creature, sender: GossipSender, action: number, code: string): void { + if (creature.IsTaxi()) { + if (action === 0) { + // Check if the player has the special taxi unlock item + if (player.HasItem(TAXI_UNLOCK_ITEM_ENTRY)) { + // Enable special taxi routes for the player + player.EnableTaxiNode(1234); + player.EnableTaxiNode(5678); + player.SendBroadcastMessage("Special taxi routes unlocked!"); + } else { + player.SendBroadcastMessage("You need the special taxi unlock item to access these routes."); + } + player.GossipComplete(); + } else { + // Handle regular taxi functionality + player.SendTaxiMenu(creature.GetGUID()); + } + } else { + // Handle other gossip options for non-taxi master creatures + // ... + } +} + +// Register the gossip select event +RegisterCreatureGossipEvent(NPC_ENTRY, 1, onGossipSelect); +``` + +In this example: +1. We define a constant `TAXI_UNLOCK_ITEM_ENTRY` to represent the item entry for the special taxi unlock item. + +2. Inside the `onGossipSelect` function, we check if the creature is a taxi master using the `IsTaxi()` method. + +3. If the creature is a taxi master and the selected gossip action is 0 (assuming it corresponds to the special taxi option), we check if the player has the special taxi unlock item using `player.HasItem(TAXI_UNLOCK_ITEM_ENTRY)`. + +4. If the player has the item, we enable specific taxi nodes using `player.EnableTaxiNode()` and send a broadcast message to the player indicating that the special routes are unlocked. + +5. If the player doesn't have the item, we send a message informing them that they need the special item to access the routes. + +6. If the selected gossip action is not 0, we assume it corresponds to regular taxi functionality and send the taxi menu to the player using `player.SendTaxiMenu(creature.GetGUID())`. + +7. If the creature is not a taxi master, we handle other gossip options accordingly. + +8. Finally, we register the gossip select event for the specific NPC entry using `RegisterCreatureGossipEvent()`. + +This example showcases how the `IsTaxi()` method can be used in conjunction with other Eluna methods and game logic to create a custom taxi system with special unlock requirements. + +## IsTrainer +This method returns true if the [Unit](./unit.md) is a trainer, false otherwise. This can be helpful to create custom trainer interactions, or check if a unit should have trainer capabilities. + +### Parameters +None + +### Returns +boolean: Returns true if the unit is a trainer. + +### Example Usage +Create an interaction with an NPC that will train the player if the unit is a trainer. If not a trainer, give a custom message. +```typescript +const TALK_TRAINER: action_on_gossip_hello = (player: Player, unit: Unit) => { + if(unit.IsTrainer()) { + player.SendTrainerList(unit); + return; + } + else { + const message = `I am ${unit.GetName()}, not a trainer. Did you need something else?`; + + switch(unit.GetEntry()) { + case 1234: // Innkeeper + player.GossipMenuAddItem(GossipIcon.Accept, "I'd like to browse your goods", 0, 0); + player.GossipMenuAddItem(GossipIcon.Accept, "I require a bed for the night", 0, 1); + break; + case 4321: // Stable Master + player.GossipMenuAddItem(GossipIcon.Taxi, "I'd like to stable my pet", 0, 5); + player.GossipMenuAddItem(GossipIcon.Interact_1, "Do you have any pets for sale?", 0, 6); + break; + } + player.GossipSendTextMenu(unit, message); + } +} + +const HANDLE_TRAINER_GOODBYE: action_on_gossip_select = (player: Player, unit: Unit, menuId: number, gossipListId: number) => { + if(menuId == 0 && gossipListId == 0) { + player.SendListInventory(unit); + player.GossipComplete(); + return; + } + + player.GossipComplete(); +} + +RegisterUnitGossipEvent(0, 1234, TALK_TRAINER); +RegisterUnitGossipEvent(0, 4321, TALK_TRAINER); +RegisterUnitGossipSelectEvent(0, HANDLE_TRAINER_GOODBYE); +``` + +## IsUnderWater +This method checks if the unit is currently underwater. It can be useful for applying special effects, modifying abilities, or triggering events when a unit enters or leaves water. + +### Parameters +This method does not take any parameters. + +### Returns +boolean - Returns `true` if the unit is underwater, `false` otherwise. + +### Example Usage +In this example, we'll create a script that applies a periodic damage effect to players while they are underwater, simulating drowning damage. + +```typescript +const DROWNING_DAMAGE_SPELL_ID = 37284; // Spell ID for periodic drowning damage +const DROWNING_DAMAGE_INTERVAL = 2000; // Interval in milliseconds between each damage tick + +let drowningPlayers: Map = new Map(); // Map to store player GUIDs and their periodic damage timer IDs + +const OnPlayerUpdate: player_event_on_update = (event: number, player: Player): void => { + if (player.IsUnderWater()) { + if (!drowningPlayers.has(player.GetGUID())) { + // Player is underwater and not already taking drowning damage + const timerId = player.RegisterTimedEvent(DROWNING_DAMAGE_INTERVAL, 0, () => { + player.CastSpell(player, DROWNING_DAMAGE_SPELL_ID, true); + }); + drowningPlayers.set(player.GetGUID(), timerId); + } + } else { + if (drowningPlayers.has(player.GetGUID())) { + // Player is no longer underwater, remove the periodic damage + const timerId = drowningPlayers.get(player.GetGUID()); + player.RemoveTimedEvent(timerId); + drowningPlayers.delete(player.GetGUID()); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE, (...args) => OnPlayerUpdate(...args)); +``` + +In this script: +1. We define constants for the drowning damage spell ID and the interval between each damage tick. +2. We create a `Map` called `drowningPlayers` to store player GUIDs and their associated periodic damage timer IDs. +3. In the `OnPlayerUpdate` event, we check if the player is underwater using `player.IsUnderWater()`. +4. If the player is underwater and not already taking drowning damage (not present in the `drowningPlayers` map), we register a timed event using `player.RegisterTimedEvent()` to periodically apply the drowning damage spell to the player. We store the timer ID in the `drowningPlayers` map. +5. If the player is no longer underwater and has an active drowning damage timer (present in the `drowningPlayers` map), we remove the timed event using `player.RemoveTimedEvent()` and remove the player from the `drowningPlayers` map. +6. Finally, we register the `OnPlayerUpdate` event using `RegisterPlayerEvent()` to continuously monitor the player's underwater status and apply or remove the drowning damage accordingly. + +This script demonstrates how the `IsUnderWater()` method can be used to create dynamic gameplay elements based on the unit's position relative to water. + +## IsVendor +Returns true if the unit is a vendor NPC. + +### Parameters +None + +### Returns +boolean - Returns `true` if the unit is a vendor, `false` otherwise. + +### Example Usage +Create a script that allows players to access a vendor's inventory by targeting them and using a custom command. + +```typescript +// Custom chat command `.vendor` to open targeted vendor's inventory +const vendorCommand: player_event_on_command = (event: number, player: Player, command: string): void => { + if (command !== 'vendor') { + return; + } + + const target = player.GetSelection(); + if (!target || !target.IsVendor()) { + player.SendBroadcastMessage('You must target a vendor NPC to use this command.'); + return; + } + + // Open the vendor's inventory for the player + player.SendVendorWindow(target); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => vendorCommand(...args)); +``` + +In this example, we create a custom chat command `.vendor` that players can use to access a vendor's inventory. When the command is executed, the script performs the following steps: + +1. Check if the command is `.vendor`. If not, return early. +2. Get the player's currently selected target using `player.GetSelection()`. +3. Check if the target exists and is a vendor using `target.IsVendor()`. If either condition is false, send an error message to the player and return early. +4. If the target is a valid vendor, open the vendor's inventory window for the player using `player.SendVendorWindow(target)`. + +This script allows players to quickly access a vendor's inventory by targeting the vendor NPC and using the `.vendor` command. It demonstrates the usage of the `IsVendor()` method to check if the targeted unit is a vendor before attempting to open the vendor window. + +## Kill +Makes the [Unit] kill the target [Unit]. This will cause the target to die and the [Unit] to perform a killing blow animation if possible. + +### Parameters +* target: [Unit](./unit.md) - The [Unit] to kill +* durLoss?: boolean - Optional parameter to determine if the target's items suffer durability loss. Defaults to 'true' if not provided. + +### Example Usage +In this example, we register an event that checks if a player kills a specific creature. If the creature is killed, it will respawn after 30 seconds and broadcast a message to the entire server. + +```typescript +const CREATURE_ENTRY = 1234; +const RESPAWN_DELAY = 30000; // 30 seconds + +const onCreatureKill: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + if (creature.GetEntry() === CREATURE_ENTRY) { + creature.Respawn(RESPAWN_DELAY); + SendServerMessage(`${creature.GetName()} has been slain by ${player.GetName()}! It will respawn in 30 seconds.`); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => onCreatureKill(...args)); +``` + +In this more advanced example, we create a script that allows players to challenge each other to a duel. When a player wins the duel, the losing player is killed without durability loss, and the winner is restored to full health and mana. + +```typescript +let activeDuel: [Player, Player] | null = null; + +const startDuel = (player1: Player, player2: Player) => { + activeDuel = [player1, player2]; + player1.SetFaction(1); // Set players to hostile factions + player2.SetFaction(2); + SendBroadcastMessage(`A duel has started between ${player1.GetName()} and ${player2.GetName()}!`); +}; + +const endDuel = (winner: Player, loser: Player) => { + winner.Kill(loser, false); // Kill the losing player without durability loss + winner.SetHealth(winner.GetMaxHealth()); // Restore the winner's health + winner.SetPower(PowerType.POWER_MANA, winner.GetMaxPower(PowerType.POWER_MANA)); // Restore the winner's mana + winner.SetFaction(35); // Reset player factions to friendly + loser.SetFaction(35); + activeDuel = null; + SendBroadcastMessage(`${winner.GetName()} has won the duel against ${loser.GetName()}!`); +}; + +const onChatCommand: player_event_on_command = (event: number, player: Player, command: string, args: string) => { + if (command === "duel" && args) { + const target = GetPlayerByName(args); + if (target && target.IsInWorld() && target.GetDistance(player) <= 10) { + if (!activeDuel) { + startDuel(player, target); + } else { + player.SendBroadcastMessage("A duel is already in progress. Please wait for it to finish."); + } + } else { + player.SendBroadcastMessage("Player not found or too far away."); + } + } +}; + +const onPlayerDeath: player_event_on_death = (event: number, player: Player) => { + if (activeDuel && (activeDuel[0] === player || activeDuel[1] === player)) { + const [player1, player2] = activeDuel; + endDuel(player1 === player ? player2 : player1, player); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_COMMAND, (...args) => onChatCommand(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => onPlayerDeath(...args)); +``` + +## ModifyPower +Modifies the [Unit]'s power amount for the given power type. The power types are defined in an enum called `Powers`. + +### Parameters +* amount: number - The amount to modify the power by. Positive values will increase the power, while negative values will decrease it. +* type: number - The type of power to modify. This should be one of the values from the `Powers` enum. + +### Example Usage +In this example, we'll create a script that modifies a player's power based on the type of creature they kill. + +```typescript +const CreatureKillPower: player_event_on_kill_creature = (event: number, player: Player, creature: Creature) => { + const creatureEntry = creature.GetEntry(); + + switch (creatureEntry) { + case 1234: // Mana-infused Creature + player.ModifyPower(100, Powers.POWER_MANA); + player.SendBroadcastMessage("You feel a surge of mana as you defeat the mana-infused creature!"); + break; + case 5678: // Rage-inducing Creature + player.ModifyPower(50, Powers.POWER_RAGE); + player.SendBroadcastMessage("Your rage builds as you slay the enraging creature!"); + break; + case 9012: // Focus-enhancing Creature + player.ModifyPower(75, Powers.POWER_FOCUS); + player.SendBroadcastMessage("Your focus sharpens after defeating the elusive creature!"); + break; + default: + // No power modification for other creatures + break; + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_CREATURE, (...args) => CreatureKillPower(...args)); +``` + +In this script, we register a `PLAYER_EVENT_ON_KILL_CREATURE` event handler. When a player kills a creature, the `CreatureKillPower` function is called. + +Inside the function, we check the entry of the killed creature using `creature.GetEntry()`. Based on the creature's entry, we modify the player's power using `player.ModifyPower()`. + +- If the creature entry is `1234`, we assume it's a mana-infused creature. We increase the player's mana by 100 points using `player.ModifyPower(100, Powers.POWER_MANA)`. +- If the creature entry is `5678`, we consider it a rage-inducing creature. We increase the player's rage by 50 points using `player.ModifyPower(50, Powers.POWER_RAGE)`. +- If the creature entry is `9012`, we treat it as a focus-enhancing creature. We increase the player's focus by 75 points using `player.ModifyPower(75, Powers.POWER_FOCUS)`. + +After modifying the power, we send a broadcast message to the player using `player.SendBroadcastMessage()` to inform them about the power modification. + +This script demonstrates how you can use the `ModifyPower` method to dynamically adjust a player's power based on the type of creature they defeat, providing a more engaging and interactive gameplay experience. + +## Mount +This method allows you to mount the Unit on a specified displayID or modelID. When a Unit is mounted, it will display the model associated with the given displayID/modelID. + +### Parameters +* displayId: number - The displayID or modelID of the mount to be used. + +### Example Usage +Here's an example of how to use the `Mount` method to create a script that allows players to mount a specific creature when they interact with it: + +```typescript +const MOUNT_DISPLAY_ID = 6471; // Display ID of the mount (e.g., Black Qiraji Battle Tank) +const MOUNT_SPELL_ID = 25953; // Spell ID of the mount ability (e.g., Charm of Swift Flight) + +const onGossipHello: gossip_event_on_hello = (event: number, player: Player, creature: Creature) => { + player.GossipMenuAddItem(0, "Mount the creature", 0, 1); + player.GossipSendMenu(1, creature, 0); +}; + +const onGossipSelect: gossip_event_on_select = (event: number, player: Player, creature: Creature, sender: number, intid: number) => { + if (intid === 1) { + if (!player.HasSpell(MOUNT_SPELL_ID)) { + player.LearnSpell(MOUNT_SPELL_ID); + } + + if (!creature.IsMounted()) { + creature.Mount(MOUNT_DISPLAY_ID); + creature.SetSpeed(UnitMoveType.MOVE_RUN, 2.0); + creature.SetFlag(UnitFields.UNIT_FIELD_FLAGS, UnitFlags.UNIT_FLAG_PLAYER_CONTROLLED); + creature.SetControlled(true, UnitControlTypes.UNIT_CONTROL_PLAYER); + creature.SetOwnerGUID(player.GetGUID()); + + player.EnterVehicle(creature, 0); + } + + player.GossipComplete(); + } +}; + +RegisterCreatureGossipEvent(CREATURE_ENTRY, GossipEvents.GOSSIP_EVENT_ON_HELLO, (...args) => onGossipHello(...args)); +RegisterCreatureGossipEvent(CREATURE_ENTRY, GossipEvents.GOSSIP_EVENT_ON_SELECT, (...args) => onGossipSelect(...args)); +``` + +In this example: +1. When a player interacts with the specified creature, a gossip menu is displayed with the option to mount the creature. +2. If the player selects the mount option, the script checks if the player has the required mount ability spell. If not, it learns the spell. +3. If the creature is not already mounted, the script mounts the creature using the specified display ID. +4. The creature's speed is increased, and it is set to be player-controlled. +5. The player enters the vehicle (mount) on the creature. + +Note: Make sure to replace `CREATURE_ENTRY` with the actual entry ID of the creature you want to use for mounting. + +This example demonstrates how the `Mount` method can be used in combination with other methods and events to create an interactive mounting system in your mod. + +## MoveChase +The `MoveChase` method allows the [Unit] to chase a target [Unit] while maintaining a specified distance and angle relative to the target. + +### Parameters +* target: [Unit](./unit.md) - The target [Unit] to chase. +* dist: number (optional) - The distance to maintain between the [Unit] and the target. Default value is 0. +* angle: number (optional) - The angle in radians to maintain relative to the target. Default value is 0. + +### Example Usage +In this example, we create an AI script for a creature that chases a random player within a certain range until the player is caught or the creature loses sight of the player. + +```typescript +const CHASE_RANGE = 30; // The maximum range to start chasing a player +const CATCH_DISTANCE = 2; // The distance at which the creature catches the player + +const onUpdate: creature_event_on_update = (event: number, creature: Creature, diff: number) => { + if (!creature.IsInCombat() && !creature.HasAura(STUN_AURA)) { + const nearestPlayer = creature.GetNearestPlayer(CHASE_RANGE); + + if (nearestPlayer) { + creature.MoveChase(nearestPlayer, CATCH_DISTANCE); + + const distance = creature.GetDistance(nearestPlayer); + if (distance <= CATCH_DISTANCE) { + creature.CastSpell(nearestPlayer, STUN_SPELL, true); + creature.DealDamage(nearestPlayer, nearestPlayer.GetHealth() * 0.2, true); + creature.MonsterSay("Caught you!", LANG_UNIVERSAL, nearestPlayer); + } + } else { + creature.MoveRandomPosition(CHASE_RANGE); + } + } +} + +RegisterCreatureEvent(CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => onUpdate(...args)); +``` + +In this script: +1. We define constants for the maximum chase range and catch distance. +2. In the `onUpdate` event, we check if the creature is not in combat and not stunned. +3. We use `GetNearestPlayer` to find the nearest player within the `CHASE_RANGE`. +4. If a player is found, we use `MoveChase` to make the creature chase the player, maintaining the specified `CATCH_DISTANCE`. +5. We calculate the distance between the creature and the player using `GetDistance`. +6. If the distance is less than or equal to the `CATCH_DISTANCE`, the creature catches the player: + - The creature casts a stun spell on the player using `CastSpell`. + - The creature deals 20% of the player's health as damage using `DealDamage`. + - The creature says "Caught you!" to the player using `MonsterSay`. +7. If no player is found within the chase range, the creature moves to a random position within the `CHASE_RANGE` using `MoveRandomPosition`. + +This script demonstrates how the `MoveChase` method can be used in combination with other methods and events to create engaging AI behavior for creatures in the game. + +## MoveClear +Clears the unit's movement and stops them from moving. Optionally resets the unit's movement to their original position. + +### Parameters +* reset: boolean (optional) - If 'true', the unit's movement will be reset to their original position. Default: 'false' + +### Example Usage +Freeze a creature in place and prevent them from moving until attacked. +```typescript +let AGGRESSIVE_CREATURE_ENTRY = 1234; +let AGGRESSIVE_AURA = 5678; + +const onCreatureSpawn: creature_event_on_spawn = (event: number, creature: Creature) => { + if (creature.GetEntry() === AGGRESSIVE_CREATURE_ENTRY) { + // Stop the creature from moving + creature.MoveClear(); + + // Set the creature as unattackable + creature.SetUInt32Value(UnitFields.UNIT_FIELD_FLAGS, 0x02); + + // Add an aura that forces the creature to stand still + creature.AddAura(AGGRESSIVE_AURA, creature); + + // Register an event to allow the creature to move and attack when attacked + RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_DAMAGE_TAKEN, (event: number, creature: Creature, attacker: Unit) => { + if (creature.GetEntry() === AGGRESSIVE_CREATURE_ENTRY) { + // Allow the creature to move again + creature.MoveClear(true); + + // Remove the unattackable flag + creature.SetUInt32Value(UnitFields.UNIT_FIELD_FLAGS, 0x00); + + // Remove the aura that forces the creature to stand still + creature.RemoveAura(AGGRESSIVE_AURA); + + // Force the creature to attack the player + creature.AttackStart(attacker); + } + }); + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => onCreatureSpawn(...args)); +``` + +In this example, when a specific aggressive creature spawns, it is immediately frozen in place and made unattackable. An aura is applied to the creature to visually indicate that it is not moving. When the creature takes damage from an attacker, the `MoveClear` method is called with `reset` set to `true`, which allows the creature to move again. The unattackable flag and aura are removed, and the creature is forced to attack the player who attacked it. + +This script could be used to create a more challenging encounter where the player must strategically attack the creature to unfreeze it and engage in combat, rather than the creature immediately attacking on spawn. + +## MoveConfused +This method will cause the [Unit] to move in a confused state for a short period of time. The unit will move erratically in random directions for a few seconds. + +### Parameters +None + +### Returns +None + +### Example Usage +Here's an example of how to use `MoveConfused` in a script that causes all nearby enemy units to become confused when a player dies: + +```typescript +const CONFUSION_RADIUS = 10; // Radius in yards around the player to confuse units + +const OnPlayerDeath: player_event_on_death = (event: number, player: Player, killer: Unit) => { + // Get all enemy units within the specified radius of the player + const nearbyUnits = player.GetUnitsInRange(CONFUSION_RADIUS, 0, true); + + // Loop through each nearby unit + for (const unit of nearbyUnits) { + // Skip dead or confused units + if (unit.IsDead() || unit.HasAura(14821)) { + continue; + } + + // Randomly decide whether to confuse the unit (50% chance) + if (Math.random() < 0.5) { + unit.MoveConfused(); + + // Also apply a confusion spell visual for added effect + unit.CastSpell(unit, 14821, true); + + // Optionally, make the unit say a confused emote + unit.SendUnitEmote("looks confused!", 0); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_DEATH, (...args) => OnPlayerDeath(...args)); +``` + +In this example, when a player dies, the script will find all nearby enemy units within a radius of 10 yards. For each unit, there is a 50% chance that it will be forced to move in a confused state using `MoveConfused()`. + +To enhance the effect, the script also applies a confusion spell visual to the unit using `CastSpell()` and makes the unit display a confused emote using `SendUnitEmote()`. + +This script can add some interesting and chaotic behavior to combat encounters, especially if there are many enemies near the player when they die. The confusion effect can temporarily disrupt enemy formations and create openings for other players to exploit. + +## MoveExpire +This method expires the [Unit]'s current movement and clears the movement generator. Optionally, you can reset the movement generator to its default state. + +### Parameters +* reset (optional): boolean - If 'true', the movement generator will be reset to its default state. Default is 'false'. + +### Example Usage +In this example, we create a script that expires a creature's movement and resets its movement generator when it reaches a certain health threshold. This can be useful for creating more dynamic and challenging encounters. + +```typescript +const CREATURE_ENTRY = 1234; +const HEALTH_THRESHOLD = 30; + +const OnCreatureHealthChanged: creature_event_on_health_change = (event: number, creature: Creature, attacker: Unit) => { + const healthPercent = creature.GetHealthPct(); + + if (healthPercent <= HEALTH_THRESHOLD) { + // Expire the creature's current movement + creature.MoveExpire(true); + + // Set the creature to evade mode + creature.SetEvadeMode(); + + // Move the creature to a specific position + const x = 100.0; + const y = 200.0; + const z = 50.0; + const o = 0.0; + creature.MoveTo(x, y, z, o); + + // Make the creature say something + creature.Say("I will not be defeated so easily!", 0); + + // Reset the creature's health + creature.SetHealth(creature.GetMaxHealth()); + + // Remove the creature from combat + creature.ClearInCombat(); + + // Despawn the creature after 5 seconds + creature.DespawnOrUnsummon(5000); + } +}; + +RegisterCreatureEvent(CREATURE_ENTRY, CreatureEvents.CREATURE_EVENT_ON_HEALTH_CHANGE, OnCreatureHealthChanged); +``` + +In this script: +1. We define the creature entry and the health threshold at which the script will trigger. +2. When the creature's health changes, we check if its current health percentage is below or equal to the threshold. +3. If the condition is met, we expire the creature's current movement and reset its movement generator using `creature.MoveExpire(true)`. +4. We set the creature to evade mode using `creature.SetEvadeMode()`. +5. We move the creature to a specific position using `creature.MoveTo(x, y, z, o)`. +6. We make the creature say something using `creature.Say()`. +7. We reset the creature's health to its maximum value using `creature.SetHealth(creature.GetMaxHealth())`. +8. We remove the creature from combat using `creature.ClearInCombat()`. +9. Finally, we despawn the creature after 5 seconds using `creature.DespawnOrUnsummon(5000)`. + +This script showcases how the `MoveExpire()` method can be used in combination with other methods to create more engaging and dynamic creature encounters. + +## MoveFleeing +The `MoveFleeing` method causes the [Unit](./unit.md) to flee from the specified target for a given duration. If no duration is provided, the default fleeing time will be used. + +### Parameters +* target: [Unit](./unit.md) - The target [Unit](./unit.md) to flee from. +* time: number (optional) - The duration in milliseconds for which the [Unit](./unit.md) will flee. If not specified, the default fleeing time will be used. + +### Example Usage +In this example, we create a script that causes a creature to flee from a player when the player gets too close. If the player remains within a certain range of the creature for more than 5 seconds, the creature will start fleeing for 10 seconds. + +```typescript +const FLEE_DISTANCE = 10; // Distance in yards at which the creature starts fleeing +const FLEE_DURATION = 10000; // Fleeing duration in milliseconds (10 seconds) +const CHECK_INTERVAL = 5000; // Check interval in milliseconds (5 seconds) + +let lastCheckTime = 0; + +const onCreatureUpdate: creature_event_on_update = (event: number, creature: Creature, diff: number) => { + const now = GetTime(); + + if (now - lastCheckTime >= CHECK_INTERVAL) { + lastCheckTime = now; + + const nearestPlayer = creature.GetNearestPlayer(FLEE_DISTANCE); + + if (nearestPlayer) { + creature.MoveFleeing(nearestPlayer, FLEE_DURATION); + creature.SendUnitSay("I must flee from this dangerous player!", 0); + } + } +}; + +RegisterCreatureEvent(CreatureEntry, CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => onCreatureUpdate(...args)); +``` + +In this script: +1. We define constants for the flee distance, flee duration, and check interval. +2. We initialize a variable `lastCheckTime` to keep track of the last time we checked for nearby players. +3. In the `onCreatureUpdate` event, we check if the specified check interval has passed since the last check. +4. If the check interval has passed, we update `lastCheckTime` and use the `GetNearestPlayer` method to find the nearest player within the flee distance. +5. If a nearby player is found, we call the `MoveFleeing` method on the creature, passing the nearest player as the target and the specified flee duration. +6. We also make the creature say a message using `SendUnitSay` to indicate that it is fleeing from the player. +7. Finally, we register the `onCreatureUpdate` event for the specific creature entry using `RegisterCreatureEvent`. + +This script ensures that the creature starts fleeing when a player gets too close and continues fleeing for the specified duration. The creature will only start fleeing again if the player remains within the flee distance for more than the check interval. + +## MoveFollow +Makes the [Unit] follow the specified target unit, maintaining a specified distance and angle relative to the target. + +### Parameters +* target: [Unit](./unit.md) - The target unit to follow +* dist: number (optional) - The distance to maintain from the target unit (default: 0) +* angle: number (optional) - The angle in radians to maintain relative to the target unit (default: 0) + +### Example Usage +Create an NPC that follows the player, assisting in combat and providing buffs. +```typescript +const FOLLOW_DISTANCE = 3; +const FOLLOW_ANGLE = 0; + +const onGossipHello: gossip_event_on_hello = (event: number, player: Player, object: GameObject) => { + const followerNPC = object.ToCreature(); + if (!followerNPC) { + return; + } + + followerNPC.SetFaction(player.GetFaction()); + followerNPC.SetLevel(player.GetLevel()); + followerNPC.SetMaxHealth(player.GetMaxHealth() * 0.8); + followerNPC.SetHealth(followerNPC.GetMaxHealth()); + followerNPC.SetMana(followerNPC.GetMaxMana()); + + const onCombat: creature_event_on_enter_combat = (event: number, creature: Creature, target: Unit) => { + creature.MoveFollow(player, FOLLOW_DISTANCE, FOLLOW_ANGLE); + }; + + const onLeaveCombat: creature_event_on_leave_combat = (event: number, creature: Creature) => { + creature.MoveFollow(player, FOLLOW_DISTANCE, FOLLOW_ANGLE); + }; + + RegisterCreatureEvent(followerNPC.GetEntry(), CreatureEvents.CREATURE_EVENT_ON_ENTER_COMBAT, onCombat); + RegisterCreatureEvent(followerNPC.GetEntry(), CreatureEvents.CREATURE_EVENT_ON_LEAVE_COMBAT, onLeaveCombat); + + followerNPC.MoveFollow(player, FOLLOW_DISTANCE, FOLLOW_ANGLE); +}; + +const onGossipSelect: gossip_event_on_select = (event: number, player: Player, object: GameObject, sender: number, code: number, menu: string) => { + // Handle gossip menu actions +}; + +RegisterGameObjectGossipEvent(GO_ENTRY, GossipEvents.GOSSIP_EVENT_ON_HELLO, onGossipHello); +RegisterGameObjectGossipEvent(GO_ENTRY, GossipEvents.GOSSIP_EVENT_ON_SELECT, onGossipSelect); +``` +In this example, when a player interacts with a specific game object (GO_ENTRY), the `onGossipHello` event is triggered. The script retrieves the creature associated with the game object and sets up the follower NPC. + +The follower NPC's faction, level, health, and mana are adjusted based on the player's stats. Event handlers are registered for the follower NPC's enter combat and leave combat events. In both cases, the follower NPC is instructed to follow the player using `MoveFollow` with the specified distance and angle. + +The follower NPC will assist the player in combat and maintain the specified distance and angle relative to the player. Additional functionality, such as providing buffs or handling gossip menu actions, can be added as needed. + +## MoveHome +This method will cause the [Unit] to move back to its original home location. The home location is set based on the spawn location from the database for the creature. + +### Parameters +None + +### Returns +None + +### Example Usage +In this example, we have a world boss that will target a random player in the raid and chase them down for 30 seconds. After the 30 seconds, the boss will retreat to its home location to begin a new phase of the fight. + +```typescript +const BOSS_ENTRY = 500000; +const CHASE_PHASE_DURATION = 30000; + +const StartChasePhase = (boss: Unit) => { + const players = boss.GetPlayersInRange(100); + if (players.length > 0) { + const randomPlayer = players[Math.floor(Math.random() * players.length)]; + boss.MoveTo(randomPlayer.GetX(), randomPlayer.GetY(), randomPlayer.GetZ()); + + boss.RegisterEvent(() => { + boss.MoveHome(); + StartNewPhase(boss); + }, CHASE_PHASE_DURATION); + } +} + +const StartNewPhase = (boss: Unit) => { + // Begin a new phase of the fight + // ... +} + +const OnBossSpawn = (event: number, creature: Creature) => { + if (creature.GetEntry() === BOSS_ENTRY) { + StartChasePhase(creature); + } +} + +RegisterServerEvent(ServerEvents.CREATURE_ON_SPAWN, (...args) => OnBossSpawn(...args)); +``` + +In this script, when the boss creature spawns, it will start the chase phase by selecting a random player within 100 yards and moving towards their location. After 30 seconds (defined by `CHASE_PHASE_DURATION`), the boss will use `MoveHome()` to return to its original spawn location and then start a new phase of the fight using the `StartNewPhase` function. + +This example demonstrates how `MoveHome()` can be used in conjunction with other methods and events to create dynamic and interesting encounter mechanics in your mod. + +## MoveIdle +This method will cause the [Unit] to enter an idle state and stop moving. The unit will remain idle until it receives new movement orders or is engaged in combat. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any values. + +### Example Usage +In this example, we'll create a script that forces all creatures in a certain radius around the player to become idle when the player enters the world. This could be useful for setting up a safe zone or a non-combat area. + +```typescript +const IDLE_RADIUS = 30; // The radius in yards around the player in which creatures will be made idle + +const OnPlayerEnterWorld: player_event_on_enter_world = (event: number, player: Player) => { + // Get all creatures in the specified radius around the player + const creatures = player.GetCreaturesInRange(IDLE_RADIUS); + + // Loop through each creature and make it idle + for (const creature of creatures) { + creature.MoveIdle(); + + // Optionally, we can also clear the creature's threat list to ensure it doesn't engage in combat + creature.ClearThreatList(); + + // We can also set the creature's movement type to idle to prevent it from resuming its default movement + creature.SetMovementType(0); // 0 corresponds to IDLE_MOTION_TYPE + } + + // Inform the player about what happened + player.SendBroadcastMessage(`All creatures within ${IDLE_RADIUS} yards have been made idle.`); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_WORLD, (...args) => OnPlayerEnterWorld(...args)); +``` + +In this script: +1. We define a constant `IDLE_RADIUS` to specify the radius around the player in which creatures will be made idle. +2. In the `OnPlayerEnterWorld` event, we get all creatures within the specified radius using `player.GetCreaturesInRange(IDLE_RADIUS)`. +3. We loop through each creature and call `creature.MoveIdle()` to make it idle. +4. Optionally, we also clear the creature's threat list using `creature.ClearThreatList()` to ensure it doesn't engage in combat even if it was previously threatened. +5. We set the creature's movement type to idle (`IDLE_MOTION_TYPE`) using `creature.SetMovementType(0)` to prevent it from resuming its default movement. +6. Finally, we inform the player about what happened by sending a broadcast message using `player.SendBroadcastMessage()`. + +This script showcases a practical use case for the `MoveIdle()` method, demonstrating how it can be used in combination with other methods to create a specific game mechanic or behavior. + +## MoveJump +Makes the Unit jump to the specified coordinates with the given speed and maximum height. This method can be used to create dynamic movement or jumping effects for units, such as making a boss leap to a specific location during an encounter or having a creature jump across gaps or obstacles. + +### Parameters +- x: number - The destination X coordinate. +- y: number - The destination Y coordinate. +- z: number - The destination Z coordinate. +- zSpeed: number - The speed of the vertical (Z) movement during the jump. +- maxHeight: number - The maximum height the Unit will reach during the jump. +- id: number (optional) - The spline ID for the jump movement. If not provided, a default value will be used. + +### Example Usage +In this example, we create a world event script that makes a boss creature jump to a random player's position every 30 seconds. + +```typescript +const BOSS_ENTRY = 12345; +const JUMP_INTERVAL = 30000; // 30 seconds + +const BossJumpEvent: world_event_on_update = (event: number, diff: number) => { + const boss = GetWorldObject(BOSS_ENTRY); + if (!boss || boss.GetTypeId() !== ObjectType.UNIT) { + return; + } + + const players = boss.GetPlayersInRange(100); + if (players.length === 0) { + return; + } + + const randomPlayer = players[Math.floor(Math.random() * players.length)]; + const playerPosition = randomPlayer.GetLocation(); + + boss.MoveJump(playerPosition.x, playerPosition.y, playerPosition.z, 10, 5); +}; + +RegisterWorldEvent(WorldEvents.WORLD_EVENT_ON_UPDATE, (...args) => BossJumpEvent(...args)); + +let jumpTimerId: number | null = null; + +const StartJumpTimer = () => { + if (jumpTimerId) { + return; + } + + jumpTimerId = CreateTimer(JUMP_INTERVAL, () => { + BossJumpEvent(0, 0); + }, 0, JUMP_INTERVAL); +}; + +const StopJumpTimer = () => { + if (!jumpTimerId) { + return; + } + + DestroyTimer(jumpTimerId); + jumpTimerId = null; +}; + +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_CREATURE_SPAWN, (entry: number) => { + if (entry === BOSS_ENTRY) { + StartJumpTimer(); + } +}); + +RegisterServerEvent(ServerEvents.SERVER_EVENT_ON_CREATURE_DESPAWN, (entry: number) => { + if (entry === BOSS_ENTRY) { + StopJumpTimer(); + } +}); +``` + +In this script, we define a world event that runs every game tick (WORLD_EVENT_ON_UPDATE). When the event is triggered, we check if the boss creature exists and if there are any players within a 100-yard range. If both conditions are met, we randomly select a player and make the boss jump to their position using the `MoveJump` method. + +We also set up a timer that triggers the jump event every 30 seconds using the `CreateTimer` function. The timer is started when the boss creature spawns (SERVER_EVENT_ON_CREATURE_SPAWN) and stopped when the boss despawns (SERVER_EVENT_ON_CREATURE_DESPAWN). + +This example demonstrates how the `MoveJump` method can be used to create dynamic and engaging encounters by making creatures jump to specific locations or player positions during combat. + +## MoveRandom +The `MoveRandom` method causes the [Unit](./unit.md) to move in a random direction within a specified radius. This can be useful for simulating wandering behavior or adding unpredictability to NPC movement patterns. + +### Parameters +* radius: number - The maximum distance the unit can move from its current position. + +### Example Usage +Here's an example of how to use the `MoveRandom` method to create a wandering NPC that moves randomly every 5 seconds within a 20-yard radius: + +```typescript +const WANDER_RADIUS = 20; +const WANDER_INTERVAL = 5000; // 5 seconds + +const onCreatureUpdate: creature_event_on_update = (event: number, creature: Creature, diff: number) => { + creature.RegisterEvent(() => { + creature.MoveRandom(WANDER_RADIUS); + }, WANDER_INTERVAL); +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => onCreatureUpdate(...args)); +``` + +In this example, we define constants for the wander radius and interval. Inside the `CREATURE_EVENT_ON_UPDATE` event, we register a new event using `creature.RegisterEvent`. This event will be triggered every `WANDER_INTERVAL` milliseconds (5 seconds in this case). When the event is triggered, the creature will move randomly within the specified `WANDER_RADIUS` using the `MoveRandom` method. + +You can adjust the `WANDER_RADIUS` and `WANDER_INTERVAL` values to control the size of the wandering area and the frequency of random movements, respectively. + +Note that the `MoveRandom` method only initiates the movement; it does not wait for the movement to complete before returning. If you need to perform actions after the movement is finished, you can use the `CREATURE_EVENT_ON_REACH_WP` event to detect when the creature has reached its destination. + +### Tips +- Be cautious when using large radius values, as they may cause the unit to wander too far from its original position or into unintended areas. +- Consider combining `MoveRandom` with other movement methods, such as `MoveTo` or `MoveFollow`, to create more complex and realistic movement patterns. +- You can use the `creature.GetCurrentWaypointId()` method to determine the current waypoint of the creature after calling `MoveRandom`, which can be useful for implementing specific behaviors at certain locations. + +By utilizing the `MoveRandom` method judiciously, you can add a sense of liveliness and unpredictability to the movement of units in your mod, enhancing the overall gameplay experience. + +## MoveStop +Stops the unit's movement immediately. This method can be useful in various scenarios where you want to halt a unit's movement, such as when they enter a specific area, encounter a certain condition, or need to be stopped for any other reason. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return anything. + +### Example Usage +Let's consider an example where you want to create a "freeze trap" that stops a unit's movement when they step on it. Here's how you can achieve this using the `MoveStop` method: + +```typescript +const FREEZE_TRAP_ENTRY = 100001; +const FREEZE_TRAP_RADIUS = 5; +const FREEZE_DURATION = 5000; // 5 seconds + +const OnAreaTrigger: map_event_on_area_trigger = (event: number, unit: Unit, areaTrigger: AreaTrigger) => { + if (areaTrigger.GetEntry() === FREEZE_TRAP_ENTRY) { + const trapX = areaTrigger.GetPositionX(); + const trapY = areaTrigger.GetPositionY(); + const trapZ = areaTrigger.GetPositionZ(); + + if (unit.IsWithinDist3d(trapX, trapY, trapZ, FREEZE_TRAP_RADIUS)) { + unit.MoveStop(); + unit.CastSpell(unit, 12544, true); // Cast "Frost Armor" visual effect + unit.AddAura(45524, FREEZE_DURATION); // Apply "Chains of Ice" aura for the duration + + const timerId = CreateTimer(FREEZE_DURATION, () => { + unit.RemoveAura(45524); // Remove the "Chains of Ice" aura after the duration + DestroyTimer(timerId); // Clean up the timer + }); + } + } +}; + +RegisterMapEvent(MapEvents.MAP_EVENT_ON_AREA_TRIGGER, (...args) => OnAreaTrigger(...args)); +``` + +In this example: +1. We define constants for the freeze trap entry, radius, and duration. +2. In the `OnAreaTrigger` event handler, we check if the triggered area trigger matches the freeze trap entry. +3. If a unit steps within the specified radius of the freeze trap, we stop their movement using `unit.MoveStop()`. +4. We then apply a visual effect (e.g., "Frost Armor") and an aura (e.g., "Chains of Ice") to the unit for the duration of the freeze effect. +5. We create a timer that removes the aura after the specified duration and cleans up the timer itself. + +This script effectively creates a freeze trap that stops a unit's movement and applies a visual effect and aura when they step on it, immobilizing them for a certain duration. + +Note: Make sure to replace the spell IDs and adjust the constants according to your specific requirements and the spells available in your Azeroth Core database. + +## MoveTo +The `MoveTo` method allows you to move a unit to a specific location in the game world by providing the map ID and coordinates (x, y, z). You can also specify whether to generate a path for the unit to follow. + +### Parameters +- `id`: number - The ID of the map where the unit should move to. +- `x`: number - The X-coordinate of the destination on the specified map. +- `y`: number - The Y-coordinate of the destination on the specified map. +- `z`: number - The Z-coordinate (height) of the destination on the specified map. +- `genPath` (optional): boolean - Determines whether to generate a path for the unit to follow. If set to `true`, the unit will find a path to the destination. If set to `false` or omitted, the unit will move directly to the destination without pathfinding. + +### Example Usage +Moving a creature to a specific location with pathfinding: +```typescript +const STORMWIND_MAP_ID = 0; +const STORMWIND_X = -8913.23; +const STORMWIND_Y = 554.633; +const STORMWIND_Z = 93.7944; + +const MoveCreatureToStormwind: creature_event_on_spawn = (event: number, creature: Creature) => { + // Move the creature to Stormwind with pathfinding + creature.MoveTo(STORMWIND_MAP_ID, STORMWIND_X, STORMWIND_Y, STORMWIND_Z, true); +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => MoveCreatureToStormwind(...args)); +``` + +Teleporting a player to a random location within a certain range: +```typescript +const TELEPORT_RANGE = 10; + +const RandomTeleportPlayer: player_event_on_login = (event: number, player: Player) => { + const mapId = player.GetMapId(); + const x = player.GetX(); + const y = player.GetY(); + const z = player.GetZ(); + + // Generate random coordinates within the specified range + const randomX = x + Math.random() * TELEPORT_RANGE * (Math.random() < 0.5 ? -1 : 1); + const randomY = y + Math.random() * TELEPORT_RANGE * (Math.random() < 0.5 ? -1 : 1); + + // Teleport the player to the random location without pathfinding + player.MoveTo(mapId, randomX, randomY, z); + + // Send a message to the player + player.SendBroadcastMessage(`You have been teleported to a random location within ${TELEPORT_RANGE} yards!`); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => RandomTeleportPlayer(...args)); +``` + +In the first example, we register a creature event that triggers when a creature spawns. When the event is triggered, we use the `MoveTo` method to move the creature to a specific location in Stormwind, specifying the map ID and coordinates. We set `genPath` to `true` to ensure the creature follows a path to the destination. + +In the second example, we register a player event that triggers when a player logs in. We generate random coordinates within a specified range (`TELEPORT_RANGE`) based on the player's current location. We then use the `MoveTo` method to teleport the player to the random location without pathfinding. Finally, we send a message to the player informing them about the teleportation. + +These examples demonstrate how the `MoveTo` method can be used to move units to specific locations or teleport them to random positions within a certain range. + +## NearTeleport +This method will teleport the unit to the specified coordinates within the same map. This can be useful for moving units around the world quickly without the need for pathing or movement. + +### Parameters +* x: number - The x coordinate to teleport the unit to +* y: number - The y coordinate to teleport the unit to +* z: number - The z coordinate to teleport the unit to +* o: number - The orientation to face the unit after teleport + +### Example Usage: +Here's an example of how you might use `NearTeleport` in a script that teleports a player to a random location within a certain radius of their current position: + +```typescript +const TELEPORT_RADIUS = 10; // 10 yard radius + +const onGossipSelect: gossip_select_hook = (event, player, creature, sender, intid, code, menu_id) => { + if (intid === 1) { + // Get the player's current position + const playerX = player.GetX(); + const playerY = player.GetY(); + const playerZ = player.GetZ(); + const playerO = player.GetO(); + + // Calculate a random offset within the specified radius + const randomAngle = Math.random() * 2 * Math.PI; + const randomDistance = Math.random() * TELEPORT_RADIUS; + const offsetX = Math.cos(randomAngle) * randomDistance; + const offsetY = Math.sin(randomAngle) * randomDistance; + + // Calculate the new coordinates + const newX = playerX + offsetX; + const newY = playerY + offsetY; + const newZ = playerZ; + + // Teleport the player to the new location + player.NearTeleport(newX, newY, newZ, playerO); + + player.SendBroadcastMessage("You have been teleported to a random location nearby!"); + } +}; + +RegisterCreatureGossipEvent(NPC_ID, GOSSIP_EVENT_ON_SELECT, (...args) => onGossipSelect(...args)); +``` + +In this example, when the player selects a specific gossip option (with `intid` 1), the script calculates a random location within a certain radius of the player's current position. It then uses `NearTeleport` to instantly move the player to that location, maintaining their current orientation. + +This can be a fun way to add some unpredictability to player movement, or to create a "random teleport" feature for players to explore the world around them. Just be careful not to teleport players into any dangerous or inaccessible areas! + +## PerformEmote +Makes the unit perform a specified emote animation. + +### Parameters +* emoteId: number - The ID of the emote to perform. Emote IDs can be found in the `emotes` table in the world database. + +### Example Usage +This example script makes a creature perform a random emote every 5 seconds: + +```typescript +const EMOTE_ONESHOT_WOUNDED = 18; +const EMOTE_ONESHOT_ROAR = 15; +const EMOTE_ONESHOT_ATTACKUNARMED = 26; +const EMOTE_ONESHOT_ATTACK1H = 36; +const EMOTE_ONESHOT_POINT = 25; + +const emotes = [ + EMOTE_ONESHOT_WOUNDED, + EMOTE_ONESHOT_ROAR, + EMOTE_ONESHOT_ATTACKUNARMED, + EMOTE_ONESHOT_ATTACK1H, + EMOTE_ONESHOT_POINT +]; + +const CreatureRandomEmote = (entry: number) => { + const creature = GetCreatureByEntry(entry); + + if (!creature || !creature.IsInWorld()) { + return; + } + + const randomEmote = emotes[Math.floor(Math.random() * emotes.length)]; + creature.PerformEmote(randomEmote); + + SetTimeout(() => CreatureRandomEmote(entry), 5000); +}; + +const OnModuleInit: mod_on_module_init = (): void => { + const CREATURE_ENTRY = 1234; // Replace with the desired creature entry ID + CreatureRandomEmote(CREATURE_ENTRY); +}; + +RegisterModEvent('OnModuleInit', OnModuleInit); +``` + +In this script: +1. We define constants for different emote IDs that we want the creature to perform. +2. We create an array called `emotes` that contains the emote IDs. +3. We define a function `CreatureRandomEmote` that takes the creature entry ID as a parameter. +4. Inside the function, we retrieve the creature object using `GetCreatureByEntry` and check if it exists and is in the world. +5. We generate a random index using `Math.floor(Math.random() * emotes.length)` to select a random emote from the `emotes` array. +6. We call the `PerformEmote` method on the creature object, passing the randomly selected emote ID. +7. We use `SetTimeout` to schedule the next emote performance after a 5-second delay (5000 milliseconds) by recursively calling `CreatureRandomEmote` with the same creature entry ID. +8. In the `OnModuleInit` event, we specify the desired creature entry ID and call `CreatureRandomEmote` to start the emote performance loop. + +By registering the `OnModuleInit` event, the script will start executing when the module is initialized, and the creature will perform random emotes every 5 seconds indefinitely. + +Note: Make sure to replace `CREATURE_ENTRY` with the actual entry ID of the creature you want to perform the emotes. + +## RemoveAllAuras +Removes all auras from the Unit, including buffs, debuffs, talents, and racials. This method should be used with caution as it can significantly impact the Unit's performance and abilities. + +### Parameters +None + +### Returns +None + +### Example Usage +In this example, we create a script that removes all auras from a player when they enter a specific area, such as a PvP zone or a boss encounter. This can be useful for creating a level playing field or for preventing players from using certain abilities during the encounter. + +```typescript +const AREA_ID = 1234; // Replace with the ID of the area where auras should be removed + +const OnPlayerEnterArea: player_event_on_area_trigger = (event: number, player: Player, areaId: number) => { + if (areaId === AREA_ID) { + player.RemoveAllAuras(); + player.SendBroadcastMessage("All auras have been removed as you enter the area."); + + // Apply a debuff to prevent players from re-applying auras + const DEBUFF_ENTRY = 5678; // Replace with the ID of the debuff spell + const DEBUFF_DURATION = 60 * IN_MILLISECONDS; // 1 minute duration + player.AddAura(DEBUFF_ENTRY, DEBUFF_DURATION); + + // Notify the player's party members + const group = player.GetGroup(); + if (group) { + group.BroadcastGroupPacket( + CliGmMessage(`${player.GetName()} has entered the area and had all auras removed.`) + ); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER, (...args) => OnPlayerEnterArea(...args)); +``` + +In this script: +1. We define the `AREA_ID` constant with the ID of the area where auras should be removed. +2. When a player enters the specified area, the `OnPlayerEnterArea` event handler is triggered. +3. We check if the entered area matches the `AREA_ID`. +4. If it matches, we call `player.RemoveAllAuras()` to remove all auras from the player. +5. We send a broadcast message to the player informing them that their auras have been removed. +6. To prevent players from immediately re-applying auras, we apply a debuff using `player.AddAura()` with a specific duration (`DEBUFF_DURATION`). +7. If the player is in a group, we notify their party members that the player has entered the area and had their auras removed using `group.BroadcastGroupPacket()`. + +This example demonstrates how to use the `RemoveAllAuras()` method in combination with other methods and events to create a specific gameplay mechanic or encounter. + +## RemoveAura +Removes an aura from the unit based on the spell entry. This can be useful for removing buffs or debuffs from the unit. + +### Parameters +* spell: number - The spell entry ID of the aura to remove. + +### Example Usage +Remove a specific aura from the unit when they enter combat. +```typescript +const AURA_TO_REMOVE = 12345; + +const onEnterCombat: unit_event_on_enter_combat = (event: UnitEvents, unit: Unit, target: Unit) => { + // Check if the unit has the aura + if (unit.HasAura(AURA_TO_REMOVE)) { + // Remove the aura from the unit + unit.RemoveAura(AURA_TO_REMOVE); + + // Notify the unit that the aura was removed + unit.SendBroadcastMessage(`The aura ${AURA_TO_REMOVE} has been removed from you.`); + } +} + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +Another example could be removing a specific aura from the unit when they respawn after dying. +```typescript +const AURA_TO_REMOVE = 67890; + +const onRespawn: unit_event_on_respawn = (event: UnitEvents, unit: Unit) => { + // Check if the unit has the aura + if (unit.HasAura(AURA_TO_REMOVE)) { + // Remove the aura from the unit + unit.RemoveAura(AURA_TO_REMOVE); + + // Notify the unit that the aura was removed + unit.SendBroadcastMessage(`The aura ${AURA_TO_REMOVE} has been removed from you upon respawning.`); + } + + // Check if the unit is a player + if (unit.IsPlayer()) { + const player = unit.ToPlayer(); + + // Send a welcome back message to the player + player.SendBroadcastMessage("Welcome back to the world of the living!"); + } +} + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_RESPAWN, (...args) => onRespawn(...args)); +``` + +In this example, we remove a specific aura from the unit when they respawn after dying. We also check if the unit is a player, and if so, we send them a welcome back message. This can be useful for removing any lingering effects from the unit's previous life, and giving them a fresh start upon respawning. + +## SendChatMessageToPlayer +Sends a chat message to a specific player from this unit. + +### Parameters +* type: [ChatMsg](../enums/ChatMsg.md) - The type of chat message to send. +* lang: [Language](../enums/Language.md) - The language of the message. +* msg: string - The content of the message to send. +* target: [Player](./Player.md) - The player to receive the message. + +### Example Usage +Here's an example of how to use the `SendChatMessageToPlayer` method to send a message to a player when they enter the world: + +```typescript +const WELCOME_MESSAGE = "Welcome to the server, {name}! Remember to read the rules and have fun!"; + +function OnLogin(event: PlayerEvents, player: Player): void { + // Check if the player is logging in for the first time + if (player.GetTotalPlayedTime() == 0) { + // Get the player's name + const playerName = player.GetName(); + + // Format the welcome message with the player's name + const formattedMessage = WELCOME_MESSAGE.replace("{name}", playerName); + + // Send the welcome message to the player + player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_SYSTEM, Language.LANG_UNIVERSAL, formattedMessage, player); + + // Give the player a small bonus for their first login + const bonusAmount = 10; + const bonusMoney = player.ModifyMoney(bonusAmount * 10000); // 1 gold = 10000 copper + + // Inform the player about their bonus + const bonusMessage = `As a welcome gift, you have received ${bonusAmount} gold!`; + player.SendChatMessageToPlayer(ChatMsg.CHAT_MSG_SYSTEM, Language.LANG_UNIVERSAL, bonusMessage, player); + } +} + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, OnLogin); +``` + +In this example: +1. We define a constant `WELCOME_MESSAGE` that contains the message to send to new players, with a placeholder for their name. +2. We register a callback function `OnLogin` to the `PLAYER_EVENT_ON_LOGIN` event. +3. Inside the callback function, we check if the player is logging in for the first time by comparing their total played time to 0. +4. If it's their first login, we retrieve the player's name using `player.GetName()`. +5. We format the welcome message by replacing the placeholder `{name}` with the player's actual name. +6. We send the formatted welcome message to the player using `player.SendChatMessageToPlayer()`, specifying the chat message type as `CHAT_MSG_SYSTEM`, the language as `LANG_UNIVERSAL`, and the target player as the player itself. +7. As a bonus, we grant the player a small amount of money (10 gold) using `player.ModifyMoney()`. +8. We send another message to the player informing them about the bonus they received. + +This script ensures that new players receive a personalized welcome message and a small bonus upon their first login to the server. + +## SendUnitEmote +The `SendUnitEmote` method allows the [Unit](./unit.md) to display an emote message to the specified receiver or to nearby players if no receiver is specified. This can be useful for creating custom boss encounters or adding flavor to NPC interactions. + +### Parameters +* `msg`: string - The emote message to be displayed. +* `receiver`: [Unit](./unit.md) (optional) - The target [Unit](./unit.md) that will receive the emote message. If not specified, the emote will be sent to nearby players. +* `bossEmote`: boolean (optional) - Determines whether the emote is a boss emote or a regular emote. Boss emotes are displayed in the chat frame with a different color and font. Default is `false`. + +### Example Usage +Creating a custom boss encounter with emotes: +```typescript +const BOSS_ENTRY = 12345; +const EMOTE_PHASE_1 = 'The boss lets out a menacing roar!'; +const EMOTE_PHASE_2 = 'The boss becomes enraged and starts to glow with a fiery aura!'; +const EMOTE_PLAYER_KILLED = 'The boss laughs as it claims another victim!'; + +const OnBossEnterCombat: creature_event_on_enter_combat = (event: number, creature: Creature, target: Unit): void => { + creature.SendUnitEmote(EMOTE_PHASE_1, undefined, true); + creature.RegisterEvent(() => { + creature.SendUnitEmote(EMOTE_PHASE_2, undefined, true); + // Add phase 2 abilities and mechanics here + }, 30000, 1); +}; + +const OnBossKillPlayer: creature_event_on_kill_player = (event: number, creature: Creature, victim: Player): void => { + creature.SendUnitEmote(EMOTE_PLAYER_KILLED, victim, true); +}; + +const OnBossDeath: creature_event_on_death = (event: number, creature: Creature, killer: Unit): void => { + creature.SendUnitEmote(`${creature.GetName()} has been defeated!`, undefined, true); + // Add any loot or post-encounter events here +}; + +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_ENTER_COMBAT, (...args) => OnBossEnterCombat(...args)); +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_KILLED_PLAYER, (...args) => OnBossKillPlayer(...args)); +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_DEATH, (...args) => OnBossDeath(...args)); +``` +In this example, we create a custom boss encounter where the boss emotes at different phases of the fight and when it kills a player. The `SendUnitEmote` method is used to display these emotes to nearby players, with the `bossEmote` parameter set to `true` to ensure they are displayed as boss emotes. + +The `OnBossEnterCombat` event sets up the initial emote and registers a delayed event to trigger the phase 2 emote after 30 seconds. The `OnBossKillPlayer` event emotes when the boss kills a player, and the `OnBossDeath` event emotes when the boss is defeated. + +This is just a simple example, but it demonstrates how the `SendUnitEmote` method can be used to enhance a boss encounter and provide additional feedback to players. + +## SendUnitSay +The `SendUnitSay` method allows the [Unit](./unit.md) to speak a message in a specified language. This can be used to create custom dialogue or announcements from various units in the game. + +### Parameters +* msg: string - The message that the unit will say. +* language: [Language](./language.md) - The language in which the message will be spoken. Refer to the [Language](./language.md) documentation for available language options. + +### Example Usage +In this example, we create a script that makes a friendly NPC say a random greeting to players who interact with them, using their race's language. + +```typescript +const FRIENDLY_NPC_ENTRY = 1234; +const GREETINGS = [ + "Hello, traveler! Welcome to our village.", + "Greetings, adventurer. How may I assist you today?", + "Ah, another brave soul. What brings you to these parts?", + "Well met, friend. I hope your journey has been safe thus far." +]; + +const NpcGreet: creature_event_on_gossip_hello = (event: number, creature: Creature, player: Player): void => { + if (creature.GetEntry() === FRIENDLY_NPC_ENTRY) { + const randomGreeting = GREETINGS[Math.floor(Math.random() * GREETINGS.length)]; + const playerRace = player.GetRace(); + let npcLanguage: Language; + + switch (playerRace) { + case Races.RACE_HUMAN: + npcLanguage = Languages.LANG_COMMON; + break; + case Races.RACE_ORC: + npcLanguage = Languages.LANG_ORCISH; + break; + case Races.RACE_DWARF: + npcLanguage = Languages.LANG_DWARVISH; + break; + case Races.RACE_NIGHTELF: + npcLanguage = Languages.LANG_DARNASSIAN; + break; + // Add more cases for other races and their respective languages + default: + npcLanguage = Languages.LANG_UNIVERSAL; + } + + creature.SendUnitSay(randomGreeting, npcLanguage); + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, (...args) => NpcGreet(...args)); +``` + +In this script, we define an array of friendly greetings and a constant for the friendly NPC's entry ID. When a player interacts with the NPC (triggering the `CREATURE_EVENT_ON_GOSSIP_HELLO` event), the script checks if the creature's entry matches the friendly NPC. + +If it does, the script selects a random greeting from the `GREETINGS` array and determines the player's race using the `GetRace()` method. Based on the player's race, it sets the appropriate language for the NPC to speak using a `switch` statement. + +Finally, the script calls the `SendUnitSay` method on the creature object, passing the selected random greeting and the determined language. This makes the NPC say the greeting to the player in their race's language, adding a touch of immersion to the interaction. + +## SendUnitWhisper +The `SendUnitWhisper` method allows a unit to send a whisper message to a specific player. This can be useful for creating custom boss encounters or interactive NPCs that communicate directly with players. + +### Parameters +* `msg`: string - The message to be sent as a whisper. +* `lang`: number - The language of the message. Refer to the [Languages](https://www.azerothcore.org/wiki/Languages) table for valid language IDs. +* `receiver`: [Player](./player.md) - The player who will receive the whisper message. +* `bossWhisper`: boolean (optional) - If set to true, the message will be treated as a boss whisper, which may trigger additional visual effects or sounds for the receiving player. + +### Example Usage +Here's an example of how to use `SendUnitWhisper` to create a custom boss encounter that interacts with players based on their actions: + +```typescript +const BOSS_ENTRY = 12345; +const PLAYER_EMOTE_DANCE = 10; + +const OnEmote: creature_event_on_receive_emote = (event: number, creature: Creature, player: Player, emote: number) => { + if (creature.GetEntry() === BOSS_ENTRY) { + if (emote === PLAYER_EMOTE_DANCE) { + creature.SendUnitWhisper("You dare to dance in my presence? Prepare to face my wrath!", 0, player); + creature.CastSpell(player, 12345, true); // Cast a spell on the player + } else { + creature.SendUnitWhisper("Your actions are meaningless. Prove your worth or perish!", 0, player); + } + } +}; + +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_RECEIVE_EMOTE, (...args) => OnEmote(...args)); +``` + +In this example: +1. We define a constant `BOSS_ENTRY` to represent the entry ID of the custom boss creature. +2. We define a constant `PLAYER_EMOTE_DANCE` to represent the emote ID for the player's dance action. +3. We create a function `OnEmote` that handles the `CREATURE_EVENT_ON_RECEIVE_EMOTE` event. +4. Inside the `OnEmote` function, we check if the creature's entry matches the `BOSS_ENTRY`. +5. If the player performs the dance emote (`PLAYER_EMOTE_DANCE`), the boss sends a threatening whisper message to the player using `SendUnitWhisper` and casts a spell on them using `CastSpell`. +6. If the player performs any other emote, the boss sends a different whisper message, urging the player to prove their worth. +7. Finally, we register the `OnEmote` function to handle the `CREATURE_EVENT_ON_RECEIVE_EMOTE` event for the specific boss creature using `RegisterCreatureEvent`. + +This example demonstrates how `SendUnitWhisper` can be used to create interactive boss encounters that respond to player actions, providing a more immersive and engaging experience. + +## SendUnitYell +The `SendUnitYell` method causes the [Unit](./unit.md) to yell the specified message in the specified language. The message will be displayed in the chat window for nearby players based on the range of the yell. + +### Parameters +* msg: string - The message to be yelled by the unit. +* language: [Language](./language.md) - The language in which the message will be yelled. You can find the list of available languages in the [Language](./language.md) enum. + +### Example Usage +In this example, we create a script that makes a friendly NPC yell a random greeting to players who interact with it, in a random language. + +```typescript +const FRIENDLY_NPC_ENTRY = 1234; +const GREETINGS = [ + "Welcome, traveler!", + "Greetings, adventurer!", + "Salutations, hero!", + "Well met, champion!", +]; + +const RandomGreeting = (player: Player, creature: Creature): void => { + if (creature.GetEntry() === FRIENDLY_NPC_ENTRY) { + const randomGreeting = GREETINGS[Math.floor(Math.random() * GREETINGS.length)]; + const randomLanguage = Math.floor(Math.random() * (MAX_LANGUAGES - 1)) + 1; + + creature.SendUnitYell(randomGreeting, randomLanguage); + + const playerResponse = `${player.GetName()}, I hope you enjoy your stay in our town!`; + creature.SendUnitSay(playerResponse, 0); + + creature.HandleEmoteCommand(EMOTE_ONESHOT_WAVE); + } +}; + +RegisterCreatureEvent(FRIENDLY_NPC_ENTRY, CreatureEvents.CREATURE_EVENT_ON_GOSSIP_HELLO, (event, player, creature) => RandomGreeting(player, creature)); +``` + +In this script: +1. We define the entry of the friendly NPC and an array of random greetings. +2. In the `RandomGreeting` function, we check if the interacted creature has the desired entry. +3. We select a random greeting from the `GREETINGS` array. +4. We generate a random language ID between 1 and `MAX_LANGUAGES - 1` (excluding the universal language). +5. We make the creature yell the random greeting in the random language using `SendUnitYell`. +6. We make the creature say a personalized response to the player using `SendUnitSay`. +7. We make the creature perform a wave emote using `HandleEmoteCommand`. +8. Finally, we register the `RandomGreeting` function to be called when a player interacts with the friendly NPC using `RegisterCreatureEvent` and the `CREATURE_EVENT_ON_GOSSIP_HELLO` event. + +This script adds a touch of immersion and interactivity to the game world by making the friendly NPC greet players in different languages and respond to their interactions. + +## SetConfused +This method sets the confused state of the [Unit]. If the `apply` parameter is set to `true` or not provided, the unit will be confused. If `apply` is set to `false`, the unit will no longer be confused. + +When a unit is confused, its movement and actions become erratic and unpredictable. This can be useful for crowd control or to temporarily disable a powerful enemy. + +### Parameters +- `apply`: boolean (optional) - Determines whether to confuse the unit (`true`) or remove the confusion effect (`false`). If not provided, the default value is `true`. + +### Example Usage +In this example, we have a script that confuses a random nearby enemy unit when a player enters combat. The confusion effect lasts for 5 seconds, after which the unit is no longer confused. + +```typescript +const onEnterCombat: player_event_on_enter_combat = (event: number, player: Player, enemy: Unit): void => { + // Get all enemy units within 10 yards of the player + const nearbyEnemies = player.GetUnitsInRange(10, 0, true); + + if (nearbyEnemies.length > 0) { + // Select a random enemy unit from the nearby units + const randomIndex = Math.floor(Math.random() * nearbyEnemies.length); + const targetEnemy = nearbyEnemies[randomIndex]; + + // Confuse the target enemy unit + targetEnemy.SetConfused(true); + + // Create a delayed action to remove the confusion effect after 5 seconds + player.RegisterTimedEvent(5000, (eventId: number, delay: number, repeats: number, player: Player) => { + // Check if the target enemy unit is still alive and confused + if (targetEnemy.IsAlive() && targetEnemy.IsConfused()) { + // Remove the confusion effect from the target enemy unit + targetEnemy.SetConfused(false); + } + }); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script: +1. When a player enters combat, we retrieve all enemy units within 10 yards of the player using the `GetUnitsInRange` method. +2. If there are nearby enemy units, we select a random unit from the list. +3. We confuse the selected target enemy unit by calling `SetConfused(true)`. +4. We register a timed event using `RegisterTimedEvent` to remove the confusion effect after a delay of 5 seconds (5000 milliseconds). +5. In the timed event callback, we check if the target enemy unit is still alive and confused using `IsAlive()` and `IsConfused()` methods. +6. If the target enemy unit is still confused, we remove the confusion effect by calling `SetConfused(false)`. + +This example demonstrates how to use the `SetConfused` method to apply and remove the confusion effect on a unit, as well as how to create delayed actions using `RegisterTimedEvent` to control the duration of the effect. + +## SetCreatorGUID +Sets the creator GUID for the [Unit]. The creator GUID is used to identify the entity that created or summoned the [Unit]. + +### Parameters +* guid: number - The GUID to set as the creator GUID. + +### Example Usage +Set the creator GUID of a summoned creature to the summoning player's GUID. +```typescript +const SUMMON_ENTRY = 12345; + +const OnSummon: player_event_on_summon_creature = (event: number, player: Player, creature: Creature) => { + if (creature.GetEntry() === SUMMON_ENTRY) { + const creatorGUID = player.GetGUID(); + creature.SetCreatorGUID(creatorGUID); + + // Add a special aura if the creature was summoned by a specific player + const SPECIAL_PLAYER_GUID = 1234567890; + if (creatorGUID === SPECIAL_PLAYER_GUID) { + const SPECIAL_AURA_ENTRY = 54321; + creature.AddAura(SPECIAL_AURA_ENTRY, creature); + } + + // Set the creature's faction to match the summoner's faction + const summonerFaction = player.GetFaction(); + creature.SetFaction(summonerFaction); + + // Make the creature despawn after 5 minutes (300000 milliseconds) + creature.DespawnOrUnsummon(300000); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SUMMON_CREATURE, (...args) => OnSummon(...args)); +``` +In this example: +1. When a player summons a creature with the entry `SUMMON_ENTRY`, the `OnSummon` event is triggered. +2. The summoned creature's creator GUID is set to the summoning player's GUID using `SetCreatorGUID()`. +3. If the summoning player's GUID matches a specific value (`SPECIAL_PLAYER_GUID`), a special aura with the entry `SPECIAL_AURA_ENTRY` is added to the summoned creature using `AddAura()`. +4. The summoned creature's faction is set to match the summoner's faction using `SetFaction()`. +5. The summoned creature is set to despawn after 5 minutes (300000 milliseconds) using `DespawnOrUnsummon()`. + +This script demonstrates how `SetCreatorGUID()` can be used in combination with other methods to customize the behavior of summoned creatures based on their creator. + +## SetCritterGUID +This method sets the GUID of the critter that the [Unit](./unit.md) is currently interacting with. Critters are small, non-combat creatures that can be found throughout the game world, such as squirrels, rabbits, and other small animals. + +### Parameters +This method does not take any parameters. + +### Returns +This method does not return any value. + +### Example Usage +In this example, we'll create a script that allows a player to interact with a critter and receive a small reward. + +```typescript +const CRITTER_ENTRY = 721; // Rabbit +const ITEM_ENTRY = 44228; // Rabbit's Foot + +const InteractWithCritter: player_event_on_gossip_hello = (event: number, player: Player, creature: Creature) => { + if (creature.GetEntry() === CRITTER_ENTRY) { + player.SetCritterGUID(); + + // Check if the player has already interacted with this critter + const critterGUID = player.GetCritterGUID(); + const hasInteracted = player.HasStoredValue(critterGUID); + + if (!hasInteracted) { + // Reward the player with a small item + const item = player.AddItem(ITEM_ENTRY, 1); + if (item) { + player.SendBroadcastMessage(`You received a ${item.GetName()}!`); + } + + // Store the critter's GUID to prevent multiple interactions + player.StoreValue(critterGUID, 1); + } else { + player.SendBroadcastMessage("You have already interacted with this critter."); + } + + player.GossipComplete(); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_GOSSIP_HELLO, (...args) => InteractWithCritter(...args)); +``` + +In this script: + +1. We define the entry ID of the critter (rabbit) and the item (rabbit's foot) that the player will receive as a reward. +2. When the player interacts with a creature (via gossip), we check if the creature is the desired critter. +3. If it is the correct critter, we set the critter's GUID using `SetCritterGUID()`. +4. We then check if the player has already interacted with this specific critter by using the stored value associated with the critter's GUID. +5. If the player hasn't interacted with the critter before, we reward them with the specified item using `AddItem()` and send them a broadcast message informing them of the reward. +6. We store the critter's GUID using `StoreValue()` to prevent the player from receiving multiple rewards from the same critter. +7. If the player has already interacted with the critter, we send them a message indicating that they have already interacted with it. +8. Finally, we close the gossip interaction using `GossipComplete()`. + +This example demonstrates how `SetCritterGUID()` can be used in conjunction with other methods to create a simple interaction system with critters, allowing players to receive rewards for interacting with them while preventing multiple interactions with the same critter. + +## SetDisplayId +Sets the display ID of the unit. The display ID determines the visual appearance of the unit, such as its model, size, and equipment. Changing the display ID can be used to transform the unit into a different creature or character. + +### Parameters +- `displayId`: number - The new display ID to set for the unit. You can find display IDs in the `creature_template` table in the world database. + +### Example Usage +Transform a player into a random creature when they enter a specific area: + +```typescript +const AREA_ID = 1234; // Replace with the desired area ID +const DISPLAY_IDS = [1111, 2222, 3333, 4444, 5555]; // Replace with the desired display IDs + +const transformPlayer: player_event_on_update_zone = (event: number, player: Player, newZone: number, newArea: number) => { + if (newArea === AREA_ID) { + const randomDisplayId = DISPLAY_IDS[Math.floor(Math.random() * DISPLAY_IDS.length)]; + player.SetDisplayId(randomDisplayId); + + // Store the player's original display ID + const originalDisplayId = player.GetNativeDisplayId(); + player.SetData("originalDisplayId", originalDisplayId); + + // Send a message to the player + player.SendBroadcastMessage("You have been transformed!"); + } else { + // Check if the player has a stored original display ID + const originalDisplayId = player.GetData("originalDisplayId"); + if (originalDisplayId !== undefined) { + player.SetDisplayId(Number(originalDisplayId)); + player.DeleteData("originalDisplayId"); + + // Send a message to the player + player.SendBroadcastMessage("You have been transformed back!"); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_UPDATE_ZONE, (...args) => transformPlayer(...args)); +``` + +In this example: +1. We define a specific area ID (`AREA_ID`) and an array of display IDs (`DISPLAY_IDS`) that we want to use for the transformation. +2. When a player enters the specified area, we randomly select a display ID from the `DISPLAY_IDS` array using `Math.random()` and `Math.floor()`. +3. We set the player's display ID to the randomly selected display ID using `player.SetDisplayId(randomDisplayId)`. +4. We store the player's original display ID using `player.SetData("originalDisplayId", originalDisplayId)` so that we can restore it later. +5. We send a message to the player indicating that they have been transformed. +6. When the player leaves the specified area, we check if they have a stored original display ID using `player.GetData("originalDisplayId")`. +7. If an original display ID exists, we restore the player's appearance using `player.SetDisplayId(Number(originalDisplayId))` and remove the stored data using `player.DeleteData("originalDisplayId")`. +8. We send a message to the player indicating that they have been transformed back to their original appearance. + +This example demonstrates how you can use the `SetDisplayId` method to temporarily transform a player's appearance based on their location and restore their original appearance when they leave the area. + +## SetFFA +This method sets the Free-for-All (FFA) flag on the [Unit](./unit.md). When the FFA flag is set, the unit can be attacked by any other unit, regardless of faction or group membership. + +### Parameters +- `apply`: boolean (optional) - If set to `true`, the FFA flag will be set. If set to `false`, the FFA flag will be removed. If not provided, the FFA flag will be toggled (if it was on, it will be turned off, and vice versa). + +### Example Usage +In this example, we create a custom battleground where players can attack each other regardless of their faction: + +```typescript +const BATTLEGROUND_MAP_ID = 123; + +const OnPlayerEnterBattleground: player_event_on_enter_map = (event, player, newMapId, oldMapId): void => { + if (newMapId === BATTLEGROUND_MAP_ID) { + player.SetFFA(true); + player.SendBroadcastMessage("You have entered the FFA Battleground. Attack anyone you want!"); + } +}; + +const OnPlayerLeaveBattleground: player_event_on_leave_map = (event, player, newMapId, oldMapId): void => { + if (oldMapId === BATTLEGROUND_MAP_ID) { + player.SetFFA(false); + player.SendBroadcastMessage("You have left the FFA Battleground. Normal faction rules apply."); + } +}; + +const OnPlayerDeath: player_event_on_kill_player = (event, killer, killed): void => { + if (killer.GetMapId() === BATTLEGROUND_MAP_ID) { + killer.SendBroadcastMessage(`You have slain ${killed.GetName()}!`); + killer.AddItem(REWARD_ITEM_ID, 1); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_ENTER_MAP, OnPlayerEnterBattleground); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LEAVE_MAP, OnPlayerLeaveBattleground); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_KILL_PLAYER, OnPlayerDeath); +``` + +In this script: + +1. When a player enters the custom battleground map, their FFA flag is set to `true` using `player.SetFFA(true)`. They are also sent a message informing them that they can attack anyone. + +2. When a player leaves the custom battleground map, their FFA flag is set back to `false` using `player.SetFFA(false)`. They are sent a message informing them that normal faction rules apply again. + +3. When a player kills another player in the custom battleground map, the killer is sent a message congratulating them and is awarded a custom item using `killer.AddItem(REWARD_ITEM_ID, 1)`. + +This script showcases how the `SetFFA()` method can be used in conjunction with other Eluna methods and events to create a unique gameplay experience. + +## SetFacing +Sets the facing/orientation of the unit in the world. Orientation is expressed as a radian value between 0 and 2π (pi). +This method can be used to script actions that require a unit to face a specific direction before executing. + +### Parameters +* orientation: number - The direction in radians which the unit will face. + +### Example Usage: +Example script that will cause a creature to face a random player in range and cast a spell. +```typescript +const RANGE = 10; +const SPELL_ID = 6713; + +function CastAtRandomPlayer(creature: Creature) { + const nearbyPlayers = creature.GetPlayersInRange(RANGE, false); + if(nearbyPlayers && nearbyPlayers.length > 0){ + //select random player in range + const randomIndex = Math.floor(Math.random() * nearbyPlayers.length); + const target = nearbyPlayers[randomIndex]; + + //Get player position + const targetPosition = target.GetLocation(); + + //calculate facing based on creature -> player position + const dx = targetPosition.x - creature.GetX(); + const dy = targetPosition.y - creature.GetY(); + let orientation = Math.atan2(dy, dx); + + //Creature AI has some inconsistencies with SetFacing + //Clip orientation to 0 to 2π (pi) and rotate + if(orientation < 0) { + orientation += Math.PI * 2; + } + + //set facing + creature.SetFacing(orientation); + + //cast spell at target + creature.CastSpell(target, SPELL_ID, true); + } +} + +const OnCreatureUpdate: creature_event_on_update = (event: number, creature: Creature, diff: number): void => { + CastAtRandomPlayer(creature); +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_UPDATE, (...args) => OnCreatureUpdate(...args)); +``` +In this example, when the creature updates it will search for any players in a given range (10 yards). If there are any players in range +it will select one at random and calculate the direction that player is in relation to the creature. The creature will then face that direction and cast a spell (Shadow Word: Pain in this case) at the player before continuing on. + +## SetFacingToObject +Sets the [Unit] to face the given [WorldObject]'s direction. + +### Parameters +- `target`: [WorldObject](./world-object.md) - The target object to face towards. + +### Example Usage +In this example, we create an event handler for the `CREATURE_EVENT_ON_SPAWN` event. When a creature spawns, we find the nearest player within a radius of 10 yards and set the creature to face the player. + +```typescript +const SEARCH_RADIUS = 10; // 10 yards + +const onCreatureSpawn: creature_event_on_spawn = (event: number, creature: Creature) => { + // Find the nearest player within the search radius + const nearestPlayer = creature.GetNearestPlayer(SEARCH_RADIUS); + + if (nearestPlayer) { + // Set the creature to face the nearest player + creature.SetFacingToObject(nearestPlayer); + + // Print a message indicating the creature is facing the player + const creatureName = creature.GetName(); + const playerName = nearestPlayer.GetName(); + console.log(`${creatureName} is now facing ${playerName}.`); + } else { + // No player found within the search radius + console.log(`No player found within ${SEARCH_RADIUS} yards of the spawned creature.`); + } +}; + +// Register the event handler for the creature spawn event +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => onCreatureSpawn(...args)); +``` + +In this example: +1. We define a constant `SEARCH_RADIUS` to specify the radius within which to search for the nearest player. +2. We create an event handler function `onCreatureSpawn` that takes the event number and the spawned creature as parameters. +3. Inside the event handler, we use the `GetNearestPlayer` method of the creature to find the nearest player within the specified search radius. +4. If a player is found (`nearestPlayer` is truthy), we use the `SetFacingToObject` method of the creature to set its facing direction towards the nearest player. +5. We print a message indicating which creature is now facing which player. +6. If no player is found within the search radius, we print a message indicating that no player was found. +7. Finally, we register the event handler for the `CREATURE_EVENT_ON_SPAWN` event using the `RegisterCreatureEvent` function. + +This example demonstrates how the `SetFacingToObject` method can be used in a practical scenario where a spawned creature automatically faces the nearest player within a certain radius. The example includes error handling and provides informative console messages for better understanding of the script's behavior. + +## SetFaction +Sets the faction for the [Unit]. Faction determines if a unit is hostile, friendly or neutral when interacting with other units. More information about faction IDs can be found in the [AzerothCore faction.dbc file](https://github.com/azerothcore/azerothcore-wotlk/blob/master/data/dbc/faction.dbc). + +### Parameters +- faction: number - The faction ID to set for the unit. + +### Example Usage +This example demonstrates how to change a unit's faction based on its current health percentage. If the unit's health drops below 50%, it will change its faction to a neutral one, making it non-hostile to all players. + +```typescript +const HOSTILE_FACTION_ID = 14; +const NEUTRAL_FACTION_ID = 35; +const HEALTH_THRESHOLD = 50; + +const UnitDamageTaken: unit_event_on_damage_taken = (event: number, unit: Unit, attacker: Unit, damage: number) => { + const healthPct = unit.GetHealthPct(); + + if (healthPct < HEALTH_THRESHOLD && unit.GetFaction() === HOSTILE_FACTION_ID) { + unit.SetFaction(NEUTRAL_FACTION_ID); + unit.SetSheath(SheathState.SHEATH_STATE_UNARMED); + unit.SetFlag(UnitFields.UNIT_FIELD_FLAGS, UnitFlags.UNIT_FLAG_IMMUNE_TO_PC); + unit.SetFlag(UnitFields.UNIT_FIELD_FLAGS, UnitFlags.UNIT_FLAG_IMMUNE_TO_NPC); + unit.ClearThreatList(); + unit.Say("I surrender! Please spare my life!", 0); + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_DAMAGE_TAKEN, (...args) => UnitDamageTaken(...args)); +``` + +In this example: + +1. We define constants for the hostile and neutral faction IDs, as well as a health threshold percentage. +2. We register a `UNIT_EVENT_ON_DAMAGE_TAKEN` event handler for all units. +3. When a unit takes damage, we calculate its current health percentage using `unit.GetHealthPct()`. +4. If the unit's health is below the threshold and its current faction is hostile, we change its faction to neutral using `unit.SetFaction(NEUTRAL_FACTION_ID)`. +5. We also update the unit's visual state by sheathing its weapons (`unit.SetSheath(SheathState.SHEATH_STATE_UNARMED)`), making it immune to both players and NPCs (`unit.SetFlag()`), clearing its threat list (`unit.ClearThreatList()`), and making it say a surrender message (`unit.Say()`). + +This script showcases how changing a unit's faction can influence its behavior and interactions with other units in the game world. + +## SetFeared +This method can be used to apply or remove the fear effect on a unit. + +### Parameters +* apply: boolean (optional) - If set to true, the fear effect will be applied to the unit. If set to false, the fear effect will be removed from the unit. If not specified, the default value is true. + +### Example Usage +Here's an example of how you can use the SetFeared method in a script: + +```typescript +const SPELL_FEAR_ID = 5782; + +const onSpellCast: creature_event_on_spell_cast = (event: number, creature: Creature, caster: Unit, spellInfo: SpellEntry): void => { + if (spellInfo.Id === SPELL_FEAR_ID) { + const targets = creature.GetAITargets(5 /* Radius in yards */); + + for (const target of targets) { + if (target instanceof Player) { + // Apply fear to players within range + target.SetFeared(true); + + // Remove fear after 5 seconds + setTimeout(() => { + target.SetFeared(false); + }, 5000); + } + } + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPELL_CAST, (...args) => onSpellCast(...args)); +``` + +In this example: +1. We define a constant `SPELL_FEAR_ID` to store the ID of the fear spell. +2. We register a creature event handler for the `CREATURE_EVENT_ON_SPELL_CAST` event. +3. Inside the event handler, we check if the spell being cast matches the `SPELL_FEAR_ID`. +4. If it matches, we retrieve all the AI targets within a radius of 5 yards using `creature.GetAITargets()`. +5. We iterate over the targets and check if each target is a player using the `instanceof` operator. +6. If the target is a player, we apply the fear effect to them using `target.SetFeared(true)`. +7. We also set up a timer using `setTimeout()` to remove the fear effect after 5 seconds by calling `target.SetFeared(false)`. + +This script demonstrates how you can use the `SetFeared` method to apply and remove the fear effect on units, specifically targeting players within a certain range when a creature casts a fear spell. + +Note: Make sure to replace `SPELL_FEAR_ID` with the actual ID of the fear spell you want to use in your script. + +## SetHealth +Sets the current health of the Unit to the specified value. + +### Parameters +* health: number - The new health value to set for the Unit. + +### Example Usage +Setting a Unit's health based on a percentage of their maximum health: +```typescript +const HEALTH_PERCENTAGE = 0.75; + +function setUnitHealthPercentage(unit: Unit): void { + const maxHealth = unit.GetMaxHealth(); + const newHealth = Math.floor(maxHealth * HEALTH_PERCENTAGE); + + unit.SetHealth(newHealth); + console.log(`Set ${unit.GetName()}'s health to ${newHealth}/${maxHealth}`); +} + +const onUnitSpawn: creature_event_on_spawn = (event: number, creature: Creature): void => { + const percentageHealth = creature.GetHealthPct(); + + if (percentageHealth < HEALTH_PERCENTAGE * 100) { + console.log(`${creature.GetName()} spawned with ${percentageHealth}% health`); + setUnitHealthPercentage(creature); + } else { + console.log(`${creature.GetName()} spawned with ${percentageHealth}% health, no adjustment needed`); + } +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => onUnitSpawn(...args)); +``` + +In this example, we define a function `setUnitHealthPercentage` that takes a Unit as a parameter. It calculates the new health value based on a percentage (`HEALTH_PERCENTAGE`) of the Unit's maximum health using `unit.GetMaxHealth()`. The calculated `newHealth` value is then set using `unit.SetHealth(newHealth)`. + +We then register a creature event handler for the `CREATURE_EVENT_ON_SPAWN` event. When a creature spawns, we check its current health percentage using `creature.GetHealthPct()`. If the health percentage is below the desired `HEALTH_PERCENTAGE`, we call the `setUnitHealthPercentage` function to adjust the creature's health to the specified percentage. We also log a message indicating the creature's name and the adjusted health value. + +This script ensures that whenever a creature spawns with a health percentage lower than the desired value, its health is automatically adjusted to the specified percentage. This can be useful for balancing encounters or ensuring consistent health levels for certain creatures. + +## SetImmuneTo +This method allows you to set a unit's immunity to a specific type of damage or mechanic. You can use this to make a unit immune to certain types of damage, such as physical damage, magic damage, or even specific mechanics like stuns or fears. + +### Parameters +* immunity: number - The type of damage or mechanic to set immunity for. You can use the values from the [MechanicType](./mechanictype.md) enumeration. +* apply: boolean (optional) - If set to true (default), the immunity will be applied. If set to false, the immunity will be removed. + +### Example Usage +In this example, we will create a script that makes a boss immune to physical damage and stuns when it reaches 50% health, and removes the immunities when the boss dies. + +```typescript +const BOSS_ENTRY = 12345; +const PHYSICAL_DAMAGE_IMMUNITY = 1; +const STUN_MECHANIC_IMMUNITY = 12; + +let bossHealthPercent = 100; +let isImmune = false; + +const UpdateBossHealth: player_event_on_creature_health_changed = (event: number, player: Player, creature: Creature, healthPercent: number) => { + if (creature.GetEntry() === BOSS_ENTRY) { + bossHealthPercent = healthPercent; + + if (healthPercent <= 50 && !isImmune) { + creature.SetImmuneTo(PHYSICAL_DAMAGE_IMMUNITY); + creature.SetImmuneTo(STUN_MECHANIC_IMMUNITY); + isImmune = true; + creature.SendUnitYell("I am now immune to physical damage and stuns!", 0); + } + } +}; + +const RemoveBossImmunities: player_event_on_creature_death = (event: number, player: Player, creature: Creature) => { + if (creature.GetEntry() === BOSS_ENTRY && isImmune) { + creature.SetImmuneTo(PHYSICAL_DAMAGE_IMMUNITY, false); + creature.SetImmuneTo(STUN_MECHANIC_IMMUNITY, false); + isImmune = false; + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CREATURE_HEALTH_CHANGED, (...args) => UpdateBossHealth(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CREATURE_DEATH, (...args) => RemoveBossImmunities(...args)); +``` + +In this script, we first define some constants for the boss entry and the immunity types we want to use. We also create variables to keep track of the boss's health percentage and immunity status. + +In the `UpdateBossHealth` function, we check if the creature is the boss we're interested in, and update the `bossHealthPercent` variable. If the boss's health drops below 50% and it's not already immune, we set its immunities using `SetImmuneTo` and update the `isImmune` variable. We also make the boss yell to let players know it's now immune. + +In the `RemoveBossImmunities` function, we check if the creature that died is the boss and if it was immune. If so, we remove its immunities using `SetImmuneTo` with `false` as the second parameter, and update the `isImmune` variable. + +Finally, we register the event handlers using `RegisterPlayerEvent`. + +## SetLevel +This method allows you to set the level of a unit. The level must be within the valid range for the unit's race and class combination. If an invalid level is provided, the method will fail silently. + +### Parameters +* level: number - The new level to set for the unit. Must be a positive integer between 1 and the maximum level allowed for the unit's race and class. + +### Example Usage +Here's an example of how you might use the SetLevel method in a script that adjusts the level of a player based on their performance in a custom event: + +```typescript +// Constants for the custom event +const EVENT_REQUIRED_SCORE = 1000; +const EVENT_LEVEL_REWARD = 5; + +// Event handler for the custom event completion +const OnEventComplete: player_event_on_custom_event = (event: number, player: Player, score: number) => { + // Check if the player achieved the required score + if (score >= EVENT_REQUIRED_SCORE) { + // Get the player's current level + const currentLevel = player.GetLevel(); + + // Calculate the new level after the reward + const newLevel = currentLevel + EVENT_LEVEL_REWARD; + + // Check if the new level exceeds the maximum allowed level + const maxLevel = player.GetMaxLevel(); + if (newLevel > maxLevel) { + // Set the player's level to the maximum allowed level + player.SetLevel(maxLevel); + player.SendNotification(`Congratulations! You have reached the maximum level of ${maxLevel} for completing the event.`); + } else { + // Set the player's level to the new level + player.SetLevel(newLevel); + player.SendNotification(`Congratulations! You have been rewarded with ${EVENT_LEVEL_REWARD} levels for completing the event. Your new level is ${newLevel}.`); + } + } +}; + +// Register the event handler for the custom event completion +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_CUSTOM_EVENT, OnEventComplete); +``` + +In this example, we define a custom event that rewards players with a certain number of levels (EVENT_LEVEL_REWARD) if they achieve a certain score (EVENT_REQUIRED_SCORE). + +When a player completes the event, the OnEventComplete function is called. It checks if the player's score meets the required threshold, and if so, it calculates the player's new level by adding the EVENT_LEVEL_REWARD to their current level. + +Before setting the player's level, the script checks if the new level exceeds the maximum allowed level for the player's race and class. If it does, the player's level is set to the maximum level instead, and they receive a notification informing them that they have reached the maximum level. + +If the new level is valid, the player's level is set to the new level using the SetLevel method, and they receive a notification informing them of their new level and the reward they received. + +This example demonstrates how the SetLevel method can be used in conjunction with other methods and game events to create custom functionality in your mod. + +## SetMaxHealth +Sets the maximum health of the unit. If the unit's current health is higher than the new maximum health, the unit's health will be set to the new maximum health value. + +### Parameters +* maxHealth: number - The new maximum health value for the unit. + +### Example Usage +This example demonstrates how to set a player's maximum health based on their level and a custom multiplier. + +```typescript +const HEALTH_MULTIPLIER = 10; + +function updatePlayerHealth(player: Player): void { + const playerLevel = player.GetLevel(); + const baseHealth = 100; // Base health at level 1 + const healthPerLevel = 50; // Additional health per level + + // Calculate the player's maximum health based on their level + const maxHealth = baseHealth + (playerLevel - 1) * healthPerLevel; + + // Apply the custom health multiplier + const customMaxHealth = maxHealth * HEALTH_MULTIPLIER; + + // Set the player's maximum health + player.SetMaxHealth(customMaxHealth); + + // Set the player's current health to the new maximum health + player.SetHealth(customMaxHealth); + + // Send a message to the player informing them about their updated health + player.SendBroadcastMessage(`Your maximum health has been updated to ${customMaxHealth}.`); +} + +// Register the player event to call the updatePlayerHealth function on login +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (event, player) => { + updatePlayerHealth(player); +}); +``` + +In this example: +1. We define a constant `HEALTH_MULTIPLIER` to customize the maximum health calculation. +2. The `updatePlayerHealth` function takes a `Player` object as a parameter. +3. We retrieve the player's level using `player.GetLevel()`. +4. We calculate the player's base maximum health using a formula based on their level. +5. We apply the custom health multiplier to the calculated maximum health. +6. We set the player's maximum health using `player.SetMaxHealth(customMaxHealth)`. +7. We also set the player's current health to the new maximum health using `player.SetHealth(customMaxHealth)`. +8. Finally, we send a message to the player informing them about their updated maximum health. +9. We register the `PLAYER_EVENT_ON_LOGIN` event to call the `updatePlayerHealth` function whenever a player logs in. + +This example showcases how you can customize a player's maximum health based on their level and a custom multiplier. You can adjust the `HEALTH_MULTIPLIER` constant to change the scaling of the maximum health. Additionally, you can modify the base health and health per level values to suit your desired balance. + +## SetMaxPower +Sets the maximum power amount for the specified power type for the Unit. + +### Parameters +- type: number - The power type to set the maximum power for. Refer to the Powers enum for valid power types. +- maxPower: number - The maximum power amount to set for the specified power type. + +### Returns +void + +### Example Usage +Set the maximum mana for a unit based on their level and a multiplier. +```typescript +const SetUnitMaxMana = (unit: Unit, multiplier: number): void => { + const manaPerLevel = 50; + const unitLevel = unit.GetLevel(); + const calculatedMaxMana = unitLevel * manaPerLevel * multiplier; + + unit.SetMaxPower(Powers.POWER_MANA, calculatedMaxMana); +}; + +const OnSpawn: creature_event_on_spawn = (event: number, creature: Creature): void => { + const creatureEntry = creature.GetEntry(); + + switch (creatureEntry) { + case 1234: // Mage NPC + SetUnitMaxMana(creature, 1.5); + break; + case 5678: // Priest NPC + SetUnitMaxMana(creature, 1.2); + break; + default: + SetUnitMaxMana(creature, 1.0); + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => OnSpawn(...args)); +``` + +In this example, the `SetUnitMaxMana` function calculates the maximum mana for a unit based on their level and a multiplier. The multiplier is used to adjust the maximum mana for different types of units, such as mages having a higher multiplier than priests. + +The `OnSpawn` event handler is registered to be called when a creature spawns. It retrieves the creature's entry ID and uses a switch statement to determine the appropriate multiplier for the creature's maximum mana based on its entry ID. It then calls the `SetUnitMaxMana` function with the creature and the corresponding multiplier. + +By using this approach, you can set different maximum mana values for various types of creatures based on their entry IDs, allowing for customization and balance in your mod. + +## SetName +Sets the name of the unit. This is the name that will show up when you mouse over the unit. + +### Parameters +* name: string - The name to set for the unit + +### Example Usage +Set a custom name for a creature based on the player that killed it +```typescript +const CUSTOM_TAG_KILLED_BY_PLAYER = "killed_by_player"; + +const KilledByPlayer: creature_event_on_just_died = (event, creature, killer) => { + + if(killer?.IsPlayer()) { + let playerName = killer.GetName(); + let creatureName = creature.GetName(); + let customCreatureName = `${creatureName} `; + + creature.SetInt32Value(CUSTOM_TAG_KILLED_BY_PLAYER, killer.GetGUID()); + creature.SetName(customCreatureName); + } +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_JUST_DIED, (...args) => KilledByPlayer(...args)); + +const RespawnCreature: creature_event_on_spawn = (event, creature) => { + + let killedByPlayer = creature.GetInt32Value(CUSTOM_TAG_KILLED_BY_PLAYER); + if(killedByPlayer > 0) { + let playerGUID = killedByPlayer; + let player = WorldObject.GetPlayer(playerGUID); + + if(player) { + let playerName = player.GetName(); + let creatureName = creature.GetName(); + let customCreatureName = `${creatureName} `; + + creature.SetName(customCreatureName); + } + } +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, (...args) => RespawnCreature(...args)); +``` +This script does the following: +1. When a creature dies, it checks if the killer was a player +2. If the killer was a player, it sets a custom tag on the creature with the player's GUID +3. It then sets the creature's name to include the player's name +4. When the creature respawns, it checks if it has the custom tag set +5. If the tag is set, it gets the player's GUID from the tag +6. It then gets the player object from the GUID +7. If the player is found, it sets the creature's name to include the player's name again + +This allows the creature to persist the custom name even after it respawns. The custom name will include the name of the player that killed it last. + +Note: This script assumes that the creature respawn time is longer than the time it takes for the player to log out and back in. If the player logs out before the creature respawns, the player object will not be found and the custom name will not be set. + +## SetNativeDisplayId +Sets the [Unit]'s native/default model ID. This model ID will be used when the unit is restored to its original state, such as after shapeshifting or when a temporary model ID is removed. + +### Parameters +* displayId: number - The model ID to set as the unit's native/default model. + +### Example Usage +In this example, we'll create a script that changes a player's native model ID based on their class when they log in. If the player is a warrior, their model ID will be set to a specific warrior model. If the player is a mage, their model ID will be set to a specific mage model. For all other classes, a default model ID will be used. + +```typescript +const WARRIOR_MODEL_ID = 123; // Replace with the actual model ID for warriors +const MAGE_MODEL_ID = 456; // Replace with the actual model ID for mages +const DEFAULT_MODEL_ID = 789; // Replace with the default model ID for other classes + +const OnLogin: player_event_on_login = (event: number, player: Player) => { + let modelId = DEFAULT_MODEL_ID; + + switch (player.GetClass()) { + case Classes.CLASS_WARRIOR: + modelId = WARRIOR_MODEL_ID; + break; + case Classes.CLASS_MAGE: + modelId = MAGE_MODEL_ID; + break; + } + + player.SetNativeDisplayId(modelId); + + // Notify the player about their native model change + player.SendBroadcastMessage(`Your native model has been set to ID: ${modelId}`); +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this script: +1. We define constants for the model IDs of warriors, mages, and a default model ID for other classes. +2. When a player logs in, the `OnLogin` event is triggered. +3. We initialize the `modelId` variable with the default model ID. +4. Using a switch statement, we check the player's class using `player.GetClass()`. + - If the player is a warrior (`Classes.CLASS_WARRIOR`), we set `modelId` to the warrior model ID. + - If the player is a mage (`Classes.CLASS_MAGE`), we set `modelId` to the mage model ID. + - For all other classes, `modelId` remains as the default model ID. +5. We call `player.SetNativeDisplayId(modelId)` to set the player's native model ID based on their class. +6. Finally, we send a broadcast message to the player using `player.SendBroadcastMessage()` to notify them about their native model change, including the model ID that was set. + +This script demonstrates how to use `SetNativeDisplayId()` to change a unit's native model ID based on certain conditions, such as the player's class. It provides a more comprehensive example that goes beyond a simple model ID change and includes additional logic and player interaction. + +## SetOwnerGUID +This method sets the owner GUID of the unit to the specified GUID. The owner GUID is used to determine the owner of the unit, such as a player's pet or a creature's summoner. + +### Parameters +* guid: number - The GUID to set as the owner of the unit. + +### Example Usage +Here's an example of how to use the `SetOwnerGUID` method to transfer ownership of a player's pet to another player: + +```typescript +// Event handler for player login +const OnLogin: player_event_on_login = (event: number, player: Player) => { + // Get the player's pet + const pet = player.GetPet(); + + // Check if the player has a pet + if (pet) { + // Get the GUID of another player (e.g., by name) + const otherPlayerGUID = CharDBQuery("SELECT guid FROM characters WHERE name = 'OtherPlayer'")[0].GetUInt32(0); + + // Set the owner GUID of the pet to the other player's GUID + pet.SetOwnerGUID(otherPlayerGUID); + + // Save the pet to the database to persist the ownership change + pet.SaveToDB(); + + // Send a message to the player indicating the ownership transfer + player.SendBroadcastMessage("Your pet's ownership has been transferred to OtherPlayer."); + } +}; + +// Register the event handler for player login +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_LOGIN, (...args) => OnLogin(...args)); +``` + +In this example, when a player logs in, the script checks if the player has a pet. If the player has a pet, it retrieves the GUID of another player (in this case, by querying the characters table in the database using the player's name). + +The script then uses the `SetOwnerGUID` method to set the owner GUID of the pet to the GUID of the other player. This effectively transfers the ownership of the pet from the original player to the other player. + +After setting the owner GUID, the script saves the pet to the database using the `SaveToDB` method to persist the ownership change. + +Finally, the script sends a broadcast message to the original player indicating that their pet's ownership has been transferred to the other player. + +Note: This example assumes the existence of a player with the name "OtherPlayer" in the characters table of the database. Make sure to replace it with a valid player name or use a different method to obtain the GUID of the desired owner. + +## SetPetGUID +Sets the GUID of the pet owned by the Unit. + +### Parameters +- guid: number - The GUID of the pet to set. + +### Example Usage +This example demonstrates how to set the pet GUID of a player's pet when it is summoned. + +```typescript +const SUMMON_PET_SPELL_ID = 883; + +const OnSpellCast: player_event_on_spell_cast = (event: number, player: Player, spell: Spell): void => { + if (spell.GetEntry() === SUMMON_PET_SPELL_ID) { + const pet = player.GetPet(); + if (pet) { + const petGUID = pet.GetGUID(); + player.SetPetGUID(petGUID); + + // Store the pet's GUID in the database for future reference + const query = `INSERT INTO player_pets (player_guid, pet_guid) VALUES (${player.GetGUID()}, ${petGUID}) ON DUPLICATE KEY UPDATE pet_guid = ${petGUID}`; + WorldDBQuery(query); + + player.SendBroadcastMessage(`Your pet's GUID has been set to: ${petGUID}`); + } else { + player.SendBroadcastMessage("You do not have a pet summoned."); + } + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_SPELL_CAST, (...args) => OnSpellCast(...args)); +``` + +In this example: +1. We define a constant `SUMMON_PET_SPELL_ID` with the spell ID of the pet summoning spell. +2. We register a player event handler for the `PLAYER_EVENT_ON_SPELL_CAST` event. +3. Inside the event handler, we check if the cast spell is the pet summoning spell. +4. If the player has a pet summoned, we retrieve the pet using `player.GetPet()`. +5. We get the GUID of the pet using `pet.GetGUID()`. +6. We set the pet's GUID for the player using `player.SetPetGUID(petGUID)`. +7. We store the pet's GUID in the database using a WorldDBQuery to insert or update the record in the `player_pets` table. +8. We send a broadcast message to the player informing them of the pet's GUID. +9. If the player does not have a pet summoned, we send a broadcast message indicating that they don't have a pet. + +This example showcases how to set the pet GUID for a player when their pet is summoned, store the GUID in the database for future reference, and provide feedback to the player about the operation. + +## SetPower +Sets the power amount for the specified power type for the [Unit]. + +### Parameters +* amount: number - The amount of power to set. +* type: number - The type of power to set. This can be one of the following values from the Powers enum: + * POWER_MANA = 0 + * POWER_RAGE = 1 + * POWER_FOCUS = 2 + * POWER_ENERGY = 3 + * POWER_HAPPINESS = 4 + * POWER_RUNE = 5 + * POWER_RUNIC_POWER = 6 + * MAX_POWERS = 7 + * POWER_ALL = 127 + * POWER_HEALTH = 0xFFFFFFFE + +### Example Usage +This script demonstrates how to set the power of a unit based on the type of power they use. It sets the power to a percentage of their maximum power for that power type. + +```typescript +const POWER_PERCENTAGE = 0.5; + +function SetUnitPower(unit: Unit): void { + let powerType: number; + switch (unit.GetClass()) { + case Classes.CLASS_WARRIOR: + powerType = Powers.POWER_RAGE; + break; + case Classes.CLASS_PALADIN: + case Classes.CLASS_MAGE: + case Classes.CLASS_WARLOCK: + case Classes.CLASS_PRIEST: + powerType = Powers.POWER_MANA; + break; + case Classes.CLASS_HUNTER: + powerType = Powers.POWER_FOCUS; + break; + case Classes.CLASS_ROGUE: + powerType = Powers.POWER_ENERGY; + break; + case Classes.CLASS_DEATH_KNIGHT: + powerType = Powers.POWER_RUNIC_POWER; + break; + case Classes.CLASS_DRUID: + powerType = unit.GetShapeshiftForm() == ShapeshiftForm.FORM_CAT ? Powers.POWER_ENERGY : Powers.POWER_MANA; + break; + default: + powerType = Powers.POWER_MANA; + break; + } + + const maxPower = unit.GetMaxPower(powerType); + const newPower = Math.floor(maxPower * POWER_PERCENTAGE); + unit.SetPower(newPower, powerType); +} +``` + +In this example, the `SetUnitPower` function takes a [Unit](./unit.md) as a parameter. It then determines the appropriate power type for the unit based on its class using a switch statement. For some classes, like Druids, it further checks the shapeshift form to determine the correct power type. + +Once the power type is determined, it calculates the maximum power for that power type using `GetMaxPower`, and then calculates a new power value based on a percentage of the maximum power. + +Finally, it calls the `SetPower` method on the unit, passing in the new power value and the power type. + +This script could be used in various situations, such as when a unit spawns, when they change shapeshift forms, or when they should be restored to a certain percentage of their power after an event. + +## SetPowerType +Sets the power type for the unit. The power type determines which type of power the unit uses, such as mana, rage, energy, or runic power. + +### Parameters +* type: [Powers](../Constants/Powers.md) - The power type to set for the unit. This can be one of the following values: + * POWER_MANA (0) + * POWER_RAGE (1) + * POWER_FOCUS (2) + * POWER_ENERGY (3) + * POWER_HAPPINESS (4) + * POWER_RUNE (5) + * POWER_RUNIC_POWER (6) + * MAX_POWERS (7) + * POWER_ALL (127) + * POWER_HEALTH (-2) + +### Example Usage +In this example, we create a script that changes the power type of a unit based on its class when it enters combat. + +```typescript +const onEnterCombat: unit_event_on_enter_combat = (event: number, unit: Unit, target: Unit) => { + const unitClass = unit.GetClass(); + + switch (unitClass) { + case Classes.CLASS_WARRIOR: + unit.SetPowerType(Powers.POWER_RAGE); + break; + case Classes.CLASS_ROGUE: + case Classes.CLASS_DRUID: + unit.SetPowerType(Powers.POWER_ENERGY); + break; + case Classes.CLASS_HUNTER: + unit.SetPowerType(Powers.POWER_FOCUS); + break; + case Classes.CLASS_DEATH_KNIGHT: + unit.SetPowerType(Powers.POWER_RUNIC_POWER); + break; + default: + unit.SetPowerType(Powers.POWER_MANA); + break; + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_ENTER_COMBAT, (...args) => onEnterCombat(...args)); +``` + +In this script, we register a callback function for the `UNIT_EVENT_ON_ENTER_COMBAT` event. When a unit enters combat, the script retrieves the unit's class using the `GetClass` method. Based on the unit's class, it sets the appropriate power type using the `SetPowerType` method. + +* For warriors, it sets the power type to `POWER_RAGE`. +* For rogues and druids, it sets the power type to `POWER_ENERGY`. +* For hunters, it sets the power type to `POWER_FOCUS`. +* For death knights, it sets the power type to `POWER_RUNIC_POWER`. +* For all other classes, it defaults to `POWER_MANA`. + +This script allows units to use the appropriate power type based on their class when they enter combat. It showcases how the `SetPowerType` method can be used to dynamically change the power type of units during gameplay. + +## SetPvP +This method allows you to set a unit's PvP state on or off. If the unit is a player, it will enable or disable their PvP flag, which determines whether they can engage in PvP combat with other players. If the unit is a creature, it will enable or disable its ability to attack players and be attacked by players. + +### Parameters +- `apply`: boolean (optional) - Determines whether to enable or disable PvP for the unit. If set to `true`, PvP will be enabled. If set to `false`, PvP will be disabled. If not provided, the default value is `true`. + +### Example Usage +Here's an example of how to use the `SetPvP` method to create a script that allows players to toggle their PvP state by interacting with a special NPC: + +```typescript +const NPC_ENTRY = 1234; // Replace with the actual NPC entry ID + +const OnGossipHello: npc_event_on_gossip_hello = (event, player, creature) => { + player.GossipMenuAddItem(0, "Toggle PvP", 0, 1); + player.GossipSendMenu(creature.GetEntry(), creature.GetGUID()); +}; + +const OnGossipSelect: npc_event_on_gossip_select = (event, player, creature, sender, action) => { + if (action === 1) { + if (player.IsPvP()) { + player.SetPvP(false); + player.SendBroadcastMessage("PvP mode disabled."); + } else { + player.SetPvP(true); + player.SendBroadcastMessage("PvP mode enabled. Prepare for battle!"); + } + player.GossipComplete(); + } +}; + +RegisterCreatureGossipEvent(NPC_ENTRY, (...args) => OnGossipHello(...args)); +RegisterCreatureGossipEvent(NPC_ENTRY, (...args) => OnGossipSelect(...args)); +``` + +In this example: +1. We define the entry ID of the special NPC that players will interact with to toggle their PvP state. +2. In the `OnGossipHello` event, we add a gossip menu item that allows players to toggle their PvP state. +3. In the `OnGossipSelect` event, we check if the player selected the "Toggle PvP" option (action 1). +4. If the player clicks the gossip option, we check their current PvP state using `player.IsPvP()`. + - If PvP is currently enabled, we disable it using `player.SetPvP(false)` and send a message to the player. + - If PvP is currently disabled, we enable it using `player.SetPvP(true)` and send a message to the player. +5. Finally, we close the gossip menu using `player.GossipComplete()`. + +With this script, players can interact with the designated NPC to toggle their PvP state on or off, allowing them to engage in PvP combat when desired or avoid it when needed. + +## SetRooted +This method allows you to root or unroot a unit. When a unit is rooted, it cannot move from its current position. This can be useful for various scenarios such as when a spell or ability requires the target to stay in place. + +### Parameters +- `apply`: boolean (optional) - If set to `true`, the unit will be rooted. If set to `false`, the unit will be unrooted. If not provided, the default value is `true`. + +### Example Usage +Here's an example of how to use `SetRooted` in a script that roots a player in place when they enter a specific area and unroots them when they leave: + +```typescript +const AREA_ID = 123; // Replace with the desired area ID + +const onAreaTrigger: player_event_on_area_trigger = (event: number, player: Player, areaTrigger: AreaTrigger) => { + if (areaTrigger.GetAreaId() === AREA_ID) { + player.SetRooted(true); + player.SendBroadcastMessage("You have been rooted in place!"); + + // Create a timed event to unroot the player after 5 seconds + player.RegisterEvent(CreateLuaEvent((events: LuaEvent) => { + player.SetRooted(false); + player.SendBroadcastMessage("You are no longer rooted."); + }, 5000, false)); + } +}; + +const onAreaTriggerLeave: player_event_on_area_trigger_leave = (event: number, player: Player, areaTrigger: AreaTrigger) => { + if (areaTrigger.GetAreaId() === AREA_ID) { + player.SetRooted(false); + player.SendBroadcastMessage("You have left the rooted area."); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER, (...args) => onAreaTrigger(...args)); +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_AREA_TRIGGER_LEAVE, (...args) => onAreaTriggerLeave(...args)); +``` + +In this example: +1. We define a specific area ID (`AREA_ID`) that triggers the rooting effect. +2. In the `onAreaTrigger` event, when a player enters the specified area, we call `player.SetRooted(true)` to root the player in place. +3. We send a broadcast message to the player indicating that they have been rooted. +4. We create a timed event using `player.RegisterEvent` and `CreateLuaEvent` to unroot the player after 5 seconds (5000 milliseconds). +5. In the `onAreaTriggerLeave` event, when a player leaves the specified area, we call `player.SetRooted(false)` to unroot the player. +6. We send a broadcast message to the player indicating that they have left the rooted area. + +This script demonstrates how you can use `SetRooted` to control a player's movement based on their presence in a specific area. You can adapt this example to suit your specific requirements, such as applying rooting effects during certain abilities or encounters. + +## SetSanctuary +This method sets the [Unit]'s sanctuary flag on or off. When a unit has the sanctuary flag set, it is immune to damage and cannot be attacked by players or NPCs. + +### Parameters +- `apply`: boolean (optional) - If set to `true`, the sanctuary flag will be applied. If set to `false`, the sanctuary flag will be removed. If not provided, the flag will be toggled (applied if not currently applied, removed if currently applied). + +### Example Usage +This script demonstrates how to create a special NPC that grants players temporary sanctuary when interacted with. + +```typescript +const SANCTUARY_NPC_ENTRY = 1234; +const SANCTUARY_DURATION = 30000; // 30 seconds + +const OnGossipHello: GossipHello = (event, player, object) => { + if (object.GetEntry() === SANCTUARY_NPC_ENTRY) { + player.SetSanctuary(true); + player.SendBroadcastMessage("You have been granted temporary sanctuary!"); + + player.RegisterEvent(CreateLuaEvent((time, event, delay, repeats, player) => { + player.SetSanctuary(false); + player.SendBroadcastMessage("Your temporary sanctuary has ended."); + }, SANCTUARY_DURATION, 1, player)); + + player.GossipComplete(); + } +}; + +const OnGossipSelect: GossipSelect = (event, player, object, sender, intid, code, menu_id) => { + if (object.GetEntry() === SANCTUARY_NPC_ENTRY) { + player.GossipComplete(); + } +}; + +RegisterCreatureGossipEvent(SANCTUARY_NPC_ENTRY, GossipEvents.GOSSIP_EVENT_ON_HELLO, OnGossipHello); +RegisterCreatureGossipEvent(SANCTUARY_NPC_ENTRY, GossipEvents.GOSSIP_EVENT_ON_SELECT, OnGossipSelect); +``` + +In this example: +1. We define a special NPC with entry `SANCTUARY_NPC_ENTRY` and a sanctuary duration of 30 seconds (`SANCTUARY_DURATION`). +2. When a player interacts with the NPC (`OnGossipHello`), we set the player's sanctuary flag using `SetSanctuary(true)`. +3. We send a broadcast message to the player indicating that they have been granted temporary sanctuary. +4. We register a timed event using `RegisterEvent` and `CreateLuaEvent` that will remove the sanctuary flag after the specified duration. +5. After the duration expires, the event callback function is called, which sets the player's sanctuary flag to `false` using `SetSanctuary(false)` and sends a message to the player indicating that their temporary sanctuary has ended. +6. We also register a `OnGossipSelect` event to handle the case when the player selects an option from the NPC's gossip menu (in this case, we simply close the gossip window using `GossipComplete()`). + +This script showcases how the `SetSanctuary` method can be used to grant temporary immunity to a player when interacting with a specific NPC. It also demonstrates how to use timed events to remove the sanctuary flag after a certain duration. + +## SetSheath +Sets the sheath state of the unit. The sheath state determines the unit's prepared weapon and animation. + +### Parameters +- `sheathState`: [SheathState](../enums/SheathState.md) - The desired sheath state for the unit. + +### Example Usage +In this example, we'll create an event handler for the `CREATURE_EVENT_ON_SPAWN` event that sets the sheath state of the creature based on its entry ID. + +```typescript +const ENTRY_WARRIOR_NPC = 1234; +const ENTRY_ARCHER_NPC = 5678; + +const onCreatureSpawn: creature_event_on_spawn = (event: number, creature: Creature) => { + const creatureEntry = creature.GetEntry(); + + switch (creatureEntry) { + case ENTRY_WARRIOR_NPC: + creature.SetSheath(SheathState.SHEATH_STATE_MELEE); + break; + case ENTRY_ARCHER_NPC: + creature.SetSheath(SheathState.SHEATH_STATE_RANGED); + break; + default: + creature.SetSheath(SheathState.SHEATH_STATE_UNARMED); + break; + } + + // Additional creature setup logic... + creature.SetEquipmentSlots(true); + creature.SetCanFly(false); + creature.SetDisableGravity(false); + + // Customize creature's stats based on its sheath state + if (creature.GetSheath() === SheathState.SHEATH_STATE_MELEE) { + creature.SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 50); + creature.SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 100); + } else if (creature.GetSheath() === SheathState.SHEATH_STATE_RANGED) { + creature.SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, 30); + creature.SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, 60); + } +}; + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_SPAWN, onCreatureSpawn); +``` + +In this example: +1. We define constants `ENTRY_WARRIOR_NPC` and `ENTRY_ARCHER_NPC` to represent the entry IDs of warrior and archer NPCs, respectively. +2. We create an event handler function `onCreatureSpawn` for the `CREATURE_EVENT_ON_SPAWN` event. +3. Inside the event handler, we retrieve the creature's entry ID using `creature.GetEntry()`. +4. Based on the entry ID, we set the appropriate sheath state using `creature.SetSheath()`. + - If the entry ID matches `ENTRY_WARRIOR_NPC`, we set the sheath state to `SHEATH_STATE_MELEE`. + - If the entry ID matches `ENTRY_ARCHER_NPC`, we set the sheath state to `SHEATH_STATE_RANGED`. + - For any other entry ID, we set the sheath state to `SHEATH_STATE_UNARMED`. +5. We perform additional creature setup, such as setting equipment slots, disabling flying and gravity. +6. Depending on the sheath state, we customize the creature's base weapon damage using `creature.SetBaseWeaponDamage()`. + - If the sheath state is `SHEATH_STATE_MELEE`, we set the base weapon damage for melee attacks. + - If the sheath state is `SHEATH_STATE_RANGED`, we set the base weapon damage for ranged attacks. +7. Finally, we register the event handler for the `CREATURE_EVENT_ON_SPAWN` event using `RegisterCreatureEvent()`. + +This example demonstrates how to set the sheath state of a creature based on its entry ID and customize its properties accordingly. + +## SetSpeed +Sets the [Unit]'s speed of a given [UnitMoveType] to the specified rate. If forced is set to true, packets will be sent to clients forcing the visual change. + +### Parameters +* type: [UnitMoveType](./unitmovetype.md) - The type of movement to set the speed for. +* rate: number - The new speed rate. +* forced: boolean (optional) - If set to true, packets will be sent to clients forcing the visual change. Default: false. + +### Example Usage +Script that changes a [Unit]'s speed based on its health percentage: +```typescript +const UpdateUnitSpeed: unit_event_on_health_pct_change = (event: number, unit: Unit, percentHealth: number) => { + if (unit.IsCreature()) { + const creature = unit.ToCreature(); + if (creature.GetEntry() === 1234) { // Replace 1234 with the desired creature entry + let newSpeed = 1.0; // Default speed + + if (percentHealth <= 20) { + newSpeed = 2.5; // Increase speed when health is low + } else if (percentHealth <= 50) { + newSpeed = 1.8; // Moderately increase speed when health is medium + } + + creature.SetSpeed(UnitMoveType.MOVE_RUN, newSpeed); + creature.SetSpeed(UnitMoveType.MOVE_WALK, newSpeed); + creature.SetSpeed(UnitMoveType.MOVE_FLIGHT, newSpeed); + } + } +}; + +RegisterUnitEvent(UnitEvents.UNIT_EVENT_ON_HEALTH_PCT_CHANGE, (...args) => UpdateUnitSpeed(...args)); +``` +In this example, the script listens for the `UNIT_EVENT_ON_HEALTH_PCT_CHANGE` event. When the event is triggered, it checks if the unit is a creature with a specific entry (replace `1234` with the desired entry). If the condition is met, the script adjusts the creature's speed based on its current health percentage. + +* If the creature's health is at or below 20%, the speed is set to 2.5 for running, walking, and flying. +* If the creature's health is between 21% and 50%, the speed is set to 1.8. +* If the creature's health is above 50%, the default speed of 1.0 is used. + +The script uses the `SetSpeed` method to change the speed of the creature for different movement types (running, walking, and flying). + +This example demonstrates how the `SetSpeed` method can be used to dynamically adjust a unit's movement speed based on certain conditions, such as its health percentage. It provides a more complex usage scenario compared to a simple one-line example. + +## SetStandState +Sets the [Unit]'s stand state, which determines the visual appearance and behavior of the unit in the game world. + +### Parameters +* state: number - The stand state to set for the unit. Valid values are: + * 0 - UNIT_STAND_STATE_STAND + * 1 - UNIT_STAND_STATE_SIT + * 2 - UNIT_STAND_STATE_SIT_CHAIR + * 3 - UNIT_STAND_STATE_SLEEP + * 4 - UNIT_STAND_STATE_SIT_LOW_CHAIR + * 5 - UNIT_STAND_STATE_SIT_MEDIUM_CHAIR + * 6 - UNIT_STAND_STATE_SIT_HIGH_CHAIR + * 7 - UNIT_STAND_STATE_DEAD + * 8 - UNIT_STAND_STATE_KNEEL + +### Example Usage: +Script to make a creature sit or stand based on its health percentage. +```typescript +const CREATURE_ENTRY = 1234; +const SIT_HEALTH_PERCENT = 50; + +const UpdateAI: creature_event_on_aiupdate = (event: number, creature: Creature, diff: number) => { + if (creature.GetEntry() === CREATURE_ENTRY) { + const healthPercent = creature.GetHealthPct(); + + if (healthPercent <= SIT_HEALTH_PERCENT) { + // If the creature's health is below or equal to the sit threshold, make it sit + creature.SetStandState(1); + } else { + // If the creature's health is above the sit threshold, make it stand + creature.SetStandState(0); + } + } +} + +RegisterCreatureEvent(CreatureEvents.CREATURE_EVENT_ON_AIUPDATE, (...args) => UpdateAI(...args)); +``` + +In this example, the script checks the health percentage of a specific creature (identified by its entry ID) during the creature's AI update event. If the creature's health is below or equal to the `SIT_HEALTH_PERCENT` threshold, it sets the creature's stand state to 1 (UNIT_STAND_STATE_SIT), making it appear sitting. If the creature's health is above the threshold, it sets the stand state to 0 (UNIT_STAND_STATE_STAND), making the creature stand up. + +This script demonstrates how the `SetStandState` method can be used to dynamically change a unit's visual appearance and behavior based on certain conditions, such as health percentage. It adds an interesting visual detail to the creature's behavior and can be used to create more immersive and interactive encounters in the game world. + +## SetWaterWalk +This method allows you to toggle the water walking ability for a [Unit](./unit.md). When water walking is enabled, the unit can move across water surfaces without sinking or swimming. + +### Parameters +* enable: boolean (optional) - Determines whether to enable or disable water walking for the unit. If not provided, the current state will be toggled. + +### Example Usage +In this example, we create a script that allows players to toggle their water walking ability by using a specific item. + +```typescript +const WATER_WALKING_ITEM_ENTRY = 12345; // Replace with the actual item entry ID + +const UseWaterWalkingItem: player_event_on_use_item = (event: number, player: Player, item: Item, target: GameObject, x: number, y: number, z: number) => { + if (item.GetEntry() === WATER_WALKING_ITEM_ENTRY) { + // Check if the player is already water walking + if (player.HasAura(546)) { // 546 is the spell ID for water walking + player.SetWaterWalk(false); + player.SendBroadcastMessage("Water walking disabled."); + } else { + player.SetWaterWalk(true); + player.SendBroadcastMessage("Water walking enabled."); + } + + // Prevent the item from being consumed + player.AddItem(WATER_WALKING_ITEM_ENTRY, 1); + } +}; + +RegisterPlayerEvent(PlayerEvents.PLAYER_EVENT_ON_USE_ITEM, (...args) => UseWaterWalkingItem(...args)); +``` + +In this script: +1. We define a constant `WATER_WALKING_ITEM_ENTRY` to store the entry ID of the item that will toggle water walking. +2. We create a function `UseWaterWalkingItem` that will be triggered when a player uses an item. +3. Inside the function, we check if the used item's entry ID matches the `WATER_WALKING_ITEM_ENTRY`. +4. If the item matches, we check if the player already has the water walking aura (spell ID 546) using `player.HasAura(546)`. +5. If the player has the water walking aura, we disable water walking using `player.SetWaterWalk(false)` and send a message to the player indicating that water walking has been disabled. +6. If the player does not have the water walking aura, we enable water walking using `player.SetWaterWalk(true)` and send a message to the player indicating that water walking has been enabled. +7. To prevent the item from being consumed, we add the item back to the player's inventory using `player.AddItem(WATER_WALKING_ITEM_ENTRY, 1)`. +8. Finally, we register the `UseWaterWalkingItem` function to the `PLAYER_EVENT_ON_USE_ITEM` event using `RegisterPlayerEvent`. + +With this script, players can use a specific item to toggle their water walking ability on and off. The item will not be consumed when used, allowing players to reuse it whenever they need to toggle water walking. + +## StopSpellCast +Stops the unit's current spell cast. If a spell ID is provided, it will only stop that specific spell. + +### Parameters +* spell: number (optional) - The ID of the specific spell to stop casting. If not provided, the unit's current spell cast will be stopped. + +### Returns +None + +### Example Usage +Interrupt a raid boss's dangerous spell cast when it reaches 50% health: +```typescript +const BOSS_ENTRY = 12345; +const DANGEROUS_SPELL_ID = 54321; + +const BossAI: creature_event_on_aiupdate = (event: number, boss: Creature) => { + if (boss.GetEntry() === BOSS_ENTRY && boss.GetHealthPct() <= 50) { + if (boss.IsCasting()) { + const currentSpell = boss.GetCurrentSpell(); + if (currentSpell && currentSpell.GetEntry() === DANGEROUS_SPELL_ID) { + boss.StopSpellCast(DANGEROUS_SPELL_ID); + boss.Yell("My spell has been interrupted! You shall pay for this!", 0); + boss.CastSpell(boss.GetVictim(), 12345, false); // Cast a punishing spell on the tank + boss.AddThreat(boss.GetVictim(), 5000); // Increase threat on the tank + boss.SetInCombatWithZone(); // Ensure the boss remains in combat + } + } + } +}; + +RegisterCreatureEvent(BOSS_ENTRY, CreatureEvents.CREATURE_EVENT_ON_AIUPDATE, (...args) => BossAI(...args)); +``` +In this example, we register a creature event for a raid boss using its entry ID. Inside the event handler, we check if the boss's health is at or below 50%. If the boss is casting a spell, we check if it's the dangerous spell we want to interrupt using its spell ID. + +If the dangerous spell is being cast, we use `StopSpellCast` to interrupt it, passing the specific spell ID. After interrupting the spell, the boss yells a message, casts a punishing spell on the tank, increases the threat on the tank, and ensures it remains in combat with the entire zone. + +This example demonstrates how `StopSpellCast` can be used strategically in a boss encounter to interrupt a critical spell cast and alter the boss's behavior in response to the interruption. +