public static void UseOpenRestMenuFeat() { var player = OBJECT_SELF; var feat = (Feat)Convert.ToInt32(Events.GetEventData("FEAT_ID")); if (feat != Feat.ChatCommandTargeter) { return; } var target = Object.StringToObject(Events.GetEventData("TARGET_OBJECT_ID")); var area = Object.StringToObject(Events.GetEventData("AREA_OBJECT_ID")); var targetX = (float)Convert.ToDouble(Events.GetEventData("TARGET_POSITION_X")); var targetY = (float)Convert.ToDouble(Events.GetEventData("TARGET_POSITION_Y")); var targetZ = (float)Convert.ToDouble(Events.GetEventData("TARGET_POSITION_Z")); var targetLocation = Location(area, new Vector(targetX, targetY, targetZ), 0.0f); var command = GetLocalString(player, "CHAT_COMMAND"); var args = GetLocalString(player, "CHAT_COMMAND_ARGS"); if (string.IsNullOrWhiteSpace(command)) { SendMessageToPC(player, "Please enter a chat command and then use this feat. Type /help to learn more about the available chat commands."); return; } ProcessChatCommand(command, player, target, targetLocation, args); DeleteLocalString(player, "CHAT_COMMAND"); DeleteLocalString(player, "CHAT_COMMAND_ARGS"); }
/// <summary> /// When an item is equipped, if any of a player's perks has an Equipped Trigger, run those actions now. /// </summary> private static void ApplyEquipTriggers() { var player = OBJECT_SELF; if (!GetIsPC(player) || GetIsDM(player)) { return; } var playerId = GetObjectUUID(player); var dbPlayer = DB.Get <Player>(playerId); var item = Object.StringToObject(Events.GetEventData("ITEM")); var slot = (InventorySlot)Convert.ToInt32(Events.GetEventData("SLOT")); foreach (var(perkType, actionList) in Perk.GetAllEquipTriggers()) { var playerPerkLevel = Perk.GetEffectivePerkLevel(player, perkType); if (playerPerkLevel <= 0) { continue; } foreach (var action in actionList) { action(player, item, slot, perkType, playerPerkLevel); } } }
private static uint CreateMerchantObject(string sellerPlayerId, PlayerStore dbPlayerStore) { const string StoreResref = "player_store"; var merchant = CreateObject(ObjectType.Store, StoreResref, GetLocation(OBJECT_SELF)); SetLocalString(merchant, "SELLER_PLAYER_ID", sellerPlayerId); foreach (var item in dbPlayerStore.ItemsForSale) { if (item.Value.Price <= 0) { continue; } var deserialized = Object.Deserialize(item.Value.Data); Object.AcquireItem(merchant, deserialized); var originalBaseGPValue = Core.NWNX.Item.GetBaseGoldPieceValue(deserialized); var originalAdditionalGPValue = Core.NWNX.Item.GetAddGoldPieceValue(deserialized); SetLocalInt(deserialized, "ORIGINAL_BASE_GP_VALUE", originalBaseGPValue); SetLocalInt(deserialized, "ORIGINAL_ADDITIONAL_GP_VALUE", originalAdditionalGPValue); Core.NWNX.Item.SetBaseGoldPieceValue(deserialized, item.Value.Price); Core.NWNX.Item.SetAddGoldPieceValue(deserialized, 0); } return(merchant); }
public static void JoinParty() { var player = OBJECT_SELF; var requester = Object.StringToObject(Events.GetEventData("INVITED_BY")); // This is a brand new party. // Add both the requester and the player to the cache. // Mark the requester as the party leader. if (!_playerToParty.ContainsKey(requester)) { var partyId = Guid.NewGuid(); _parties[partyId] = new List <uint> { requester, player }; _partyLeaders[partyId] = requester; _playerToParty[player] = partyId; _playerToParty[requester] = partyId; } // This is an existing party. // Add the player to the party cache. else { var partyId = _playerToParty[requester]; _parties[partyId].Add(player); _playerToParty[player] = partyId; } }
public static void TransferLeadership() { var player = Object.StringToObject(Events.GetEventData("NEW_LEADER")); var partyId = _playerToParty[player]; _partyLeaders[partyId] = player; }
public static void UseFeat() { var activator = OBJECT_SELF; var target = Object.StringToObject(Events.GetEventData("TARGET_OBJECT_ID")); var feat = (Feat)Convert.ToInt32(Events.GetEventData("FEAT_ID")); if (!Ability.IsFeatRegistered(feat)) { return; } var ability = Ability.GetAbilityDetail(feat); // Creature cannot use the feat. var effectivePerkLevel = Perk.GetEffectivePerkLevel(activator, ability.EffectiveLevelPerkType); if (!CanUseAbility(activator, target, ability, effectivePerkLevel)) { return; } Messaging.SendMessageNearbyToPlayers(activator, $"{GetName(activator)} readies {ability.Name}."); // Weapon abilties are queued for the next time the activator's attack lands on an enemy. if (ability.ActivationType == AbilityActivationType.Weapon) { QueueWeaponAbility(activator, ability, feat, effectivePerkLevel); } // All other abilities are funneled through the same process. else { ActivateAbility(activator, target, ability, effectivePerkLevel); } }
public static void SetBarteringFlag() { var player1 = OBJECT_SELF; var player2 = Object.StringToObject(Events.GetEventData("BARTER_TARGET")); SetLocalBool(player1, "IS_BARTERING", true); SetLocalBool(player2, "IS_BARTERING", true); }
public static void RemoveBarteringFlag() { var player1 = OBJECT_SELF; var player2 = Object.StringToObject(Events.GetEventData("BARTER_TARGET")); DeleteLocalBool(player1, "IS_BARTERING"); DeleteLocalBool(player2, "IS_BARTERING"); }
public static void ValidateItemUse() { var creature = OBJECT_SELF; var item = Object.StringToObject(Events.GetEventData("ITEM_OBJECT_ID")); Events.SetEventResult(string.IsNullOrWhiteSpace(CanItemBeUsed(creature, item)) ? "1" : "0"); Events.SkipEvent(); }
public static void ValidateDualWield() { var creature = OBJECT_SELF; var item = Object.StringToObject(Events.GetEventData("ITEM")); var slot = (InventorySlot)Convert.ToInt32(Events.GetEventData("SLOT")); // Not equipping to the left hand, or there's nothing equipped in the right hand. if (slot != InventorySlot.LeftHand) { return; } if (!GetIsObjectValid(GetItemInSlot(InventorySlot.RightHand, creature))) { return; } var baseItem = GetBaseItemType(item); var dualWieldWeapons = new[] { BaseItem.ShortSword, BaseItem.Longsword, BaseItem.BattleAxe, BaseItem.BastardSword, BaseItem.LightFlail, BaseItem.LightMace, BaseItem.Dagger, BaseItem.Club, BaseItem.HandAxe, BaseItem.Kama, BaseItem.Katana, BaseItem.Kukri, BaseItem.Rapier, BaseItem.Scimitar, BaseItem.Sickle }; if (!dualWieldWeapons.Contains(baseItem)) { return; } var dualWieldLevel = Perk.GetEffectivePerkLevel(creature, PerkType.DualWield); if (dualWieldLevel <= 0) { SendMessageToPC(creature, ColorToken.Red("Equipping two weapons requires the Dual Wield perk.")); Events.SkipEvent(); } }
public static void ValidateItemEquip() { var creature = OBJECT_SELF; var item = Object.StringToObject(Events.GetEventData("ITEM")); var error = CanItemBeUsed(creature, item); if (string.IsNullOrWhiteSpace(error)) { ApplyEquipTriggers(); return; } SendMessageToPC(creature, ColorToken.Red(error)); Events.SkipEvent(); }
public static void OnUseItem() { var creature = OBJECT_SELF; var item = Object.StringToObject(Events.GetEventData("ITEM_OBJECT_ID")); var script = GetLocalString(item, "SCRIPT"); // No script associated. Let it run the normal execution process. if (string.IsNullOrWhiteSpace(script)) { return; } Events.SkipEvent(); Events.SetEventResult("0"); // Prevents the "You cannot use that item" error message from being sent. ExecuteScript(script, creature); }
public static void AddItemToBankStorage() { var container = OBJECT_SELF; if (GetResRef(container) != "bank_chest" || GetLocalBool(container, "IS_DESERIALIZING")) { return; } var item = Object.StringToObject(Events.GetEventData("ITEM")); var player = GetItemPossessor(item); var playerId = GetObjectUUID(player); var storageId = GetStorageID(); var key = $"{storageId}:{playerId}"; AddItem(key, "Bank"); }
private void MovePageInit(DialogPage page) { var player = GetPC(); var model = GetDataModel <Model>(); void Move(float x, float y, float z) { var position = GetPosition(model.Placeable); position.X += x; position.Y += y; position.Z += z; if (position.Z > 10f) { position.Z = 10f; } else if (position.Z < -10f) { position.Z = -10f; } Object.SetPosition(model.Placeable, position); var furnitureId = GetLocalString(model.Placeable, "HOUSING_FURNITURE_ID"); var dbHouse = DB.Get <PlayerHouse>(model.OwnerUUID); dbHouse.Furnitures[furnitureId].X = position.X; dbHouse.Furnitures[furnitureId].Y = position.Y; dbHouse.Furnitures[furnitureId].Z = position.Z; DB.Set(model.OwnerUUID, dbHouse); } page.Header = ColorToken.Green("Move Furniture") + "\n\n"; page.AddResponse("Move North", () => Move(0f, 0.2f, 0f)); page.AddResponse("Move South", () => Move(0f, -0.2f, 0f)); page.AddResponse("Move East", () => Move(0.2f, 0f, 0f)); page.AddResponse("Move West", () => Move(-0.2f, 0f, 0f)); page.AddResponse("Move Up", () => Move(0f, 0f, 0.1f)); page.AddResponse("Move Down", () => Move(0f, 0f, -0.1f)); }
/// <summary> /// Creates a new spawn object into its spawn area. /// Hand-placed objects are deserialized and added to the area. /// Spawn tables run their own logic to determine which object to spawn. /// </summary> /// <param name="spawnId">The ID of the spawn</param> /// <param name="detail">The details of the spawn</param> private static uint SpawnObject(Guid spawnId, SpawnDetail detail) { // Hand-placed spawns are stored as a serialized string. // Deserialize and add it to the area. if (!string.IsNullOrWhiteSpace(detail.SerializedObject)) { var deserialized = Object.Deserialize(detail.SerializedObject); var position = new Vector(detail.X, detail.Y, detail.Z); Object.AddToArea(deserialized, detail.Area, position); AssignCommand(deserialized, () => SetFacing(detail.Facing)); SetLocalString(deserialized, "SPAWN_ID", spawnId.ToString()); return(deserialized); } // Spawn tables have their own logic which must be run to determine the spawn to use. // Create the object at the stored location. else if (detail.SpawnTableId > 0) { var spawnTable = _spawnTables[detail.SpawnTableId]; var(objectType, resref) = spawnTable.GetNextSpawnResref(); // It's possible that the rules of the spawn table don't have a spawn ready to be created. // In this case, exit early. if (string.IsNullOrWhiteSpace(resref)) { return(OBJECT_INVALID); } var position = new Vector(detail.X, detail.Y, detail.Z); var location = Location(detail.Area, position, detail.Facing); var spawn = CreateObject(objectType, resref, location); SetLocalString(spawn, "SPAWN_ID", spawnId.ToString()); return(spawn); } return(OBJECT_INVALID); }
public static void MarketTerminalDisturbed() { if (GetInventoryDisturbType() != DisturbType.Added) { return; } var player = GetLastDisturbed(); var playerId = GetObjectUUID(player); var dbPlayer = DB.Get <Player>(playerId); var dbPlayerStore = DB.Get <PlayerStore>(playerId); var item = GetInventoryDisturbItem(); var itemId = GetObjectUUID(item); var serialized = Object.Serialize(item); var listingLimit = 5 + dbPlayer.SeedProgress.Rank * 5; if (dbPlayerStore.ItemsForSale.Count >= listingLimit || // Listing limit reached. GetBaseItemType(item) == BaseItem.Gold || // Gold can't be listed. string.IsNullOrWhiteSpace(GetResRef(item)) || // Items without resrefs can't be listed. GetHasInventory(item)) // Bags and other containers can't be listed. { Item.ReturnItem(player, item); SendMessageToPC(player, "This item cannot be listed."); return; } dbPlayerStore.ItemsForSale.Add(itemId, new PlayerStoreItem { Data = serialized, Name = GetName(item), Price = 0, StackSize = GetItemStackSize(item) }); DB.Set(playerId, dbPlayerStore); DestroyObject(item); SendMessageToPC(player, $"Listing limit: {dbPlayerStore.ItemsForSale.Count} / {5 + dbPlayer.SeedProgress.Rank * 5}"); }
public static void UsePerkRefundTome() { var player = OBJECT_SELF; if (!GetIsPC(player) || GetIsDM(player)) { return; } var item = Object.StringToObject(Events.GetEventData("ITEM_OBJECT_ID")); if (GetResRef(item) != "refund_tome") { return; } SetLocalObject(player, "PERK_REFUND_OBJECT", item); AssignCommand(player, () => ClearAllActions()); Dialog.StartConversation(player, player, "PerkRefundDialog"); // Don't display the "You cannot use this item" message. Skip the event. Events.SetEventResult("1"); Events.SkipEvent(); }
public static void LearnRecipes() { var user = OBJECT_SELF; if (!GetIsPC(user) || GetIsDM(user)) { SendMessageToPC(user, "Only players may use this item."); return; } var item = Object.StringToObject(Events.GetEventData("ITEM_OBJECT_ID")); var playerId = GetObjectUUID(user); var dbPlayer = DB.Get <Player>(playerId); var recipeList = GetLocalString(item, "RECIPES"); var recipeIds = recipeList.Split(','); var recipesLearned = 0; foreach (var recipeId in recipeIds) { // If it fails to parse, exit early. if (!int.TryParse(recipeId, out var convertedId)) { SendMessageToPC(user, "This recipe book has a configuration problem. Please inform a DM."); return; } // Id number is zero or negative. Skip as those aren't valid. if (convertedId <= 0) { SendMessageToPC(user, "This recipe book has a configuration problem. Please inform a DM."); return; } var recipeType = (RecipeType)convertedId; // Ensure this type of recipe has been registered. if (!Craft.RecipeExists(recipeType)) { SendMessageToPC(user, "This recipe has not been registered. Please inform a DM."); return; } // Player already knows this recipe. Move to the next one. if (dbPlayer.UnlockedRecipes.ContainsKey(recipeType)) { continue; } recipesLearned++; dbPlayer.UnlockedRecipes[recipeType] = DateTime.UtcNow; var recipeDetail = Craft.GetRecipe(recipeType); var skillDetail = Skill.GetSkillDetails(recipeDetail.Skill); SendMessageToPC(user, $"You learn the {skillDetail.Name} recipe: {recipeDetail.Name}."); } // Player didn't learn any recipes. Let them know but don't destroy the item. if (recipesLearned <= 0) { SendMessageToPC(user, "You have already learned all of the recipes contained in this book."); return; } DestroyObject(item); }
private void ListingInit(DialogPage page) { var player = GetPC(); var playerId = GetObjectUUID(player); var dbPlayerStore = DB.Get <PlayerStore>(playerId); var model = GetDataModel <Model>(); var item = dbPlayerStore.ItemsForSale[model.SelectedItemId]; void AdjustPrice(int amount) { item.Price += amount; if (item.Price <= 0) { item.Price = 1; } else if (item.Price > 999999) { item.Price = 999999; } DB.Set(playerId, dbPlayerStore); PlayerMarket.UpdateCacheEntry(playerId, dbPlayerStore); } page.Header = ColorToken.Green("Item: ") + item.StackSize + "x " + item.Name + "\n" + ColorToken.Green("Price: ") + item.Price + "\n\n" + "Please select an option."; if (model.IsConfirmingRemoveItem) { page.AddResponse(ColorToken.Red("CONFIRM REMOVE ITEM"), () => { var inWorldItem = Object.Deserialize(item.Data); Object.AcquireItem(player, inWorldItem); dbPlayerStore.ItemsForSale.Remove(model.SelectedItemId); DB.Set(playerId, dbPlayerStore); PlayerMarket.UpdateCacheEntry(playerId, dbPlayerStore); ChangePage(EditItemListPageId, false); model.IsConfirmingRemoveItem = false; }); } else { page.AddResponse(ColorToken.Red("Remove Item"), () => { model.IsConfirmingRemoveItem = true; }); } page.AddResponse("Increase by 10,000 gil", () => { AdjustPrice(10000); }); page.AddResponse("Increase by 1,000 gil", () => { AdjustPrice(1000); }); page.AddResponse("Increase by 100 gil", () => { AdjustPrice(100); }); page.AddResponse("Increase by 10 gil", () => { AdjustPrice(10); }); page.AddResponse("Increase by 1 gil", () => { AdjustPrice(1); }); page.AddResponse("Decrease by 10,000 gil", () => { AdjustPrice(-10000); }); page.AddResponse("Decrease by 1,000 gil", () => { AdjustPrice(-1000); }); page.AddResponse("Decrease by 100 gil", () => { AdjustPrice(-100); }); page.AddResponse("Decrease by 10 gil", () => { AdjustPrice(-10); }); page.AddResponse("Decrease by 1 gil", () => { AdjustPrice(-1); }); }
public static void LeaveParty() { var player = Object.StringToObject(Events.GetEventData("LEAVING")); RemovePlayerFromParty(player); }
/// <summary> /// When the module loads, spawns are located in all areas. Details about those spawns are stored /// into the cached data. /// </summary> public static void StoreSpawns() { for (var area = GetFirstArea(); GetIsObjectValid(area); area = GetNextArea()) { for (var obj = GetFirstObjectInArea(area); GetIsObjectValid(obj); obj = GetNextObjectInArea(area)) { var type = GetObjectType(obj); var position = GetPosition(obj); var facing = GetFacing(obj); var id = Guid.NewGuid(); // Hand-placed creature information is stored and the actual NPC is destroyed so it can be spawned by the system. if (type == ObjectType.Creature) { _spawns.Add(id, new SpawnDetail { SerializedObject = Object.Serialize(obj), X = position.X, Y = position.Y, Z = position.Z, Facing = facing, Area = area, RespawnDelayMinutes = 5 }); // Add this entry to the spawns by area cache. if (!_allSpawnsByArea.ContainsKey(area)) { _allSpawnsByArea[area] = new List <Guid>(); } _allSpawnsByArea[area].Add(id); DestroyObject(obj); } // Waypoints with a spawn table ID else if (type == ObjectType.Waypoint) { var spawnTableId = GetLocalInt(obj, "SPAWN_TABLE_ID"); if (spawnTableId > 0) { if (!_spawnTables.ContainsKey(spawnTableId)) { Log.Write(LogGroup.Error, $"Waypoint has an invalid spawn table Id. ({spawnTableId}) is not defined. Do you have the right spawn table Id?"); continue; } var spawnTable = _spawnTables[spawnTableId]; _spawns.Add(id, new SpawnDetail { SpawnTableId = spawnTableId, X = position.X, Y = position.Y, Z = position.Z, Facing = facing, Area = area, RespawnDelayMinutes = spawnTable.RespawnDelayMinutes }); // Add this entry to the spawns by area cache. if (!_allSpawnsByArea.ContainsKey(area)) { _allSpawnsByArea[area] = new List <Guid>(); } _allSpawnsByArea[area].Add(id); } } } } }