public PyDataType DestroyFitting(PyInteger itemID, CallInformation call) { ItemEntity item = this.mInventory.Items[itemID]; if (item.IsInRigSlot() == false) { throw new CannotDestroyFittedItem(); } if (item is ShipModule module) { // disable passive effects module.StopApplyingPassiveEffects(Client); } int oldLocationID = item.LocationID; Flags oldFlag = item.Flag; // destroy the rig this.ItemFactory.DestroyItem(item); // notify the client about the change call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, oldFlag, oldLocationID)); return(null); }
private void InvokeChanged(OptionsItemChangedEventArgs <TKey, TOptionsItem> args) { if (OnItemChange != null) { OnItemChange?.Invoke(args); } }
/// <summary> /// Removes an expired sell order from the database and returns the leftover items back to the player's hangar /// </summary> /// <param name="connection">The database connection that acquired the lock</param> /// <param name="order">The order to mark as expired</param> private void SellOrderExpired(MySqlConnection connection, MarketOrder order) { // remove order this.DB.RemoveOrder(connection, order.OrderID); // create the item back into the player's hanger // create the new item that will be used by the player ItemEntity item = this.ItemFactory.CreateSimpleItem( this.TypeManager[order.TypeID], order.CharacterID, order.LocationID, Flags.Hangar, order.UnitsLeft ); // immediately unload it, if it has to be loaded the OnItemUpdate notification will take care of that this.ItemFactory.UnloadItem(item); long stationNode = this.SystemManager.GetNodeStationBelongsTo(order.LocationID); if (stationNode == 0 || this.SystemManager.StationBelongsToUs(order.LocationID) == true) { this.NotificationManager.NotifyCharacter(order.CharacterID, Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, this.ItemFactory.LocationMarket.ID)); } else { this.NotificationManager.NotifyNode(stationNode, OnItemChange.BuildLocationChange(item.ID, this.ItemFactory.LocationMarket.ID, order.LocationID)); } // finally notify the character about the order change this.NotificationManager.NotifyCharacter(order.CharacterID, new OnOwnOrderChanged(order.TypeID, "Expiry")); // TODO: SEND AN EVEMAIL TO THE PLAYER? }
public void AddItem(Item item) { if (item.Stackable()) { bool isInInv = false; // Increment the item's quantity if its already in the inventory foreach (Item inventoryItem in itemList) { if (inventoryItem.itemType == item.itemType) { inventoryItem.quantity += item.quantity; isInInv = true; } } // If the item is not in the inventory, then add it if (!isInInv) { itemList.Add(item); } } else { itemList.Add(item); } // When the player picks up an item, it will trigger the EventHandler // which invokes its method in the InvUI.cs to force a re-draw of the inventory with the update OnItemChange?.Invoke(this, EventArgs.Empty); }
private void Reprocess(Character character, ItemEntity item, Client client) { if (item.Quantity < item.Type.PortionSize) { throw new QuantityLessThanMinimumPortion(item.Type); } int leftovers = item.Quantity % item.Type.PortionSize; int quantityToProcess = item.Quantity - leftovers; List <ReprocessingDB.Recoverables> recoverablesList = this.ReprocessingDB.GetRecoverables(item.Type.ID); foreach (ReprocessingDB.Recoverables recoverable in recoverablesList) { int ratio = recoverable.AmountPerBatch * quantityToProcess / item.Type.PortionSize; double efficiency = this.CalculateEfficiency(character, recoverable.TypeID); int quantityForClient = (int)(efficiency * (1.0 - this.mCorporation.TaxRate) * ratio); // create the new item ItemEntity newItem = this.ItemFactory.CreateSimpleItem(this.TypeManager[recoverable.TypeID], character, this.mStation, Flags.Hangar, quantityForClient); // notify the client about the new item client.NotifyMultiEvent(OnItemChange.BuildNewItemChange(newItem)); } }
public PyInteger LeaveShip(CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); Character character = this.ItemFactory.GetItem <Character>(callerCharacterID); // get the item type Type capsuleType = this.TypeManager[Types.Capsule]; // create a pod for this character ItemInventory capsule = this.ItemFactory.CreateShip(capsuleType, this.Location, character); // update capsule's name capsule.Name = character.Name + "'s Capsule"; // change character's location to the pod character.LocationID = capsule.ID; // notify the client about the item changes call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(capsule, Flags.Capsule, capsule.LocationID)); call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(character, Flags.Pilot, call.Client.ShipID)); // update session call.Client.ShipID = capsule.ID; // persist changes! capsule.Persist(); character.Persist(); // TODO: CHECKS FOR IN-SPACE LEAVING! return(capsule.ID); }
public PyDataType CharAddImplant(PyInteger itemID, CallInformation call) { if (this.Character.SkillQueue.Count > 0) { throw new FailedPlugInImplant(); } // get the item and plug it into our brain now! ItemEntity item = this.ItemFactory.LoadItem(itemID); // ensure the item is somewhere we can interact with it if (item.LocationID != call.Client.ShipID && item.LocationID != call.Client.StationID) { throw new CustomError("You do not have direct access to this implant"); } // check if the slot is free or not this.Character.EnsureFreeImplantSlot(item); // check ownership and skills required to plug in the implant item.EnsureOwnership(this.Character); item.CheckPrerequisites(this.Character); // separate the item if there's more than one if (item.Quantity > 1) { item.Quantity--; // notify the client of the stack change call.Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(item, item.Quantity + 1)); // save the item to the database item.Persist(); // create the new item with a default location and flag // this way the item location change notification is only needed once item = this.ItemFactory.CreateSimpleItem(item.Type, item.OwnerID, 0, Flags.None, 1, item.Contraband, item.Singleton); } int oldLocationID = item.LocationID; Flags oldFlag = item.Flag; item.LocationID = this.Character.ID; item.Flag = Flags.Implant; call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, oldFlag, oldLocationID)); // add the item to the inventory it belongs this.Character.AddItem(item); // persist item changes to database item.Persist(); return(null); }
/// <summary> /// 设置代理 /// </summary> /// <param name="_onItemChange"></param> /// <param name="_onClickItem"></param> public void SetDelegate(OnItemChange _onItemChange, OnClickItem _onClickItem) { m_pItemChangeCallBack = _onItemChange; if (_onClickItem != null) { m_pOnClickItemCallBack = _onClickItem; } }
public PyDataType MultiMerge(PyList merges, CallInformation call) { foreach (PyTuple merge in merges.GetEnumerable <PyTuple>()) { if (merge[0] is PyInteger == false || merge[1] is PyInteger == false || merge[2] is PyInteger == false) { continue; } PyInteger fromItemID = merge[0] as PyInteger; PyInteger toItemID = merge[1] as PyInteger; PyInteger quantity = merge[2] as PyInteger; if (this.mInventory.Items.TryGetValue(toItemID, out ItemEntity toItem) == false) { continue; } ItemEntity fromItem = this.ItemFactory.GetItem(fromItemID); // ignore singleton items if (fromItem.Singleton == true || toItem.Singleton == true) { continue; } // ignore items that are not the same type if (fromItem.Type.ID != toItem.Type.ID) { continue; } // if we're fully merging two stacks, just remove one item if (quantity == fromItem.Quantity) { int oldLocationID = fromItem.LocationID; // remove the item this.ItemFactory.DestroyItem(fromItem); // notify the client about the item too call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(fromItem, oldLocationID)); } else { // change the item's quantity fromItem.Quantity -= quantity; // notify the client about the change call.Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(fromItem, fromItem.Quantity + quantity)); fromItem.Persist(); } toItem.Quantity += quantity; call.Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(toItem, toItem.Quantity - quantity)); toItem.Persist(); } return(null); }
public PyDataType AssembleShip(PyInteger itemID, CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); int stationID = call.Client.EnsureCharacterIsInStation(); // ensure the item is loaded somewhere in this node // this will usually be taken care by the EVE Client if (this.ItemFactory.TryGetItem(itemID, out Ship ship) == false) { throw new CustomError("Ships not loaded for player and hangar!"); } Character character = this.ItemFactory.GetItem <Character>(callerCharacterID); if (ship.OwnerID != callerCharacterID) { throw new AssembleOwnShipsOnly(ship.OwnerID); } // do not do anything if item is already assembled if (ship.Singleton == true) { return(new ShipAlreadyAssembled(ship.Type)); } // first split the stack if (ship.Quantity > 1) { // subtract one off the stack ship.Quantity -= 1; ship.Persist(); // notify the quantity change call.Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(ship, ship.Quantity + 1)); // create the new item in the database Station station = this.ItemFactory.GetStaticStation(stationID); ship = this.ItemFactory.CreateShip(ship.Type, station, character); // notify the new item call.Client.NotifyMultiEvent(OnItemChange.BuildNewItemChange(ship)); } else { // stack of one, simple as changing the singleton flag ship.Singleton = true; call.Client.NotifyMultiEvent(OnItemChange.BuildSingletonChange(ship, false)); } // save the ship ship.Persist(); return(null); }
private void PrepareItemsForCourierOrAuctionContract(MySqlConnection connection, ulong contractID, ClusterConnection clusterConnection, PyList <PyList> itemList, Station station, int ownerID, int shipID) { // create the container in the system to ensure it's not visible to the player Container container = this.ItemFactory.CreateSimpleItem(this.TypeManager[Types.PlasticWrap], this.ItemFactory.LocationSystem.ID, station.ID, Flags.None) as Container; Dictionary <int, ContractDB.ItemQuantityEntry> items = this.DB.PrepareItemsForContract(connection, contractID, itemList, station, ownerID, container.ID, shipID); double volume = 0; // build notification for item changes OnItemChange changes = new OnItemChange(); long stationNode = this.SystemManager.GetNodeStationBelongsTo(station.ID); bool stationBelongsToUs = this.SystemManager.StationBelongsToUs(station.ID); // notify the changes in the items to the nodes foreach ((int _, ContractDB.ItemQuantityEntry item) in items) { if (stationNode == 0 || stationBelongsToUs == true) { ItemEntity entity = this.ItemFactory.LoadItem(item.ItemID); entity.LocationID = container.ID; entity.Persist(); // notify the character this.NotificationManager.NotifyCharacter(ownerID, Notifications.Client.Inventory.OnItemChange.BuildLocationChange(entity, station.ID)); } else { // queue the notification changes.AddChange(item.ItemID, "locationID", station.ID, container.ID); } // ensure the volume is taken into account volume += item.Volume; } // notify the proper node if needed if (changes.Updates.Count > 0) { this.NotificationManager.NotifyNode(stationNode, changes); } // update the contract with the crate and the new volume this.DB.UpdateContractCrateAndVolume(ref connection, contractID, container.ID, volume); }
public PyDataType RemoveImplantFromCharacter(PyInteger itemID, CallInformation call) { if (this.Character.Items.TryGetValue(itemID, out ItemEntity item) == false) { throw new CustomError("This implant is not in your brain!"); } // now destroy the item this.ItemFactory.DestroyItem(item); // notify the change call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, this.Character.ID)); return(null); }
public PyDataType Board(PyInteger itemID, CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); // ensure the item is loaded somewhere in this node // this will usually be taken care by the EVE Client if (this.ItemFactory.TryGetItem(itemID, out Ship newShip) == false) { throw new CustomError("Ships not loaded for player and hangar!"); } Character character = this.ItemFactory.GetItem <Character>(callerCharacterID); Ship currentShip = this.ItemFactory.GetItem <Ship>((int)call.Client.ShipID); if (newShip.Singleton == false) { throw new CustomError("TooFewSubSystemsToUndock"); } // TODO: CHECKS FOR IN-SPACE BOARDING! // check skills required to board the given ship newShip.EnsureOwnership(character); newShip.CheckPrerequisites(character); // move the character into this new ship character.LocationID = newShip.ID; // finally update the session call.Client.ShipID = newShip.ID; // notify the client about the change in location call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(character, Flags.Pilot, currentShip.ID)); character.Persist(); // ensure the character is not removed when the capsule is removed currentShip.RemoveItem(character); if (currentShip.Type.ID == (int)Types.Capsule) { // destroy the pod from the database this.ItemFactory.DestroyItem(currentShip); // notify the player of the item change call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(currentShip, this.Location.ID)); } return(null); }
private void OnSkillTrainingCompleted(int itemID) { Skill skill = this.Character.Items[itemID] as Skill; // set the skill to the proper flag and set the correct attributes skill.Flag = Flags.Skill; skill.Level = skill.Level + 1; skill.ExpiryTime = 0; // make sure the client is aware of the new item's status this.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(skill, Flags.SkillInTraining)); // also notify attribute changes this.Client.NotifyAttributeChange(new Attributes[] { Attributes.skillPoints, Attributes.skillLevel }, skill); this.Client.NotifyMultiEvent(new OnSkillTrained(skill)); this.Client.SendPendingNotifications(); skill.Persist(); // create history entry this.DB.CreateSkillHistoryRecord(skill.Type, this.Character, SkillHistoryReason.SkillTrainingComplete, skill.Points); // finally remove it off the skill queue this.Character.SkillQueue.RemoveAll(x => x.Skill.ID == skill.ID && x.TargetLevel == skill.Level); this.Character.CalculateSkillPoints(); // get the next skill from the queue (if any) and send the client proper notifications if (this.Character.SkillQueue.Count == 0) { this.Character.Persist(); return; } skill = this.Character.SkillQueue[0].Skill; // setup the process for training next skill in the queue this.SetupTimerForNextSkillInQueue(); this.Client.SendPendingNotifications(); // create history entry this.DB.CreateSkillHistoryRecord(skill.Type, this.Character, SkillHistoryReason.SkillTrainingStarted, skill.Points); // persist the character changes this.Character.Persist(); }
void MouseDown(UIMouseEvent evt, UIElement listeningElement) { Player player = Main.LocalPlayer; if (player.itemAnimation == 0 && player.itemTime == 0 && !IsLocked() && CanPutIntoSlot(Main.mouseItem)) { Item tempItem = Main.mouseItem.Clone(); Main.mouseItem = item.Clone(); if (!Main.mouseItem.IsAir) { Main.playerInventory = true; } item = tempItem; Main.PlaySound(SoundID.Grab, Main.LocalPlayer.position); OnItemChange?.Invoke(Main.mouseItem, item); } }
private void InitializeCharacter() { // perform basic checks on the skill queue // iterate the skill queue and generate a timer for the first skill that must be trained // this also prepares the correct notification for multiple skill training done PyList <PyInteger> skillTypeIDs = new PyList <PyInteger>(); List <Character.SkillQueueEntry> toRemove = new List <Character.SkillQueueEntry>(); foreach (Character.SkillQueueEntry entry in this.Character.SkillQueue) { if (entry.Skill.ExpiryTime < DateTime.Now.ToFileTimeUtc()) { // ensure the skill is marked as trained and that they have the correct values stored entry.Skill.Level = entry.TargetLevel; entry.Skill.Flag = Flags.Skill; entry.Skill.ExpiryTime = 0; // add the skill to the list of trained skills for the big notification skillTypeIDs.Add(entry.Skill.Type.ID); toRemove.Add(entry); // update it's location in the client if needed this.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(entry.Skill, Flags.SkillInTraining)); // also notify attribute changes this.Client.NotifyAttributeChange(new Attributes[] { Attributes.skillPoints, Attributes.skillLevel }, entry.Skill); } } // remove skills that already expired this.Character.SkillQueue.RemoveAll(x => toRemove.Contains(x)); // send notification of multiple skills being finished training (if any) if (skillTypeIDs.Count > 0) { this.Client.NotifyMultiEvent(new OnGodmaMultipleSkillsTrained(skillTypeIDs)); } // persists the skill queue this.Character.Persist(); // setup the process for training next skill in the queue this.SetupTimerForNextSkillInQueue(); }
private void StackAll(Flags locationFlag, CallInformation call) { // TODO: ADD CONSTRAINTS CHECKS FOR THE LOCATIONFLAG foreach ((int firstItemID, ItemEntity firstItem) in this.mInventory.Items) { // singleton items are not even checked if (firstItem.Singleton == true || firstItem.Flag != locationFlag) { continue; } foreach ((int secondItemID, ItemEntity secondItem) in this.mInventory.Items) { // ignore the same itemID as they cannot really be merged if (firstItemID == secondItemID) { continue; } // ignore the item if it's singleton if (secondItem.Singleton == true || secondItem.Flag != locationFlag) { continue; } // ignore the item check if they're not the same type ID if (firstItem.Type.ID != secondItem.Type.ID) { continue; } int oldQuantity = secondItem.Quantity; // add the quantity of the first item to the second secondItem.Quantity += firstItem.Quantity; // also create the notification for the user call.Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(secondItem, oldQuantity)); this.ItemFactory.DestroyItem(firstItem); // notify the client about the item too call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(firstItem, firstItem.Flag, secondItem.LocationID)); // ensure the second item is saved to database too secondItem.Persist(); // finally break this loop as the merge was already done break; } } }
public PyDataType Reprocess(PyList itemIDs, PyInteger ownerID, PyInteger flag, PyBool unknown, PyList skipChecks, CallInformation call) { Character character = this.ItemFactory.GetItem <Character>(call.Client.EnsureCharacterIsSelected()); // TODO: TAKE INTO ACCOUNT OWNERID AND FLAG, THESE MOST LIKELY WILL BE USED BY CORP STUFF foreach (PyInteger itemID in itemIDs.GetEnumerable <PyInteger>()) { if (this.mInventory.Items.TryGetValue(itemID, out ItemEntity item) == false) { throw new MktNotOwner(); } // reprocess the item this.Reprocess(character, item, call.Client); int oldLocationID = item.LocationID; // finally remove the item from the inventories this.ItemFactory.DestroyItem(item); // notify the client about the item being destroyed call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, oldLocationID)); } return(null); }
private void CreateCmd(string[] argv, CallInformation call) { if (argv.Length < 2) { throw new SlashError("create takes at least one argument"); } int typeID = int.Parse(argv[1]); int quantity = 1; if (argv.Length > 2) { quantity = int.Parse(argv[2]); } if (call.Client.StationID == null) { throw new SlashError("Creating items can only be done at station"); } // ensure the typeID exists if (this.TypeManager.ContainsKey(typeID) == false) { throw new SlashError("The specified typeID doesn't exist"); } // create a new item with the correct locationID Station location = this.ItemFactory.GetStaticStation((int)call.Client.StationID); Character character = this.ItemFactory.GetItem <Character>(call.Client.EnsureCharacterIsSelected()); Type itemType = this.TypeManager[typeID]; ItemEntity item = this.ItemFactory.CreateSimpleItem(itemType, character, location, Flags.Hangar, quantity); item.Persist(); // send client a notification so they can display the item in the hangar call.Client.NotifyMultiEvent(OnItemChange.BuildNewItemChange(item)); }
public PyDataType TrashItems(PyList itemIDs, PyInteger stationID, CallInformation call) { foreach (PyInteger itemID in itemIDs.GetEnumerable <PyInteger>()) { // do not trash the active ship if (itemID == call.Client.ShipID) { throw new CantMoveActiveShip(); } ItemEntity item = this.ItemFactory.GetItem(itemID); // store it's location id int oldLocation = item.LocationID; Flags oldFlag = item.Flag; // remove the item off the ItemManager this.ItemFactory.DestroyItem(item); // notify the client of the change call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, oldFlag, oldLocation)); // TODO: CHECK IF THE ITEM HAS ANY META INVENTORY AND/OR BOUND SERVICE // TODO: AND FREE THOSE TOO SO THE ITEMS CAN BE REMOVED OFF THE DATABASE } return(null); }
public PyDataType AssembleCargoContainer(PyInteger containerID, PyDataType ignored, PyDecimal ignored2, CallInformation call) { ItemEntity item = this.ItemFactory.GetItem(containerID); if (item.OwnerID != call.Client.EnsureCharacterIsSelected()) { throw new TheItemIsNotYoursToTake(containerID); } // ensure the item is a cargo container switch (item.Type.Group.ID) { case (int)Groups.CargoContainer: case (int)Groups.SecureCargoContainer: case (int)Groups.AuditLogSecureContainer: case (int)Groups.FreightContainer: case (int)Groups.Tool: case (int)Groups.MobileWarpDisruptor: break; default: throw new ItemNotContainer(containerID); } bool oldSingleton = item.Singleton; // update singleton item.Singleton = true; item.Persist(); // notify the client call.Client.NotifyMultiEvent(OnItemChange.BuildSingletonChange(item, oldSingleton)); return(null); }
public PyDataType CancelCharOrder(PyInteger orderID, PyInteger regionID, CallInformation call) { int callerCharacterID = call.Client.EnsureCharacterIsSelected(); Character character = this.ItemFactory.GetItem <Character>(callerCharacterID); using MySqlConnection connection = this.DB.AcquireMarketLock(); try { MarketOrder order = this.DB.GetOrderById(connection, orderID); if (order.CharacterID != callerCharacterID) { throw new MktOrderDidNotMatch(); } long currentTime = DateTime.UtcNow.ToFileTimeUtc(); // check for timers, no changes in less than 5 minutes if (currentTime < order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) { throw new MktOrderDelay((order.Issued + TimeSpan.TicksPerSecond * this.NodeContainer.Constants[Constants.mktModificationDelay]) - currentTime); } // check for escrow if (order.Escrow > 0.0 && order.Bid == TransactionType.Buy) { using Wallet wallet = this.WalletManager.AcquireWallet(character.ID, 1000); { wallet.CreateJournalRecord(MarketReference.MarketEscrow, null, null, order.Escrow); } } if (order.Bid == TransactionType.Sell) { // create the new item that will be used by the player ItemEntity item = this.ItemFactory.CreateSimpleItem( this.TypeManager[order.TypeID], character.ID, order.LocationID, Flags.Hangar, order.UnitsLeft ); // immediately unload it, if it has to be loaded the OnItemUpdate notification will take care of that this.ItemFactory.UnloadItem(item); // check what node this item should be loaded at long stationNode = this.SystemManager.GetNodeStationBelongsTo(order.LocationID); if (stationNode == 0 || this.SystemManager.StationBelongsToUs(order.LocationID) == true) { this.NotificationManager.NotifyCharacter(character.ID, Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, this.ItemFactory.LocationMarket.ID)); } else { this.NotificationManager.NotifyNode(stationNode, OnItemChange.BuildLocationChange(item.ID, this.ItemFactory.LocationMarket.ID, order.LocationID)); } } // finally remove the order this.DB.RemoveOrder(connection, order.OrderID); // send a OnOwnOrderChange notification call.Client.NotifyMultiEvent(new OnOwnOrderChanged(order.TypeID, "Removed")); } finally { this.DB.ReleaseMarketLock(connection); } return(null); }
private void MoveItemHere(ItemEntity item, Flags newFlag) { // get the old location stored as it'll be used in the notifications int oldLocation = item.LocationID; Flags oldFlag = item.Flag; // rig slots cannot be moved if (item.IsInRigSlot() == true) { throw new CannotRemoveUpgradeManually(); } // special situation, if the old location is a module slot ensure the item is first offlined if (item.IsInModuleSlot() == true) { if (item is ShipModule module) { if (module.Attributes[Attributes.isOnline] == 1) { module.StopApplyingEffect("online", Client); } // disable passive effects too module.StopApplyingPassiveEffects(Client); } } // extra special situation, is the new flag an autofit one? if (newFlag == Flags.AutoFit) { // capsules cannot fit anything if (this.mInventory.Type.ID == (int)Types.Capsule) { throw new CantFitToCapsule(); } if (this.mInventory is Ship ship) { // determine where to put the item if (item is ShipModule module) { if (module.IsHighSlot() == true) { newFlag = this.GetFreeHighSlot(ship); } else if (module.IsMediumSlot() == true) { newFlag = this.GetFreeMediumSlot(ship); } else if (module.IsLowSlot() == true) { newFlag = this.GetFreeLowSlot(ship); } else if (module.IsRigSlot() == true) { newFlag = this.GetFreeRigSlot(ship); } else { // this item cannot be fitted, move it to cargo, maybe throw a exception about not being able to fit it? newFlag = Flags.Cargo; } } // TODO: HANDLE CHARGES! else { newFlag = Flags.Cargo; } } else { newFlag = Flags.Hangar; } } // special situation, if the new location is a module slot ensure the item is a singleton (TODO: HANDLE CHARGES TOO) if (newFlag.IsModule() == true) { ShipModule module = null; if (item is ShipModule shipModule) { module = shipModule; } if (item.Quantity == 1) { // remove item off the old inventory if required if (this.ItemFactory.TryGetItem(item.LocationID, out ItemInventory inventory) == true) { inventory.RemoveItem(item); } OnItemChange changes = new OnItemChange(item); if (item.Singleton == false) { changes.AddChange(ItemChange.Singleton, item.Singleton); } item.LocationID = this.mInventory.ID; item.Flag = newFlag; item.Singleton = true; changes .AddChange(ItemChange.LocationID, oldLocation) .AddChange(ItemChange.Flag, (int)oldFlag); // notify the character about the change Client.NotifyMultiEvent(changes); // update meta inventories too this.ItemFactory.MetaInventoryManager.OnItemMoved(item, oldLocation, this.mInventory.ID); // finally persist the item changes item.Persist(); } else { // item is not a singleton, create a new item, decrease quantity and send notifications ItemEntity newItem = this.ItemFactory.CreateSimpleItem(item.Type, item.OwnerID, this.mInventory.ID, newFlag, 1, false, true); item.Quantity -= 1; // notify the quantity change and the new item Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(item, item.Quantity + 1)); Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(newItem, Flags.None, 0)); item.Persist(); // replace reference so the following code handle things properly item = newItem; if (item is ShipModule shipModule2) { module = shipModule2; } } try { // apply all the passive effects (this also blocks the item fitting if the initialization fails) module?.ApplyPassiveEffects(Client); // extra check, ensure that the character has the required skills } catch (UserError) { // ensure that the passive effects that got applied already are removed from the item module?.StopApplyingPassiveEffects(Client); int newOldLocation = item.LocationID; Flags newOldFlag = item.Flag; // now undo the whole thing item.LocationID = oldLocation; item.Flag = oldFlag; Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, newOldFlag, newOldLocation)); throw; } // ensure the new inventory knows this.mInventory.AddItem(item); module?.Persist(); // put the module online after fitting it as long as it's a normal module if (module?.IsRigSlot() == false) { module?.ApplyEffect("online", Client); } } else { // remove item off the old inventory if required if (this.ItemFactory.TryGetItem(item.LocationID, out ItemInventory inventory) == true) { inventory.RemoveItem(item); } // set the new location for the item item.LocationID = this.mInventory.ID; item.Flag = newFlag; // notify the character about the change Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(item, oldFlag, oldLocation)); // update meta inventories too this.ItemFactory.MetaInventoryManager.OnItemMoved(item, oldLocation, this.mInventory.ID); // ensure the new inventory knows this.mInventory.AddItem(item); // finally persist the item changes item.Persist(); } }
private void PlaceSellOrderCharUpdateItems(MySqlConnection connection, Client client, int stationID, int typeID, int quantity) { Dictionary <int, MarketDB.ItemQuantityEntry> items = null; // depending on where the character that is placing the order, the way to detect the items should be different if (stationID == client.StationID) { items = this.DB.PrepareItemForOrder(connection, typeID, stationID, client.ShipID ?? -1, quantity, (int)client.CharacterID); } else { items = this.DB.PrepareItemForOrder(connection, typeID, stationID, -1, quantity, (int)client.CharacterID); } if (items is null) { throw new NotEnoughQuantity(this.TypeManager[typeID]); } long stationNode = this.SystemManager.GetNodeStationBelongsTo(stationID); if (this.SystemManager.StationBelongsToUs(stationID) == true || stationNode == 0) { // load the items here and send proper notifications foreach ((int _, MarketDB.ItemQuantityEntry entry) in items) { ItemEntity item = this.ItemFactory.LoadItem(entry.ItemID); if (entry.Quantity == 0) { // item has to be destroyed this.ItemFactory.DestroyItem(item); // notify item destroyal client.NotifyMultiEvent(Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, stationID)); } else { // just a quantity change item.Quantity = entry.Quantity; // notify the client client.NotifyMultiEvent(Notifications.Client.Inventory.OnItemChange.BuildQuantityChange(item, entry.OriginalQuantity)); // unload the item if it's not needed this.ItemFactory.UnloadItem(item); } } } else { // the item changes should be handled by a different node OnItemChange changes = new OnItemChange(); foreach ((int _, MarketDB.ItemQuantityEntry entry) in items) { if (entry.Quantity == 0) { changes.AddChange(entry.ItemID, "locationID", stationID, this.ItemFactory.LocationMarket.ID); } else { changes.AddChange(entry.ItemID, "quantity", entry.OriginalQuantity, entry.Quantity); } } } }
private void GiveSkillCmd(string[] argv, CallInformation call) { // TODO: NOT NODE-SAFE, MUST REIMPLEMENT TAKING THAT INTO ACCOUNT! if (argv.Length != 4) { throw new SlashError("GiveSkill must have 4 arguments"); } string target = argv[1].Trim(new [] { '"', ' ' }); string skillType = argv[2]; int level = int.Parse(argv[3]); if (target != "me") { throw new SlashError("giveskill only supports me for now"); } Character character = this.ItemFactory.GetItem <Character>(call.Client.EnsureCharacterIsSelected()); if (skillType == "all") { // player wants all the skills! IEnumerable <KeyValuePair <int, Type> > skillTypes = this.TypeManager.Where(x => x.Value.Group.Category.ID == (int)Categories.Skill && x.Value.Published == true); Dictionary <int, Skill> injectedSkills = character.InjectedSkillsByTypeID; foreach (KeyValuePair <int, Type> pair in skillTypes) { // skill already injected, train it to the desired level if (injectedSkills.ContainsKey(pair.Key) == true) { Skill skill = injectedSkills[pair.Key]; skill.Level = level; skill.Persist(); call.Client.NotifyMultiEvent(new OnSkillTrained(skill)); } else { // skill not injected, create it, inject and done Skill skill = this.ItemFactory.CreateSkill(pair.Value, character, level, SkillHistoryReason.GMGiveSkill); call.Client.NotifyMultiEvent(OnItemChange.BuildNewItemChange(skill)); call.Client.NotifyMultiEvent(new OnSkillInjected()); } } } else { int skillTypeID = int.Parse(skillType); Dictionary <int, Skill> injectedSkills = character.InjectedSkillsByTypeID; if (injectedSkills.ContainsKey(skillTypeID) == true) { Skill skill = injectedSkills[skillTypeID]; skill.Level = level; skill.Persist(); call.Client.NotifyMultiEvent(new OnSkillTrained(skill)); } else { // skill not injected, create it, inject and done Skill skill = this.ItemFactory.CreateSkill(this.TypeManager[skillTypeID], character, level, SkillHistoryReason.GMGiveSkill); call.Client.NotifyMultiEvent(OnItemChange.BuildNewItemChange(skill)); call.Client.NotifyMultiEvent(new OnSkillInjected()); } } }
private void HandleOnItemUpdate(Notifications.Nodes.Inventory.OnItemChange change) { foreach ((PyInteger itemID, PyDictionary _changes) in change.Updates) { PyDictionary <PyString, PyTuple> changes = _changes.GetEnumerable <PyString, PyTuple>(); ItemEntity item = this.ItemFactory.LoadItem(itemID, out bool loadRequired); // if the item was just loaded there's extra things to take into account // as the item might not even need a notification to the character it belongs to if (loadRequired == true) { // trust that the notification got to the correct node // load the item and check the owner, if it's logged in and the locationID is loaded by us // that means the item should be kept here if (this.ItemFactory.TryGetItem(item.LocationID, out ItemEntity location) == false || this.CharacterManager.IsCharacterConnected(item.OwnerID) == false) { // this item should not be loaded, so unload and return this.ItemFactory.UnloadItem(item); return; } bool locationBelongsToUs = true; switch (location) { case Station _: locationBelongsToUs = this.SystemManager.StationBelongsToUs(location.ID); break; case SolarSystem _: locationBelongsToUs = this.SystemManager.SolarSystemBelongsToUs(location.ID); break; } if (locationBelongsToUs == false) { this.ItemFactory.UnloadItem(item); return; } } OnItemChange itemChange = new OnItemChange(item); // update item and build change notification if (changes.TryGetValue("locationID", out PyTuple locationChange) == true) { PyInteger oldValue = locationChange[0] as PyInteger; PyInteger newValue = locationChange[1] as PyInteger; itemChange.AddChange(ItemChange.LocationID, oldValue); item.LocationID = newValue; } if (changes.TryGetValue("quantity", out PyTuple quantityChange) == true) { PyInteger oldValue = quantityChange[0] as PyInteger; PyInteger newValue = quantityChange[1] as PyInteger; itemChange.AddChange(ItemChange.Quantity, oldValue); item.Quantity = newValue; } if (changes.TryGetValue("ownerID", out PyTuple ownerChange) == true) { PyInteger oldValue = ownerChange[0] as PyInteger; PyInteger newValue = ownerChange[1] as PyInteger; itemChange.AddChange(ItemChange.OwnerID, oldValue); item.OwnerID = newValue; } if (changes.TryGetValue("singleton", out PyTuple singletonChange) == true) { PyBool oldValue = singletonChange[0] as PyBool; PyBool newValue = singletonChange[1] as PyBool; itemChange.AddChange(ItemChange.Singleton, oldValue); item.Singleton = newValue; } // TODO: IDEALLY THIS WOULD BE ENQUEUED SO ALL OF THEM ARE SENT AT THE SAME TIME // TODO: BUT FOR NOW THIS SHOULD SUFFICE // send the notification this.NotificationManager.NotifyCharacter(item.OwnerID, "OnMultiEvent", new PyTuple(1) { [0] = new PyList(1) { [0] = itemChange } }); if (item.LocationID == this.ItemFactory.LocationRecycler.ID) { // the item is removed off the database if the new location is the recycler item.Destroy(); } else if (item.LocationID == this.ItemFactory.LocationMarket.ID) { // items that are moved to the market can be unloaded this.ItemFactory.UnloadItem(item); } else { // save the item if the new location is not removal item.Persist(); } } }
//public void RenderPropertyList () //{ // int i = 0; // if (inspecting_person != null) { // ylist = gameEngine.Instance.getScanner ().getPropertyListByOwner (inspecting_person); // foreach (Property pl in mylist) { // GameObject newitem = GameObject.Instantiate (preFabItemProperty) as GameObject; // newitem.transform.parent = Grid.transform; // newitem.transform.localPosition = new Vector3 (itemBound.x * i, 0f, 0f); // foreach (Transform t in newitem.transform) { // if (t.gameObject.name.Equals ("UISprite")) { // setItemSprite (t.gameObject.GetComponent<UISprite> (), pl); // //Debug.Log ("girl is active"); // } // } // i++; // } // } // } /// <summary> /// 设置代理 /// </summary> /// <param name="_onItemChange"></param> /// <param name="_onClickItem"></param> public void SetDelegate (OnItemChange _onItemChange, OnClickItem _onClickItem) { m_pItemChangeCallBack = _onItemChange; if (_onClickItem != null) { m_pOnClickItemCallBack = _onClickItem; } }
private void AcceptItemExchangeContract(MySqlConnection connection, Client client, ContractDB.Contract contract, Station station, int ownerID, Flags flag = Flags.Hangar) { List <ContractDB.ItemQuantityEntry> offeredItems = this.DB.GetOfferedItems(connection, contract.ID); Dictionary <int, int> itemsToCheck = this.DB.GetRequiredItemTypeIDs(connection, contract.ID); List <ContractDB.ItemQuantityEntry> changedItems = this.DB.CheckRequiredItemsAtStation(connection, station, ownerID, contract.IssuerID, flag, itemsToCheck); // extract the crate this.DB.ExtractCrate(connection, contract.CrateID, station.ID, ownerID); long stationNode = this.SystemManager.GetNodeStationBelongsTo(station.ID); if (stationNode == 0 || this.SystemManager.StationBelongsToUs(station.ID) == true) { foreach (ContractDB.ItemQuantityEntry change in changedItems) { ItemEntity item = this.ItemFactory.LoadItem(change.ItemID); if (change.Quantity == 0) { // remove item from the meta inventories this.ItemFactory.MetaInventoryManager.OnItemDestroyed(item); // temporarily move the item to the recycler, let the current owner know item.LocationID = this.ItemFactory.LocationRecycler.ID; client.NotifyMultiEvent(Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, station.ID)); // now set the item to the correct owner and place and notify it's new owner // TODO: TAKE forCorp INTO ACCOUNT item.LocationID = station.ID; item.OwnerID = contract.IssuerID; this.NotificationManager.NotifyCharacter(contract.IssuerID, Notifications.Client.Inventory.OnItemChange.BuildNewItemChange(item)); // add the item back to meta inventories if required this.ItemFactory.MetaInventoryManager.OnItemLoaded(item); } else { int oldQuantity = item.Quantity; item.Quantity = change.Quantity; client.NotifyMultiEvent(Notifications.Client.Inventory.OnItemChange.BuildQuantityChange(item, oldQuantity)); item.Persist(); // unload the item if required this.ItemFactory.UnloadItem(item); } } // move the offered items foreach (ContractDB.ItemQuantityEntry entry in offeredItems) { ItemEntity item = this.ItemFactory.LoadItem(entry.ItemID); item.LocationID = station.ID; item.OwnerID = ownerID; client.NotifyMultiEvent(Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, contract.CrateID)); item.Persist(); // unload the item if possible this.ItemFactory.UnloadItem(item); } } else { OnItemChange changes = new OnItemChange(); foreach (ContractDB.ItemQuantityEntry change in changedItems) { if (change.Quantity == 0) { changes .AddChange(change.ItemID, "locationID", contract.CrateID, station.ID) .AddChange(change.ItemID, "ownerID", contract.IssuerID, ownerID); } else { // change the item quantity changes.AddChange(change.ItemID, "quantity", change.OldQuantity, change.Quantity); // create a new item and notify the new node about it // TODO: HANDLE BLUEPRINTS TOO! RIGHT NOW NO DATA IS COPIED FOR THEM ItemEntity item = this.ItemFactory.CreateSimpleItem( this.TypeManager[change.TypeID], contract.IssuerID, station.ID, Flags.Hangar, change.OldQuantity - change.Quantity, false, false ); // unload the created item this.ItemFactory.UnloadItem(item); changes.AddChange(item.ID, "location", 0, station.ID); } } // move the offered items foreach (ContractDB.ItemQuantityEntry entry in offeredItems) { // TODO: TAKE INTO ACCOUNT forCorp changes .AddChange(entry.ItemID, "locationID", contract.CrateID, station.ID) .AddChange(entry.ItemID, "ownerID", contract.IssuerID, station.ID); } } // the contract was properly accepted, update it's status this.DB.UpdateContractStatus(ref connection, contract.ID, ContractStatus.Finished); this.DB.UpdateAcceptorID(ref connection, contract.ID, ownerID); this.DB.UpdateAcceptedDate(ref connection, contract.ID); this.DB.UpdateCompletedDate(ref connection, contract.ID); // notify the contract as being accepted if (contract.ForCorp == false) { this.NotificationManager.NotifyCharacter(contract.IssuerID, new OnContractAccepted(contract.ID)); } else { this.NotificationManager.NotifyCorporation(contract.IssuerCorpID, new OnContractAccepted(contract.ID)); } }
public PyDataType SaveSkillQueue(PyList queue, CallInformation call) { if (this.Character.SkillQueue.Count > 0) { // calculate current skill in training points Skill currentSkill = this.Character.SkillQueue[0].Skill; if (currentSkill.ExpiryTime > 0) { // get the total amount of minutes the skill would have taken to train completely long pointsLeft = (long)(currentSkill.GetSkillPointsForLevel(this.Character.SkillQueue[0].TargetLevel) - currentSkill.Points); TimeSpan timeLeft = TimeSpan.FromMinutes(pointsLeft / this.Character.GetSkillPointsPerMinute(currentSkill)); DateTime endTime = DateTime.FromFileTimeUtc(currentSkill.ExpiryTime); DateTime startTime = endTime.Subtract(timeLeft); TimeSpan timePassed = DateTime.UtcNow - startTime; // calculate the skill points to add double skillPointsToAdd = timePassed.TotalMinutes * this.Character.GetSkillPointsPerMinute(currentSkill); currentSkill.Points += skillPointsToAdd; } // remove the timer associated with the queue this.FreeSkillQueueTimers(); foreach (Character.SkillQueueEntry entry in this.Character.SkillQueue) { entry.Skill.Flag = Flags.Skill; call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(entry.Skill, Flags.SkillInTraining)); // send notification of skill training stopped call.Client.NotifyMultiEvent(new OnSkillTrainingStopped(entry.Skill)); // create history entry this.DB.CreateSkillHistoryRecord(entry.Skill.Type, this.Character, SkillHistoryReason.SkillTrainingCancelled, entry.Skill.Points); entry.Skill.ExpiryTime = 0; entry.Skill.Persist(); } this.Character.SkillQueue.Clear(); } DateTime startDateTime = DateTime.UtcNow; bool first = true; foreach (PyTuple entry in queue.GetEnumerable <PyTuple>()) { // ignore wrong entries if (entry.Count != 2) { continue; } int typeID = entry[0] as PyInteger; int level = entry[1] as PyInteger; // search for an item with the given typeID ItemEntity item = this.Character.Items.First(x => x.Value.Type.ID == typeID && (x.Value.Flag == Flags.Skill || x.Value.Flag == Flags.SkillInTraining)).Value; // ignore items that are not skills if (item is Skill == false) { continue; } Skill skill = item as Skill; double skillPointsLeft = skill.GetSkillPointsForLevel(level) - skill.Points; TimeSpan duration = TimeSpan.FromMinutes(skillPointsLeft / this.Character.GetSkillPointsPerMinute(skill)); DateTime expiryTime = startDateTime + duration; skill.ExpiryTime = expiryTime.ToFileTimeUtc(); skill.Flag = Flags.SkillInTraining; call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(skill, Flags.Skill)); startDateTime = expiryTime; // skill added to the queue, persist the character to ensure all the changes are saved this.Character.SkillQueue.Add(new Character.SkillQueueEntry() { Skill = skill, TargetLevel = level }); if (first == true) { // skill was trained, send the success message call.Client.NotifyMultiEvent(new OnSkillStartTraining(skill)); // create history entry this.DB.CreateSkillHistoryRecord(skill.Type, this.Character, SkillHistoryReason.SkillTrainingStarted, skill.Points); first = false; } skill.Persist(); } // ensure the timer is present for the first skill in the queue this.SetupTimerForNextSkillInQueue(); // finally persist the data to the database this.Character.Persist(); return(null); }
private void PlaceImmediateBuyOrderChar(MySqlConnection connection, Wallet wallet, int typeID, Character character, int stationID, int quantity, double price, int range, CallInformation call) { int solarSystemID = this.ItemFactory.GetStaticStation(stationID).SolarSystemID; // look for matching sell orders MarketOrder[] orders = this.DB.FindMatchingOrders(connection, price, typeID, character.ID, solarSystemID, TransactionType.Sell); // ensure there's at least some that match this.CheckMatchingSellOrders(orders, quantity, solarSystemID); foreach (MarketOrder order in orders) { int quantityToBuy = 0; if (order.Range == -1 && order.LocationID != stationID) { continue; } if (order.Range != -1 && order.Range < order.Jumps) { continue; } if (order.UnitsLeft <= quantity) { // the order was completed, remove it from the database this.DB.RemoveOrder(connection, order.OrderID); // increase the amount of bought items quantityToBuy = order.UnitsLeft; quantity -= order.UnitsLeft; } else { // part of the sell order was satisfied this.DB.UpdateOrderRemainingQuantity(connection, order.OrderID, order.UnitsLeft - quantity, 0); quantityToBuy = quantity; quantity = 0; } if (quantityToBuy > 0) { // acquire wallet journal for seller so we can update their balance to add the funds that he got using Wallet sellerWallet = this.WalletManager.AcquireWallet(order.CharacterID, order.AccountID); { sellerWallet.CreateJournalRecord(MarketReference.MarketTransaction, character.ID, order.CharacterID, null, price * quantityToBuy); } // create the transaction records for both characters this.WalletManager.CreateTransactionRecord(character.ID, TransactionType.Buy, order.CharacterID, typeID, quantityToBuy, price, stationID); this.WalletManager.CreateTransactionRecord(order.CharacterID, TransactionType.Sell, character.ID, typeID, quantityToBuy, price, stationID); long stationNode = this.SystemManager.GetNodeStationBelongsTo(stationID); // create the new item that will be used by the player ItemEntity item = this.ItemFactory.CreateSimpleItem( this.TypeManager[typeID], character.ID, stationID, Flags.Hangar, quantityToBuy ); // immediately unload it, if it has to be loaded the OnItemUpdate notification will take care of that this.ItemFactory.UnloadItem(item); if (stationNode == 0 || this.SystemManager.StationBelongsToUs(stationID) == true) { this.NotificationManager.NotifyCharacter(character.ID, Notifications.Client.Inventory.OnItemChange.BuildLocationChange(item, this.ItemFactory.LocationMarket.ID)); } else { this.NotificationManager.NotifyNode(stationNode, OnItemChange.BuildLocationChange(item.ID, this.ItemFactory.LocationMarket.ID, stationID)); } } // ensure we do not buy more than we need if (quantity == 0) { break; } } }
public PyDataType InjectSkillIntoBrain(PyList itemIDs, CallInformation call) { foreach (PyInteger item in itemIDs.GetEnumerable <PyInteger>()) { try { // get the item by it's ID and change the location of it Skill skill = this.ItemFactory.GetItem <Skill>(item); // check if the character already has this skill injected if (this.Character.InjectedSkillsByTypeID.ContainsKey(skill.Type.ID) == true) { throw new CharacterAlreadyKnowsSkill(skill.Type); } // is this a stack of skills? if (skill.Quantity > 1) { // add one of the skill into the character's brain Skill newStack = this.ItemFactory.CreateSkill(skill.Type, this.Character, 0, SkillHistoryReason.None); // subtract one from the quantity skill.Quantity -= 1; // save to database skill.Persist(); // finally notify the client call.Client.NotifyMultiEvent(OnItemChange.BuildQuantityChange(skill, skill.Quantity + 1)); call.Client.NotifyMultiEvent(OnItemChange.BuildNewItemChange(newStack)); } else { // store old values for the notification int oldLocationID = skill.LocationID; Flags oldFlag = skill.Flag; // now set the new values skill.LocationID = this.Character.ID; skill.Flag = Flags.Skill; skill.Level = 0; skill.Singleton = true; // ensure the character has the skill in his/her brain this.Character.AddItem(skill); // ensure the changes are saved skill.Persist(); // notify the character of the change in the item call.Client.NotifyMultiEvent(OnItemChange.BuildLocationChange(skill, oldFlag, oldLocationID)); call.Client.NotifyMultiEvent(OnItemChange.BuildSingletonChange(skill, false)); } } catch (CharacterAlreadyKnowsSkill) { throw; } catch (Exception) { Log.Error($"Cannot inject itemID {item} into {this.Character.ID}'s brain..."); throw; } } // send the skill injected notification to refresh windows if needed call.Client.NotifyMultiEvent(new OnSkillInjected()); return(null); }