/// <summary> /// Attempts to create a definition ID from a definition string, which has the form (using ores as an example) "MyObjectBuilder_Ore/Iron". /// The first part must represent an existing type, while the second (the subtype) is not enforced. /// </summary> /// <param name="id"></param> /// <param name="definitionId"></param> /// <returns></returns> public static bool TryParse(string id, out MyDefinitionId definitionId) { if (string.IsNullOrEmpty(id)) { definitionId = new MyDefinitionId(); return(false); } var slashIndex = id.IndexOf('/'); if (slashIndex == -1) { definitionId = new MyDefinitionId(); return(false); } var typeId = id.Substring(0, slashIndex).Trim(); MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(typeId, out result)) { var subtypeId = id.Substring(slashIndex + 1).Trim(); if (subtypeId == "(null)") { subtypeId = null; } definitionId = new MyDefinitionId(result, subtypeId); return(true); } definitionId = new MyDefinitionId(); return(false); }
public void AddResearchGroup(ResearchGroup group) { MyObjectBuilderType typeId; if (!MyObjectBuilderType.TryParse(group.ComponentId.TypeId, out typeId)) { return; } var compDef = new MyDefinitionId(typeId, group.ComponentId.SubtypeId); ResearchGroup existing; if (!group.OverwriteAllOthers && ResearchGroups.TryGetValue(compDef, out existing)) { foreach (var item in group.BlockDefinitons) { if (!existing.BlockDefinitons.Contains(item)) { existing.BlockDefinitons.Add(item); } } } else { ResearchGroups[compDef] = group; ResearchGroupList.Add(group); } }
private void SetItemAtSerialized(int i, string serializedItem, MyObjectBuilder_ToolbarItem data) { if (!m_items.IsValidIndex(i)) { return; } //old saves if (data == null) { if (String.IsNullOrEmpty(serializedItem)) { return; } var split = serializedItem.Split(':'); MyObjectBuilderType typeId; if (!MyObjectBuilderType.TryParse(split[0], out typeId)) { return; } string subtypeString = (split.Length == 2) ? split[1] : null; var defId = new MyDefinitionId(typeId, subtypeString); SetItemAtSerializedCompat(i, defId); } //new saves else { SetItemAtIndexInternal(i, MyToolbarItemFactory.CreateToolbarItem(data), true); } }
internal void LoadData() { if (Entity.Storage == null) { // DebugLog.Write("storage is null, exiting loadData()."); return; } string Data; if (Entity.Storage.TryGetValue(FilterStateGUID, out Data)) { // DebugLog.Write(Data); Filterdata loadedfilterdata = new Filterdata(); var base64 = Convert.FromBase64String(Data); loadedfilterdata = MyAPIGateway.Utilities.SerializeFromBinary <Filterdata>(base64); // DebugLog.Write($"loaded id: {loadedfilterdata.id}"); if (loadedfilterdata.id == MyCargoContainer.EntityId) { // DebugLog.Write($"Saved state found (id: {loadedfilterdata.id})"); MyInventory inventory = (MyInventory)MyCargoContainer.GetInventory(); if (loadedfilterdata.FilterItems != null) { for (int i = 0; i < loadedfilterdata.FilterItems.Count(); i++) { // DebugLog.Write($"{loadedfilterdata.FilterItems[i].DisplayName}"); FilterController.FilterList.Add(loadedfilterdata.FilterItems[i]); if (loadedfilterdata.FilterItems[i].Type == FilterType.FILTER_TYPE) { MyObjectBuilderType type; if (MyObjectBuilderType.TryParse(loadedfilterdata.FilterItems[i].ParseItem, out type) == true) { inventory.Constraint.AddObjectBuilderType(type); } } else if (loadedfilterdata.FilterItems[i].Type == FilterType.FILTER_ITEM) { MyDefinitionId Id; if (MyDefinitionId.TryParse(loadedfilterdata.FilterItems[i].ParseItem, out Id) == true) { inventory.Constraint.Add(Id); } } } } inventory.Constraint.IsWhitelist = loadedfilterdata.FilterMode; FilterController.FilterMode = loadedfilterdata.FilterMode; inventory.Constraint.Icon = null; } else { // DebugLog.Write($"Id mismatch - Entity Id: {Entity.EntityId} MyCargoContainerId: {MyCargoContainer.EntityId}"); } } }
static ToughNightsMod() { if (MyObjectBuilderType.TryParse("Block", out var blockType)) { lightEntityDefinitionIds.Add(new MyDefinitionId(blockType, "TorchWall")); lightEntityDefinitionIds.Add(new MyDefinitionId(blockType, "TorchStand")); lightEntityDefinitionIds.Add(new MyDefinitionId(blockType, "Brazier")); lightEntityDefinitionIds.Add(new MyDefinitionId(blockType, "Bonfire")); lightEntityDefinitionIds.Add(new MyDefinitionId(blockType, "BedWood")); } }
public MyPlanetEnvironmentMapping(PlanetEnvironmentItemMapping map) { Rule = map.Rule; Items = new MyMaterialEnvironmentItem[map.Items.Length]; if (Items.Length <= 0) { CumulativeIntervals = null; TotalFrequency = 0; return; } TotalFrequency = 0; for (int i = 0; i < map.Items.Length; i++) { var item = map.Items[i]; MyObjectBuilderType type; if (item.TypeId != null && MyObjectBuilderType.TryParse(item.TypeId, out type)) { if (!typeof(MyObjectBuilder_BotDefinition).IsAssignableFrom((Type)type) && !typeof(MyObjectBuilder_VoxelMapStorageDefinition).IsAssignableFrom((Type)type) && !typeof(MyObjectBuilder_EnvironmentItems).IsAssignableFrom((Type)type)) { MyLog.Default.WriteLine(String.Format("Object builder type {0} is not supported for environment items.", item.TypeId)); Items[i].Frequency = 0; // This should disable this item } else { Items[i] = new MyMaterialEnvironmentItem() { Definition = new MyDefinitionId(type, item.SubtypeId), Frequency = map.Items[i].Density, IsDetail = map.Items[i].IsDetail, IsBot = typeof(MyObjectBuilder_BotDefinition).IsAssignableFrom((Type)type), IsVoxel = typeof(MyObjectBuilder_VoxelMapStorageDefinition).IsAssignableFrom((Type)type), IsEnvironemntItem = typeof(MyObjectBuilder_EnvironmentItems).IsAssignableFrom((Type)type), BaseColor = map.Items[i].BaseColor, ColorSpread = map.Items[i].ColorSpread, MaxRoll = (float)Math.Cos(MathHelper.ToDegrees(map.Items[i].MaxRoll)), Offset = map.Items[i].Offset, GroupId = map.Items[i].GroupId, GroupIndex = map.Items[i].GroupIndex, ModifierId = map.Items[i].ModifierId, ModifierIndex = map.Items[i].ModifierIndex }; } } else { MyLog.Default.WriteLine(String.Format("Object builder type {0} does not exist.", item.TypeId)); Items[i].Frequency = 0; // This should disable this item } } ComputeDistribution(); }
public Wave(MyObjectBuilder_BarbarianWaveEventDefinition.WaveDef waveOb) { foreach (var botDef in waveOb.Bots) { MyObjectBuilderType botType; if (!MyObjectBuilderType.TryParse(botDef.TypeName, out botType)) { botType = typeof(MyObjectBuilder_HumanoidBot); } Bots.Add(new MyDefinitionId(botType, botDef.SubtypeName)); } }
public Wave(MyObjectBuilder_BarbarianWaveEventDefinition.WaveDef waveOb) { foreach (MyObjectBuilder_BarbarianWaveEventDefinition.BotDef def in waveOb.Bots) { MyObjectBuilderType type; if (!MyObjectBuilderType.TryParse(def.TypeName, out type)) { type = typeof(MyObjectBuilder_HumanoidBot); } this.Bots.Add(new MyDefinitionId(type, def.SubtypeName)); } }
public static MyPhysicalItemDefinition GetDefinition(this MyDefinitionManager definitionManager, string typeId, string subtypeName) { MyPhysicalItemDefinition definition = null; MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(typeId, out result)) { var id = new MyDefinitionId(result, subtypeName); MyDefinitionManager.Static.TryGetPhysicalItemDefinition(id, out definition); } return(definition); }
public MyPlanetEnvironmentMapping(PlanetEnvironmentItemMapping map) { this.Rule = map.Rule; this.Items = new MyMaterialEnvironmentItem[map.Items.Length]; if (this.Items.Length == 0) { this.CumulativeIntervals = null; this.TotalFrequency = 0f; } else { this.TotalFrequency = 0f; for (int i = 0; i < map.Items.Length; i++) { MyObjectBuilderType type; MyPlanetEnvironmentItemDef def = map.Items[i]; if ((def.TypeId == null) || !MyObjectBuilderType.TryParse(def.TypeId, out type)) { MyLog.Default.WriteLine($"Object builder type {def.TypeId} does not exist."); this.Items[i].Frequency = 0f; } else if ((!typeof(MyObjectBuilder_BotDefinition).IsAssignableFrom((Type)type) && !typeof(MyObjectBuilder_VoxelMapStorageDefinition).IsAssignableFrom((Type)type)) && !typeof(MyObjectBuilder_EnvironmentItems).IsAssignableFrom((Type)type)) { MyLog.Default.WriteLine($"Object builder type {def.TypeId} is not supported for environment items."); this.Items[i].Frequency = 0f; } else { MyMaterialEnvironmentItem item1 = new MyMaterialEnvironmentItem(); item1.Definition = new MyDefinitionId(type, def.SubtypeId); item1.Frequency = map.Items[i].Density; item1.IsDetail = map.Items[i].IsDetail; item1.IsBot = typeof(MyObjectBuilder_BotDefinition).IsAssignableFrom((Type)type); item1.IsVoxel = typeof(MyObjectBuilder_VoxelMapStorageDefinition).IsAssignableFrom((Type)type); item1.IsEnvironemntItem = typeof(MyObjectBuilder_EnvironmentItems).IsAssignableFrom((Type)type); item1.BaseColor = map.Items[i].BaseColor; item1.ColorSpread = map.Items[i].ColorSpread; item1.MaxRoll = (float)Math.Cos((double)MathHelper.ToDegrees(map.Items[i].MaxRoll)); item1.Offset = map.Items[i].Offset; item1.GroupId = map.Items[i].GroupId; item1.GroupIndex = map.Items[i].GroupIndex; item1.ModifierId = map.Items[i].ModifierId; item1.ModifierIndex = map.Items[i].ModifierIndex; this.Items[i] = item1; } } this.ComputeDistribution(); } }
private void ItemSpawned(string itemtypename, string itemsubtypename, long itemid, int amount, Vector3D position) { MyObjectBuilderType type; if (!MyObjectBuilderType.TryParse(itemtypename, out type)) { return; } var id = new MyDefinitionId(type, itemsubtypename); if (!_generatedAmmos.Contains(id)) { return; } var ent = MyAPIGateway.Entities.GetEntityById(itemid); ent?.Close(); }
internal void AddToFilter(Filterdata filterdata) { if (filterdata.FilterItems.Length == 0) { // DebugLog.Write("AddToFilter called with 0 items to add. ignoring..."); return; } var inventory = (MyInventory)MyCargoContainer.GetInventory(); for (int i = 0; i < filterdata.FilterItems.Length; i++) { if (filterdata.FilterItems[i].Type == FilterType.FILTER_TYPE) { MyObjectBuilderType type; if (MyObjectBuilderType.TryParse(filterdata.FilterItems[i].ParseItem, out type) == true) { if (!inventory.Constraint.ConstrainedTypes.Contains(type)) { inventory.Constraint.AddObjectBuilderType(type); } } } if (filterdata.FilterItems[i].Type == FilterType.FILTER_ITEM) { MyDefinitionId Id; if (MyDefinitionId.TryParse(filterdata.FilterItems[i].ParseItem, out Id) == true) { if (!inventory.Constraint.ConstrainedIds.Contains(Id)) { inventory.Constraint.Add(Id); } } } if (!FilterController.FilterList.Contains(filterdata.FilterItems[i])) { FilterController.FilterList.Add(filterdata.FilterItems[i]); } } inventory.Constraint.Icon = null; SaveData(); }
public static MyDefinitionBase GetDefinition(this MyDefinitionManager definitionManager, string typeId, string subtypeName) { MyObjectBuilderType result; if (!MyObjectBuilderType.TryParse(typeId, out result)) { return(null); } var id = new MyDefinitionId(result, subtypeName); try { return(MyDefinitionManager.Static.GetDefinition(id)); } catch { // If a item as been removed, like a mod, // or the mod has broken and failed to load, this will return null. return(null); } }
public override void ProcessServer() { if (!EconomyScript.Instance.ServerConfig.EnableNpcTradezones && !EconomyScript.Instance.ServerConfig.EnablePlayerTradezones) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "All Trade zones are disabled."); return; } switch (SellAction) { #region create case SellAction.Create: { EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create started by Steam Id '{0}'.", SenderSteamId); //* Logic: //* Get player steam ID var sellingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); MyDefinitionBase definition = null; MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(ItemTypeId, out result)) { var id = new MyDefinitionId(result, ItemSubTypeName); MyDefinitionManager.Static.TryGetDefinition(id, out definition); } if (definition == null) { // Someone hacking, and passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item you specified doesn't exist!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Definition could not be found for item during '/sell'; '{0}' '{1}'.", ItemTypeId, ItemSubTypeName); return; } // Do a floating point check on the item item. Tools and components cannot have decimals. They must be whole numbers. if (definition.Id.TypeId != typeof(MyObjectBuilder_Ore) && definition.Id.TypeId != typeof(MyObjectBuilder_Ingot)) { if (ItemQuantity != Math.Truncate(ItemQuantity)) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You must provide a whole number for the quantity of that item."); return; } //ItemQuantity = Math.Round(ItemQuantity, 0); // Or do we just round the number? } if (ItemQuantity <= 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Invalid quantity, or you dont have any to trade!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- Invalid quantity.", SenderSteamId); return; } // Who are we selling to? BankAccountStruct accountToBuy; if (SellToMerchant) { accountToBuy = AccountManager.FindAccount(EconomyConsts.NpcMerchantId); } else { accountToBuy = AccountManager.FindAccount(ToUserName); } if (accountToBuy == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, player does not exist or have an account!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- account not found.", SenderSteamId); return; } if (MarketManager.IsItemBlacklistedOnServer(ItemTypeId, ItemSubTypeName)) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item you tried to sell is blacklisted on this server."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- Item is blacklisted.", SenderSteamId); return; } // Verify that the items are in the player inventory. // TODO: later check trade block, cockpit inventory, cockpit ship inventory, inventory of targeted cube. // Get the player's inventory, regardless of if they are in a ship, or a remote control cube. var character = sellingPlayer.GetCharacter(); // TODO: do players in Cryochambers count as a valid trading partner? They should be alive, but the connected player may be offline. // I think we'll have to do lower level checks to see if a physical player is Online. if (character == null) { // Player has no body. Could mean they are dead. // Either way, there is no inventory. MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You are dead. You cannot trade while dead."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- player is dead.", SenderSteamId); return; } // TODO: is a null check adaqaute?, or do we need to check for IsDead? // I don't think the chat console is accessible during respawn, only immediately after death. // Is it valid to be able to trade when freshly dead? //var identity = payingPlayer.Identity(); //MyAPIGateway.Utilities.ShowMessage("CHECK", "Is Dead: {0}", identity.IsDead); //if (identity.IsDead) //{ // MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You are dead. You cannot trade while dead."); // return; //} EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell finalizing by Steam Id '{0}' -- cataloging cargo cubes.", SenderSteamId); // Build list of all cargo blocks that player is attached to as pilot or passenger. var cargoBlocks = new List <MyCubeBlock>(); var tankBlocks = new List <MyCubeBlock>(); var controllingCube = sellingPlayer.Controller.ControlledEntity as IMyCubeBlock; if (controllingCube != null) { var terminalsys = MyAPIGateway.TerminalActionsHelper.GetTerminalSystemForGrid(controllingCube.CubeGrid); var blocks = new List <IMyTerminalBlock>(); terminalsys.GetBlocksOfType <IMyCargoContainer>(blocks); cargoBlocks.AddRange(blocks.Cast <MyCubeBlock>()); terminalsys.GetBlocksOfType <IMyGasTank>(blocks); tankBlocks.AddRange(blocks.Cast <MyCubeBlock>()); } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell finalizing by Steam Id '{0}' -- checking inventory.", SenderSteamId); var position = ((IMyEntity)character).WorldMatrix.Translation; var playerInventory = character.GetPlayerInventory(); MyFixedPoint amount = (MyFixedPoint)ItemQuantity; var storedAmount = playerInventory.GetItemAmount(definition.Id); if (definition.Id.TypeId == typeof(MyObjectBuilder_GasProperties)) { foreach (MyCubeBlock cubeBlock in tankBlocks) { MyGasTankDefinition gasTankDefintion = cubeBlock.BlockDefinition as MyGasTankDefinition; if (gasTankDefintion == null || gasTankDefintion.StoredGasId != definition.Id) { continue; } var tankLevel = ((IMyGasTank)cubeBlock).FilledRatio; storedAmount += (MyFixedPoint)((decimal)tankLevel * (decimal)gasTankDefintion.Capacity); } } else { foreach (MyCubeBlock cubeBlock in cargoBlocks) { var cubeInventory = cubeBlock.GetInventory(); storedAmount += cubeInventory.GetItemAmount(definition.Id); } } if (amount > storedAmount) { // Insufficient items in inventory. // TODO: use of definition.GetDisplayName() isn't localized here. if ((definition.Id.TypeId != typeof(MyObjectBuilder_GasProperties) && cargoBlocks.Count == 0) && (definition.Id.TypeId == typeof(MyObjectBuilder_GasProperties) && tankBlocks.Count == 0)) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You don't have {0} of '{1}' to sell. You have {2} in your inventory.", ItemQuantity, definition.GetDisplayName(), storedAmount); } else { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You don't have {0} of '{1}' to sell. You have {2} in your player and cargo inventory.", ItemQuantity, definition.GetDisplayName(), storedAmount); } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- inventory doesn't exist.", SenderSteamId); return; } MarketItemStruct marketItem = null; if (SellToMerchant || UseBankBuyPrice) { var markets = MarketManager.FindMarketsFromLocation(position); if (markets.Count == 0) //once again here is were we could put the multi market best price logic.. { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, your are not in range of any markets!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- no market in range.", SenderSteamId); return; } // TODO: find market with best Buy price that isn't blacklisted. var market = markets.FirstOrDefault(); if (market == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the market you are accessing does not exist!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- no market found.", SenderSteamId); return; } accountToBuy = AccountManager.FindAccount(market.MarketId); marketItem = market.MarketItems.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); if (marketItem == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the items you are trying to sell doesn't have a market entry!"); // In reality, this shouldn't happen as all markets have their items synced up on start up of the mod. return; } if (marketItem.IsBlacklisted) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item you tried to sell is blacklisted in this market."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- item is blacklisted.", SenderSteamId); return; } if (UseBankBuyPrice) { // The player is selling, but the *Market* will *buy* it from the player at this price. // if we are not using price scaling OR the market we are trading with isn't owned by the NPC ID, dont change price. Otherwise scale. if (!EconomyScript.Instance.ServerConfig.PriceScaling || accountToBuy.SteamId != EconomyConsts.NpcMerchantId) { ItemPrice = marketItem.BuyPrice; } else { ItemPrice = EconDataManager.PriceAdjust(marketItem.BuyPrice, marketItem.Quantity, PricingBias.Buy); } } // if we are using price scaling adjust the price before our NPC trade (or check player for subsidy pricing) } var accountToSell = AccountManager.FindOrCreateAccount(SenderSteamId, SenderDisplayName, SenderLanguage); // need fix negative amounts before checking if the player can afford it. if (!sellingPlayer.IsAdmin()) { ItemPrice = Math.Abs(ItemPrice); } var transactionAmount = ItemPrice * ItemQuantity; if (!sellingPlayer.IsAdmin()) { transactionAmount = Math.Abs(transactionAmount); } if (SellToMerchant) // && (merchant has enough money || !EconomyScript.Instance.ServerConfig.LimitedSupply) //this is also a quick fix ideally npc should buy what it can afford and the rest is posted as a sell offer { if (accountToBuy.SteamId != accountToSell.SteamId) { decimal limit = EconomyScript.Instance.ServerConfig.LimitedSupply ? marketItem.StockLimit - marketItem.Quantity : ItemQuantity; if (limit == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, you cannot sell any more {0} into this market.", definition.GetDisplayName()); return; } if (ItemQuantity > limit) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, you cannot sell any more than {0} of {1} into this market.", limit, definition.GetDisplayName()); return; } } if (accountToBuy.BankBalance >= transactionAmount // || !EconomyScript.Instance.ServerConfig.LimitedSupply // I'm not sure why we check limited supply when selling. || accountToBuy.SteamId == accountToSell.SteamId) { // here we look up item price and transfer items and money as appropriate EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell finalizing by Steam Id '{0}' -- removing inventory.", SenderSteamId); RemoveInventory(playerInventory, cargoBlocks, tankBlocks, amount, definition.Id); marketItem.Quantity += ItemQuantity; // increment Market content. if (accountToBuy.SteamId != accountToSell.SteamId) { accountToBuy.BankBalance -= transactionAmount; accountToBuy.Date = DateTime.Now; accountToSell.BankBalance += transactionAmount; accountToSell.Date = DateTime.Now; MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just sold {0} {3} worth of {2} ({1} units)", transactionAmount, ItemQuantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); MessageUpdateClient.SendAccountMessage(accountToBuy); MessageUpdateClient.SendAccountMessage(accountToSell); } else { accountToSell.Date = DateTime.Now; MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "You just arranged transfer of {0} '{1}' into your market.", ItemQuantity, definition.GetDisplayName()); } } else { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "NPC can't afford {0} {4} worth of {2} ({1} units) NPC only has {3} funds!", transactionAmount, ItemQuantity, definition.GetDisplayName(), accountToBuy.BankBalance, EconomyScript.Instance.ServerConfig.CurrencyName); } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create completed by Steam Id '{0}' -- to NPC market.", SenderSteamId); return; } if (OfferToMarket) { // TODO: Here we post offer to appropriate zone market MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Offset to market at price is not yet available!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- Offer to market at price is not yet available.", SenderSteamId); return; } // is it a player then? if (accountToBuy.SteamId == sellingPlayer.SteamUserId) { // commented out for testing with myself. MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, you cannot sell to yourself!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- can't sell to self.", SenderSteamId); return; } // check if buying player is online and in range? var buyingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(accountToBuy.SteamId); if (EconomyScript.Instance.ServerConfig.LimitedRange && !Support.RangeCheck(buyingPlayer, sellingPlayer)) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, you are not in range of that player!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- target player not in range.", SenderSteamId); return; } // if other player online, send message. if (buyingPlayer == null) { // TODO: other player offline. MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You cannot sell to offline players at this time."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create aborted by Steam Id '{0}' -- cannot sell to offline player.", SenderSteamId); return; // TODO: we need a way to queue up messages. // While you were gone.... // You missed an offer for 4000Kg of Gold for 20,000. } else { // The other player is online. // write to Trade offer table. MarketManager.CreateTradeOffer(SenderSteamId, ItemTypeId, ItemSubTypeName, ItemQuantity, ItemPrice, accountToBuy.SteamId); // remove items from inventory. EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell finalizing by Steam Id '{0}' -- removing inventory.", SenderSteamId); RemoveInventory(playerInventory, cargoBlocks, tankBlocks, amount, definition.Id); // Only send message to targeted player if this is the only offer pending for them. // Otherwise it will be sent when the have with previous orders in their order Queue. if (EconomyScript.Instance.Data.OrderBook.Count(e => (e.OptionalId == accountToBuy.SteamId.ToString() && e.TradeState == TradeState.SellDirectPlayer)) == 1) { MessageClientTextMessage.SendMessage(accountToBuy.SteamId, "SELL", "You have received an offer from {0} to buy {1} {2} at price {3} {4} each - type '/sell accept' to accept offer (or '/sell deny' to reject and return item to seller)", SenderDisplayName, ItemQuantity, definition.GetDisplayName(), ItemPrice, EconomyScript.Instance.ServerConfig.CurrencyName); } // TODO: Improve the message here, to say who were are trading to, and that the item is gone from inventory. // send message to seller to confirm action, "Your Trade offer has been submitted, and the goods removed from you inventory." MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Your offer of {0} {1} for {2} {4} each has been sent to {3}.", ItemQuantity, definition.GetDisplayName(), ItemPrice, accountToBuy.NickName, EconomyScript.Instance.ServerConfig.CurrencyName); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Create completed by Steam Id '{0}' -- to another player.", SenderSteamId); return; } } #endregion #region accept case SellAction.Accept: { EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Accept started by Steam Id '{0}'.", SenderSteamId); var order = EconomyScript.Instance.Data.OrderBook.FirstOrDefault(e => e.OptionalId == SenderSteamId.ToString() && e.TradeState == TradeState.SellDirectPlayer); if (order == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "There are no outstanding orders to be accepted."); return; } var payingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); // get the accounts and check finance. var accountToBuy = AccountManager.FindAccount(ulong.Parse(order.OptionalId)); var transactionAmount = order.Price * order.Quantity; // need fix negative amounts before checking if the player can afford it. if (!payingPlayer.IsAdmin()) { transactionAmount = Math.Abs(transactionAmount); } if (accountToBuy.BankBalance < transactionAmount) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You cannot afford {0} {1} at this time.", transactionAmount, EconomyScript.Instance.ServerConfig.CurrencyName); return; } var accountToSell = AccountManager.FindAccount(order.TraderId); // rebalance accounts. accountToBuy.BankBalance -= transactionAmount; accountToBuy.Date = DateTime.Now; accountToSell.BankBalance += transactionAmount; accountToSell.Date = DateTime.Now; MessageUpdateClient.SendAccountMessage(accountToBuy); MessageUpdateClient.SendAccountMessage(accountToSell); order.TradeState = TradeState.SellAccepted; var definition = MyDefinitionManager.Static.GetDefinition(order.TypeId, order.SubtypeName); if (definition == null) { // Someone hacking, and passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item in your order doesn't exist!"); // trade has been finalized, so we can exit safely. EconomyScript.Instance.ServerLogger.WriteVerbose("Definition could not be found for item during '/sell accept'; '{0}' '{1}'.", order.TypeId, order.SubtypeName); return; } // TODO: Improve the messages. // message back "Your Trade offer of xxx to yyy has been accepted. You have recieved zzzz" MessageClientTextMessage.SendMessage(accountToSell.SteamId, "SELL", "You just sold {0} {3} worth of {2} ({1} units)", transactionAmount, order.Quantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); var collectingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); var playerInventory = collectingPlayer.GetPlayerInventory(); bool hasAddedToInventory = true; if (playerInventory != null) { MyFixedPoint amount = (MyFixedPoint)order.Quantity; hasAddedToInventory = Support.InventoryAdd(playerInventory, amount, definition.Id); } if (hasAddedToInventory) { EconomyScript.Instance.Data.OrderBook.Remove(order); // item has been collected, so the order is finalized. MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just purchased {0} {3} worth of {2} ({1} units) which are now in your player inventory.", transactionAmount, order.Quantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); } else { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just purchased {0} {3} worth of {2} ({1} units). Enter '/collect' when you are ready to receive them.", transactionAmount, order.Quantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); } // Send message to player if additional offers are pending their attention. DisplayNextOrderToAccept(SenderSteamId); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Accept completed by Steam Id '{0}'.", SenderSteamId); return; } #endregion #region collect case SellAction.Collect: { EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Collect or /collect started by Steam Id '{0}'.", SenderSteamId); var collectableOrders = EconomyScript.Instance.Data.OrderBook.Where(e => (e.TraderId == SenderSteamId && e.TradeState == TradeState.SellTimedout) || (e.TraderId == SenderSteamId && e.TradeState == TradeState.Holding) || (e.TraderId == SenderSteamId && e.TradeState == TradeState.SellRejected) || (e.OptionalId == SenderSteamId.ToString() && e.TradeState == TradeState.SellAccepted)).ToArray(); if (collectableOrders.Length == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "There is nothing to collect currently."); return; } var collectingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); // TODO: this is just for debugging until the message below are completed.... //MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You are collecting items from {0} order/s.", collectableOrders.Length); foreach (var order in collectableOrders) { MyDefinitionBase definition = null; MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(order.TypeId, out result)) { var id = new MyDefinitionId(result, order.SubtypeName); MyDefinitionManager.Static.TryGetDefinition(id, out definition); } if (definition == null) { // Someone hacking, and passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item in your order doesn't exist!"); // TODO: more detail on the item. EconomyScript.Instance.ServerLogger.WriteVerbose("Definition could not be found for item during '/sell collect or /collect'; '{0}' '{1}'.", order.TypeId, order.SubtypeName); continue; } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell finalizing by Steam Id '{0}' -- adding to inventories.", SenderSteamId); var remainingToCollect = MessageSell.AddToInventories(collectingPlayer, order.Quantity, definition.Id); var collected = order.Quantity - remainingToCollect; if (remainingToCollect == 0) { EconomyScript.Instance.Data.OrderBook.Remove(order); MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just collected {0} worth of {2} ({1} units)", order.Price * collected, collected, definition.GetDisplayName()); } else { order.Quantity = remainingToCollect; MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just collected {0} worth of {2} ({1} units). There are {3} remaining.", order.Price * collected, collected, definition.GetDisplayName(), remainingToCollect); } } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Collect completed by Steam Id '{0}'.", SenderSteamId); return; } #endregion #region cancel case SellAction.Cancel: { EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Cancel started by Steam Id '{0}'.", SenderSteamId); var cancellableOrders = EconomyScript.Instance.Data.OrderBook.Where(e => (e.TraderId == SenderSteamId && e.TradeState == TradeState.SellDirectPlayer)).OrderByDescending(e => e.Created).ToArray(); if (cancellableOrders.Length == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "There is nothing to cancel currently."); } // Sellers should be presented with the newest order first, as they will be the most recently created. // use of OrderByDescending above assures us that [0] is the most recent order added. var order = cancellableOrders[0]; order.TradeState = TradeState.SellRejected; var definition = MyDefinitionManager.Static.GetDefinition(order.TypeId, order.SubtypeName); if (definition == null) { // Someone hacking, and passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item in your order doesn't exist!"); // trade has been finalized, so we can exit safely. EconomyScript.Instance.ServerLogger.WriteVerbose("Definition could not be found for item during '/sell cancel'; '{0}' '{1}'.", order.TypeId, order.SubtypeName); return; } var transactionAmount = order.Price * order.Quantity; var collectingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); var inventory = collectingPlayer.GetPlayerInventory(); bool hasAddedToInventory = true; if (inventory != null) { MyFixedPoint amount = (MyFixedPoint)order.Quantity; hasAddedToInventory = Support.InventoryAdd(inventory, amount, definition.Id); } if (hasAddedToInventory) { EconomyScript.Instance.Data.OrderBook.Remove(order); // item has been collected, so the order is finalized. MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just cancelled the sale of {2} ({1} units) for a total of {0} {3} which are now in your inventory.", transactionAmount, order.Quantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); } else { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "You just cancelled the sale of {2} ({1} units) for a total of {0} {3}. Enter '/sell collect' when you are ready to receive them.", transactionAmount, order.Quantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); } cancellableOrders = EconomyScript.Instance.Data.OrderBook.Where(e => (e.TraderId == SenderSteamId && e.TradeState == TradeState.SellDirectPlayer)).OrderByDescending(e => e.Created).ToArray(); if (cancellableOrders.Length > 0) { // TODO: Inform the player of the next order in the queue that can be cancelled. } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Cancel completed by Steam Id '{0}'.", SenderSteamId); return; } #endregion #region deny case SellAction.Deny: { EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Deny started by Steam Id '{0}'.", SenderSteamId); var buyOrdersForMe = EconomyScript.Instance.Data.OrderBook.Where(e => (e.OptionalId == SenderSteamId.ToString() && e.TradeState == TradeState.SellDirectPlayer)).OrderBy(e => e.Created).ToArray(); if (buyOrdersForMe.Length == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "There is nothing to deny currently."); } // Buyers should be presented with the oldest order first, as they will timout first. // use of OrderBy above assures us that [0] is the most oldest order added. var order = buyOrdersForMe[0]; order.TradeState = TradeState.SellRejected; var definition = MyDefinitionManager.Static.GetDefinition(order.TypeId, order.SubtypeName); if (definition == null) { // Someone hacking, and passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Sorry, the item in your order doesn't exist!"); // trade has been finalized, so we can exit safely. EconomyScript.Instance.ServerLogger.WriteVerbose("Definition could not be found for item during '/sell deny'; '{0}' '{1}'.", order.TypeId, order.SubtypeName); return; } var transactionAmount = order.Price * order.Quantity; var buyerId = ulong.Parse(order.OptionalId); MessageClientTextMessage.SendMessage(buyerId, "SELL", "You just rejected the purchase of {2} ({1} units) for a total of {0} {3}.", transactionAmount, order.Quantity, definition.GetDisplayName(), EconomyScript.Instance.ServerConfig.CurrencyName); // TODO: return items to inventory automatically to Trader inventory if there is space. MessageClientTextMessage.SendMessage(order.TraderId, "SELL", "{3} has just rejected your offer of {2} ({1} units) for a total of {0} {4}. Enter '/sell collect' when you are ready to receive them.", transactionAmount, order.Quantity, definition.GetDisplayName(), SenderDisplayName, EconomyScript.Instance.ServerConfig.CurrencyName); // Send message to player if additional offers are pending their attention. DisplayNextOrderToAccept(SenderSteamId); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Sell Deny completed by Steam Id '{0}'.", SenderSteamId); return; } #endregion } // this is a fall through from the above conditions not yet complete. MessageClientTextMessage.SendMessage(SenderSteamId, "SELL", "Not yet complete."); }
public override void ProcessServer() { var player = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); // Only Admin can change Npc Market prices. if (!player.IsAdmin() && MarketId == EconomyConsts.NpcMerchantId) { EconomyScript.Instance.ServerLogger.WriteWarning("A Player without Admin \"{0}\" {1} attempted to set Default Market characteristics of item {2}/{3} to Quantity={4}.", SenderDisplayName, SenderSteamId, ItemTypeId, ItemSubTypeName, ItemQuantity); return; } // Only Player can change their own Market prices. if (SenderSteamId != MarketId && MarketId != EconomyConsts.NpcMerchantId) { EconomyScript.Instance.ServerLogger.WriteWarning("A Player \"{0}\" {1} attempted to set another Market characteristics of item {2}/{3} to Quantity={4}.", SenderDisplayName, SenderSteamId, ItemTypeId, ItemSubTypeName, ItemQuantity); return; } // TODO: do we check range to market? MyDefinitionBase definition = null; MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(ItemTypeId, out result)) { var id = new MyDefinitionId(result, ItemSubTypeName); MyDefinitionManager.Static.TryGetDefinition(id, out definition); } if (definition == null) { // Passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Sorry, the item you specified doesn't exist!"); return; } if (SetType.HasFlag(SetMarketItemType.Quantity)) { // Do a floating point check on the item item. Tools and components cannot have decimals. They must be whole numbers. if (definition.Id.TypeId != typeof(MyObjectBuilder_Ore) && definition.Id.TypeId != typeof(MyObjectBuilder_Ingot)) { if (ItemQuantity != Math.Truncate(ItemQuantity)) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "You must provide a whole number for the quantity of that item."); return; } //ItemQuantity = Math.Round(ItemQuantity, 0); // Or do we just round the number? } if (ItemQuantity <= 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Invalid quantity specified"); return; } } // Find the specified market. List <MarketStruct> markets; if (string.IsNullOrEmpty(MarketZone)) { var character = player.GetCharacter(); if (character == null) { // Player has no body. Could mean they are dead. MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "There is no market at your location to set."); return; } var position = ((IMyEntity)character).WorldMatrix.Translation; markets = MarketManager.FindMarketsFromLocation(position).Where(m => m.MarketId == MarketId).ToList(); } else { markets = EconomyScript.Instance.Data.Markets.Where(m => m.MarketId == MarketId && (MarketZone == "*" || m.DisplayName.Equals(MarketZone, StringComparison.InvariantCultureIgnoreCase))).ToList(); } if (markets.Count == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Sorry, you are not near any markets currently or the market does not exist!"); return; } var msg = new StringBuilder(); msg.AppendFormat("Applying changes to : '{0}' {1}/{2}\r\n\r\n", definition.GetDisplayName(), ItemTypeId, ItemSubTypeName); foreach (var market in markets) { msg.AppendFormat("Market: '{0}'\r\n", market.DisplayName); var marketItem = market.MarketItems.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); if (marketItem == null) { msg.AppendLine("Sorry, the items you are trying to set doesn't have a market entry!"); // In reality, this shouldn't happen as all markets have their items synced up on start up of the mod. continue; } if (SetType.HasFlag(SetMarketItemType.Quantity)) { marketItem.Quantity = ItemQuantity; msg.AppendFormat("Stock on hand to {0} units", ItemQuantity); } // Validation to prevent admins setting prices too low for items. if (SetType.HasFlag(SetMarketItemType.BuyPrice)) { if (ItemBuyPrice >= 0) { marketItem.BuyPrice = ItemBuyPrice; msg.AppendFormat("Buy price to {0}", ItemBuyPrice); } else { msg.AppendFormat("Could not set buy price to less than 0."); } } // Validation to prevent admins setting prices too low for items. if (SetType.HasFlag(SetMarketItemType.SellPrice)) { if (ItemSellPrice >= 0) { marketItem.SellPrice = ItemSellPrice; msg.AppendFormat("Sell price to {0}", ItemSellPrice); } else { msg.AppendFormat("Could not set sell price to less than 0."); } } if (SetType.HasFlag(SetMarketItemType.Blacklisted)) { marketItem.IsBlacklisted = !marketItem.IsBlacklisted; msg.AppendFormat("Blacklist to {0}", marketItem.IsBlacklisted ? "On" : "Off"); } msg.AppendLine(); msg.AppendLine(); } #region update config for the item MarketItemStruct configItem = null; if (player.IsAdmin() && MarketId == EconomyConsts.NpcMerchantId) { configItem = EconomyScript.Instance.ServerConfig.DefaultPrices.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); } if (configItem != null) { if (SetType.HasFlag(SetMarketItemType.BuyPrice)) { if (ItemBuyPrice >= 0) { configItem.BuyPrice = ItemBuyPrice; msg.AppendFormat("Config updated Buy price to {0}", ItemBuyPrice); } } // Validation to prevent admins setting prices too low for items. if (SetType.HasFlag(SetMarketItemType.SellPrice)) { if (ItemSellPrice >= 0) { configItem.SellPrice = ItemSellPrice; msg.AppendFormat("Config updated Sell price to {0}", ItemSellPrice); } } if (SetType.HasFlag(SetMarketItemType.Blacklisted)) { configItem.IsBlacklisted = !configItem.IsBlacklisted; msg.AppendFormat("Config updated Blacklist to {0}", configItem.IsBlacklisted ? "On" : "Off"); // If config blacklisted, then all markets should be updated. if (configItem.IsBlacklisted) { int counter = 0; foreach (var market in EconomyScript.Instance.Data.Markets) { var marketItem = market.MarketItems.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); if (marketItem != null && !marketItem.IsBlacklisted) { counter++; marketItem.IsBlacklisted = true; } } msg.AppendFormat("Config updated {0} Markets to also Blacklist to {1}.", counter, configItem.IsBlacklisted ? "On" : "Off"); } } } #endregion MessageClientDialogMessage.SendMessage(SenderSteamId, "SET", " ", msg.ToString()); }
public override void ProcessServer() { var player = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); // Only Admin can change Npc Market prices. if (!player.IsAdmin() && MarketId == EconomyConsts.NpcMerchantId) { EconomyScript.Instance.ServerLogger.WriteWarning("A Player without Admin \"{0}\" {1} attempted to set Default Market characteristics of item {2}/{3} to Quantity={4}.", SenderDisplayName, SenderSteamId, ItemTypeId, ItemSubTypeName, ItemQuantity); return; } // Only Player can change their own Market prices. if (SenderSteamId != MarketId && MarketId != EconomyConsts.NpcMerchantId) { EconomyScript.Instance.ServerLogger.WriteWarning("A Player \"{0}\" {1} attempted to set another Market characteristics of item {2}/{3} to Quantity={4}.", SenderDisplayName, SenderSteamId, ItemTypeId, ItemSubTypeName, ItemQuantity); return; } // TODO: do we check range to market? MyPhysicalItemDefinition definition = null; MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(ItemTypeId, out result)) { var id = new MyDefinitionId(result, ItemSubTypeName); MyDefinitionManager.Static.TryGetPhysicalItemDefinition(id, out definition); } if (definition == null) { // Passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Sorry, the item you specified doesn't exist!"); return; } if (SetType.HasFlag(SetMarketItemType.Quantity)) { // Do a floating point check on the item item. Tools and components cannot have decimals. They must be whole numbers. if (definition.Id.TypeId != typeof(MyObjectBuilder_Ore) && definition.Id.TypeId != typeof(MyObjectBuilder_Ingot)) { if (ItemQuantity != Math.Truncate(ItemQuantity)) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "You must provide a whole number for the quantity of that item."); return; } //ItemQuantity = Math.Round(ItemQuantity, 0); // Or do we just round the number? } if (ItemQuantity <= 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Invalid quantity spectified"); return; } } // Find the specified market. var market = EconomyScript.Instance.Data.Markets.FirstOrDefault(m => m.MarketId == MarketId); if (market == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Sorry, the market you are accessing does not exist!"); return; } var marketItem = market.MarketItems.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); if (marketItem == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "SET", "Sorry, the items you are trying to set doesn't have a market entry!"); // In reality, this shouldn't happen as all markets have their items synced up on start up of the mod. return; } MarketItemStruct configItem = null; if (player.IsAdmin() && MarketId == EconomyConsts.NpcMerchantId) { configItem = EconomyScript.Instance.Config.DefaultPrices.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); } var msg = new StringBuilder(); msg.AppendFormat("You just set '{0}'", definition.GetDisplayName()); if (SetType.HasFlag(SetMarketItemType.Quantity)) { marketItem.Quantity = ItemQuantity; msg.AppendFormat(", stock on hand to {0} units", ItemQuantity); } // Validation to prevent admins setting prices too low for items. if (SetType.HasFlag(SetMarketItemType.BuyPrice)) { if (ItemBuyPrice >= 0) { marketItem.BuyPrice = ItemBuyPrice; msg.AppendFormat(", buy price to {0}", ItemBuyPrice); if (configItem != null) { configItem.BuyPrice = ItemBuyPrice; msg.AppendFormat("; config updated."); } } else { msg.AppendFormat(", could not set buy price to less than 0."); } } // Validation to prevent admins setting prices too low for items. if (SetType.HasFlag(SetMarketItemType.SellPrice)) { if (ItemSellPrice >= 0) { marketItem.SellPrice = ItemSellPrice; msg.AppendFormat(", sell price to {0}", ItemSellPrice); if (configItem != null) { configItem.SellPrice = ItemSellPrice; msg.AppendFormat("; config updated."); } } else { msg.AppendFormat(", could not set sell price to less than 0."); } } if (SetType.HasFlag(SetMarketItemType.Blacklisted)) { marketItem.IsBlacklisted = !marketItem.IsBlacklisted; msg.AppendFormat(", blacklist to {0}", marketItem.IsBlacklisted ? "On" : "Off"); if (configItem != null) { configItem.IsBlacklisted = marketItem.IsBlacklisted; msg.AppendFormat("; config updated."); } } MessageClientTextMessage.SendMessage(SenderSteamId, "SET", msg.ToString()); }
public override void ProcessServer() { // update our own timestamp here AccountManager.UpdateLastSeen(SenderSteamId, SenderLanguage); EconomyScript.Instance.ServerLogger.WriteVerbose("Price List Request for from '{0}'", SenderSteamId); var player = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); var character = player.GetCharacter(); if (character == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "You are dead. You get market items values while dead."); return; } List <MarketStruct> markets; if (string.IsNullOrEmpty(FindMarket)) { var position = ((IMyEntity)character).WorldMatrix.Translation; markets = MarketManager.FindMarketsFromLocation(position); } else { markets = MarketManager.FindMarketsFromName(FindMarket); } if (markets.Count == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "Sorry, your are not in range of any markets!"); return; } // TODO: combine multiple markets to list best Buy and Sell prices that isn't blacklisted. var market = markets.FirstOrDefault(); if (market == null) //hmmm looks like market name parameter checking was started but never done { MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "That market does not exist."); return; //as I understand it this would only trigger if no markets are defined? //in which case should it read no markets exist? but in that case // wont the count check above halt execution before this if statement??? // remove these comments once read :) } string reply = null; MyAPIGateway.Parallel.StartBackground(delegate() // Background processing occurs within this block. { try { bool showAll = !ShowOre && !ShowIngot && !ShowComponent && !ShowAmmo && !ShowTools && !ShowGasses; var orderedList = new Dictionary <MarketItemStruct, string>(); foreach (var marketItem in market.MarketItems) { if (marketItem.IsBlacklisted) { continue; } MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(marketItem.TypeId, out result)) { var id = new MyDefinitionId(result, marketItem.SubtypeName); var content = Support.ProducedType(id); // Cannot check the Type of the item, without having to use MyObjectBuilderSerializer.CreateNewObject(). if (showAll || (ShowOre && content is MyObjectBuilder_Ore) || (ShowIngot && content is MyObjectBuilder_Ingot) || (ShowComponent && content is MyObjectBuilder_Component) || (ShowAmmo && content is MyObjectBuilder_AmmoMagazine) || (ShowTools && content is MyObjectBuilder_PhysicalGunObject) || // guns, welders, hand drills, grinders. (ShowGasses && content is MyObjectBuilder_GasContainerObject) || // aka gas bottle. (ShowGasses && content is MyObjectBuilder_GasProperties)) // Type check here allows mods that inherit from the same type to also appear in the lists. { var definition = MyDefinitionManager.Static.GetDefinition(marketItem.TypeId, marketItem.SubtypeName); var name = definition == null ? marketItem.SubtypeName : definition.GetDisplayName(); orderedList.Add(marketItem, name); } } } orderedList = orderedList.OrderBy(kvp => kvp.Value).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var str = new SeTextBuilder(); str.AppendLine("Market: {0}\r\n", market.DisplayName); str.AddLeftTrim(550, "Item"); str.AddRightText(650, "Buy at"); str.AddRightText(850, "Sell at"); str.AppendLine(); foreach (var kvp in orderedList) { decimal showBuy = kvp.Key.BuyPrice; decimal showSell = kvp.Key.SellPrice; if ((EconomyScript.Instance.ServerConfig.PriceScaling) && (market.MarketId == EconomyConsts.NpcMerchantId)) { showBuy = EconDataManager.PriceAdjust(kvp.Key.BuyPrice, kvp.Key.Quantity, PricingBias.Buy); showSell = EconDataManager.PriceAdjust(kvp.Key.SellPrice, kvp.Key.Quantity, PricingBias.Sell); } // TODO: formatting of numbers, and currency name. str.AddLeftTrim(550, kvp.Value); str.AddRightText(650, showBuy.ToString("0.00", EconomyScript.ServerCulture)); str.AddRightText(850, showSell.ToString("0.00", EconomyScript.ServerCulture)); str.AppendLine(); } reply = str.ToString(); } catch (Exception ex) { EconomyScript.Instance.ServerLogger.WriteException(ex); MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "Failed and died. Please contact the administrator."); } }, delegate() // when the background processing is finished, this block will run foreground. { if (reply != null) { try { MessageClientDialogMessage.SendMessage(SenderSteamId, "PRICELIST", " ", reply); } catch (Exception ex) { EconomyScript.Instance.ServerLogger.WriteException(ex); MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "Failed and died. Please contact the administrator."); } } }); }
public override void ProcessServer() { // update our own timestamp here AccountManager.UpdateLastSeen(SenderSteamId, SenderLanguage); EconomyScript.Instance.ServerLogger.WriteVerbose("Price List Request for from '{0}'", SenderSteamId); var player = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); var character = player.GetCharacter(); if (character == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "You are dead. You get market items values while dead."); return; } var position = ((IMyEntity)character).WorldMatrix.Translation; var markets = MarketManager.FindMarketsFromLocation(position); if (markets.Count == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "Sorry, your are not in range of any markets!"); return; } // TODO: combine multiple markets to list best Buy and Sell prices that isn't blacklisted. var market = markets.FirstOrDefault(); if (market == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "That market does not exist."); return; } string reply = null; MyAPIGateway.Parallel.StartBackground(delegate() // Background processing occurs within this block. { try { bool showAll = !ShowOre && !ShowIngot && !ShowComponent && !ShowAmmo && !ShowTools; var orderedList = new Dictionary <MarketItemStruct, string>(); foreach (var marketItem in market.MarketItems) { if (marketItem.IsBlacklisted) { continue; } MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(marketItem.TypeId, out result)) { var id = new MyDefinitionId(result, marketItem.SubtypeName); var content = Support.ProducedType(id); // Cannot check the Type of the item, without having to use MyObjectBuilderSerializer.CreateNewObject(). if (showAll || (ShowOre && content is MyObjectBuilder_Ore) || (ShowIngot && content is MyObjectBuilder_Ingot) || (ShowComponent && content is MyObjectBuilder_Component) || (ShowAmmo && content is MyObjectBuilder_AmmoMagazine) || (ShowTools && content is MyObjectBuilder_PhysicalGunObject) || (ShowTools && content is MyObjectBuilder_GasContainerObject)) // Type check here allows mods that inherit from the same type to also appear in the lists. { var definition = MyDefinitionManager.Static.GetDefinition(marketItem.TypeId, marketItem.SubtypeName); var name = definition == null ? marketItem.SubtypeName : definition.GetDisplayName(); orderedList.Add(marketItem, name); } } } orderedList = orderedList.OrderBy(kvp => kvp.Value).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var str = new SeTextBuilder(); str.AppendLine("Market: {0}\r\n", market.DisplayName); str.AddLeftTrim(550, "Item"); str.AddRightText(650, "Buy at"); str.AddRightText(850, "Sell at"); str.AppendLine(); foreach (var kvp in orderedList) { // TODO: formatting of numbers, and currency name. str.AddLeftTrim(550, kvp.Value); str.AddRightText(650, kvp.Key.BuyPrice.ToString("0.00", EconomyScript.ServerCulture)); str.AddRightText(850, kvp.Key.SellPrice.ToString("0.00", EconomyScript.ServerCulture)); str.AppendLine(); } reply = str.ToString(); } catch (Exception ex) { EconomyScript.Instance.ServerLogger.WriteException(ex); MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "Failed and died. Please contact the administrator."); } }, delegate() // when the background processing is finished, this block will run foreground. { if (reply != null) { try { MessageClientDialogMessage.SendMessage(SenderSteamId, "PRICELIST", " ", reply); } catch (Exception ex) { EconomyScript.Instance.ServerLogger.WriteException(ex); MessageClientTextMessage.SendMessage(SenderSteamId, "PRICELIST", "Failed and died. Please contact the administrator."); } } }); }
public static void ProcessLcdBlock(IMyTextPanel textPanel) { //counter++; var writer = TextPanelWriter.Create(textPanel); // Use the update interval on the LCD Panel to determine how often the display is updated. // It can only go as fast as the timer calling this code is. float interval; try { interval = Math.Max((float)EconomyScript.Instance.ServerConfig.MinimumLcdDisplayInterval, textPanel.GetValueFloat("ChangeIntervalSlider")); } catch (Exception ex) { // The game may generate an exception from the GetValueFloat(GetValue) call. EconomyScript.Instance.ServerLogger.WriteException(ex, UpdateCrashMessage); EconomyScript.Instance.ClientLogger.WriteException(ex, UpdateCrashMessage); // We can't safely ignore this one if it doesn't work, because this can affect the display timing. return; } if (writer.LastUpdate > DateTime.Now.AddSeconds(-interval)) { return; } var checkArray = textPanel.GetPublicTitle().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var showAll = false; bool showOre = false; bool showIngot = false; bool showComponent = false; bool showAmmo = false; bool showTools = false; bool showGasses = false; bool showStock = false; bool showPrices = true; bool showTest1 = false; bool showTest2 = false; StartFrom startFrom = StartFrom.None; //if # is specified eg #20 then run the start line logic int startLine = 0; //this is where our start line placeholder sits int pageNo = 1; // removed Linq, to reduce the looping through the array. This should only have to do one loop through all items in the array. foreach (var str in checkArray) { if (str.Equals("stock", StringComparison.InvariantCultureIgnoreCase)) { showStock = true; } if (str.Contains("#")) { string[] lineNo = str.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries); if (lineNo.Length != 0 && int.TryParse(lineNo[0], out startLine)) { //this only runs if they put a number in startFrom = StartFrom.Line; } } if (str.StartsWith("P", StringComparison.InvariantCultureIgnoreCase)) { if (int.TryParse(str.Substring(1), out pageNo)) { startFrom = StartFrom.Page; } } if (str.Equals("*", StringComparison.InvariantCultureIgnoreCase)) { showAll = true; } if (!showAll) { if (str.Equals("test1", StringComparison.InvariantCultureIgnoreCase)) { showTest1 = true; } else if (str.Equals("test2", StringComparison.InvariantCultureIgnoreCase)) { showTest2 = true; } else if (str.StartsWith("ore", StringComparison.InvariantCultureIgnoreCase)) { showOre = true; } else if (str.StartsWith("ingot", StringComparison.InvariantCultureIgnoreCase)) { showIngot = true; } else if (str.StartsWith("component", StringComparison.InvariantCultureIgnoreCase)) { showComponent = true; } else if (str.StartsWith("ammo", StringComparison.InvariantCultureIgnoreCase)) { showAmmo = true; } else if (str.StartsWith("tool", StringComparison.InvariantCultureIgnoreCase)) { showTools = true; } else if (str.StartsWith("gas", StringComparison.InvariantCultureIgnoreCase)) { showGasses = true; } } } bool showHelp = !showAll && !showOre && !showIngot && !showComponent && !showAmmo && !showTools && !showGasses; showPrices = !showStock || writer.IsWide; if (showTest1) { Test1(writer); writer.UpdatePublic(); return; } if (showTest2) { Test2(writer); writer.UpdatePublic(); return; } if (showHelp) { writer.AddPublicLine("Please add a tag to the private or public title."); writer.AddPublicLine("ie., * ingot ore component ammo tools."); writer.UpdatePublic(); return; } var buyColumn = TextPanelWriter.LcdLineWidth - 180; var sellColumn = TextPanelWriter.LcdLineWidth - 0; var stockColumn = TextPanelWriter.LcdLineWidth - 0; if (showPrices && showStock) { buyColumn = TextPanelWriter.LcdLineWidth - 280; sellColumn = TextPanelWriter.LcdLineWidth - 180; stockColumn = TextPanelWriter.LcdLineWidth - 0; } // This might be a costly operation to run. var markets = MarketManager.FindMarketsFromLocation(textPanel.WorldMatrix.Translation); if (markets.Count == 0) { writer.AddPublicCenterLine(TextPanelWriter.LcdLineWidth / 2f, "« {0} »", EconomyScript.Instance.ServerConfig.TradeNetworkName); writer.AddPublicCenterLine(TextPanelWriter.LcdLineWidth / 2f, "« No market in range »"); } else { // TODO: not sure if we should display all markets, the cheapest market item, or the closet market. // LOGIC summary: it needs to show the cheapest in stock(in range) sell(to player) price, and the highest (in range) has funds buy(from player) price // but this logic depends on the buy/sell commands defaulting to the same buy/sell rules as above. // where buy /sell commands run out of funds or supply in a given market and need to pull from the next market //it will either have to stop at each price change and notify the player, and/or prompt to keep transacting at each new price, or blindly keep buying until the //order is filled, the market runs out of stock, or the money runs out. Blindly is probably not optimal unless we are using stockmarket logic (buy orders/offers) //so the prompt option is the safer var market = markets.FirstOrDefault(); // Build a list of the items, so we can get the name so we can the sort the items by name. var list = new Dictionary <MarketItemStruct, string>(); writer.AddPublicCenterLine(TextPanelWriter.LcdLineWidth / 2f, market.DisplayName); if (startFrom == StartFrom.Page) { // convert the page to lines required. if (pageNo < 1) { pageNo = 1; } startLine = ((writer.DisplayLines - 2) * (pageNo - 1)); startFrom = StartFrom.Line; } string fromLine = " (From item #" + startLine + ".)"; writer.AddPublicText("« Market List"); if (startLine >= 1) { writer.AddPublicText(fromLine); } else { startLine = 1; // needed for truncating end line. } if (showPrices && showStock) { writer.AddPublicRightText(buyColumn, "Buy"); writer.AddPublicRightText(sellColumn, "Sell"); writer.AddPublicRightLine(stockColumn, "Stock »"); } else if (showStock) { writer.AddPublicRightLine(stockColumn, "Stock »"); } else if (showPrices) { writer.AddPublicRightText(buyColumn, "Buy"); writer.AddPublicRightLine(sellColumn, "Sell »"); } foreach (var marketItem in market.MarketItems) { if (marketItem.IsBlacklisted) { continue; } MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(marketItem.TypeId, out result)) { var id = new MyDefinitionId(result, marketItem.SubtypeName); var content = Support.ProducedType(id); //if (((Type)id.TypeId).IsSubclassOf(typeof(MyObjectBuilder_GasContainerObject))) // TODO: Not valid call yet. // Cannot check the Type of the item, without having to use MyObjectBuilderSerializer.CreateNewObject(). if (showAll || (showOre && content is MyObjectBuilder_Ore) || (showIngot && content is MyObjectBuilder_Ingot) || (showComponent && content is MyObjectBuilder_Component) || (showAmmo && content is MyObjectBuilder_AmmoMagazine) || (showTools && content is MyObjectBuilder_PhysicalGunObject) || // guns, welders, hand drills, grinders. (showGasses && content is MyObjectBuilder_GasContainerObject) || // aka gas bottle. (showGasses && content is MyObjectBuilder_GasProperties)) // Type check here allows mods that inherit from the same type to also appear in the lists. { MyDefinitionBase definition; if (MyDefinitionManager.Static.TryGetDefinition(id, out definition)) { list.Add(marketItem, definition == null ? marketItem.TypeId + "/" + marketItem.SubtypeName : definition.GetDisplayName()); } } } } int line = 0; foreach (var kvp in list.OrderBy(k => k.Value)) { line++; if (startFrom == StartFrom.Line && line < startLine) //if we have a start line specified skip all lines up to that { continue; } if (startFrom == StartFrom.Line && line - startLine >= writer.WholeDisplayLines - 2) // counts 2 lines of headers. { break; // truncate the display and don't display the text on the bottom edge of the display. } writer.AddPublicLeftTrim(buyColumn - 120, kvp.Value); decimal showBuy = kvp.Key.BuyPrice; decimal showSell = kvp.Key.SellPrice; if ((EconomyScript.Instance.ServerConfig.PriceScaling) && (market.MarketId == EconomyConsts.NpcMerchantId)) { showBuy = EconDataManager.PriceAdjust(kvp.Key.BuyPrice, kvp.Key.Quantity, PricingBias.Buy); showSell = EconDataManager.PriceAdjust(kvp.Key.SellPrice, kvp.Key.Quantity, PricingBias.Sell); } if (showPrices && showStock) { writer.AddPublicRightText(buyColumn, showBuy.ToString("\t0.000", EconomyScript.ServerCulture)); writer.AddPublicRightText(sellColumn, showSell.ToString("\t0.000", EconomyScript.ServerCulture)); // TODO: components and tools should be displayed as whole numbers. Will be hard to align with other values. writer.AddPublicRightText(stockColumn, kvp.Key.Quantity.ToString("\t0.0000", EconomyScript.ServerCulture)); // TODO: recheck number of decimal places. } else if (showStock) //does this ever actually run? seems to already be in the above? { // TODO: components and tools should be displayed as whole numbers. Will be hard to align with other values. writer.AddPublicRightText(stockColumn, kvp.Key.Quantity.ToString("\t0.0000", EconomyScript.ServerCulture)); // TODO: recheck number of decimal places. } else if (showPrices) { writer.AddPublicRightText(buyColumn, showBuy.ToString("\t0.000", EconomyScript.ServerCulture)); writer.AddPublicRightText(sellColumn, showSell.ToString("\t0.000", EconomyScript.ServerCulture)); } writer.AddPublicLine(); } } writer.UpdatePublic(); }
public override void ProcessServer() { EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy started by Steam Id '{0}'.", SenderSteamId); // Get player steam ID var buyingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(SenderSteamId); MyPhysicalItemDefinition definition = null; MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(ItemTypeId, out result)) { var id = new MyDefinitionId(result, ItemSubTypeName); MyDefinitionManager.Static.TryGetPhysicalItemDefinition(id, out definition); } if (definition == null) { // Someone hacking, and passing bad data? MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, the item you specified doesn't exist!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- item doesn't exist.", SenderSteamId); return; } // Do a floating point check on the item item. Tools and components cannot have decimals. They must be whole numbers. if (definition.Id.TypeId != typeof(MyObjectBuilder_Ore) && definition.Id.TypeId != typeof(MyObjectBuilder_Ingot)) { if (ItemQuantity != Math.Truncate(ItemQuantity)) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "You must provide a whole number for the quantity to buy that item."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- invalid qantity.", SenderSteamId); return; } //ItemQuantity = Math.Round(ItemQuantity, 0); // Or do we just round the number? } if (ItemQuantity <= 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "You must provide a valid quantity to buy."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- invalid qantity.", SenderSteamId); return; } // Who are we buying to? BankAccountStruct accountToSell; if (BuyFromMerchant) { accountToSell = AccountManager.FindAccount(EconomyConsts.NpcMerchantId); } else { accountToSell = AccountManager.FindAccount(FromUserName); } if (accountToSell == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, player does not exist or have an account!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- no account.", SenderSteamId); return; } if (MarketManager.IsItemBlacklistedOnServer(ItemTypeId, ItemSubTypeName)) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, the item you tried to buy is blacklisted on this server."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- item blacklisted.", SenderSteamId); return; } // Get the player's inventory, regardless of if they are in a ship, or a remote control cube. var character = buyingPlayer.GetCharacter(); // TODO: do players in Cryochambers count as a valid trading partner? They should be alive, but the connected player may be offline. // I think we'll have to do lower level checks to see if a physical player is Online. if (character == null) { // Player has no body. Could mean they are dead. // Either way, there is no inventory. MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "You are dead. You cannot trade while dead."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- player is dead.", SenderSteamId); return; } // TODO: is a null check adaqaute?, or do we need to check for IsDead? // I don't think the chat console is accessible during respawn, only immediately after death. // Is it valid to be able to trade when freshly dead? //var identity = buyingPlayer.Identity(); //MyAPIGateway.Utilities.ShowMessage("CHECK", "Is Dead: {0}", identity.IsDead); //if (identity.IsDead) //{ // MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "You are dead. You cannot trade while dead."); // return; //} var position = ((IMyEntity)character).WorldMatrix.Translation; MarketItemStruct marketItem = null; if (BuyFromMerchant || UseBankSellPrice) { var markets = MarketManager.FindMarketsFromLocation(position); if (markets.Count == 0) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, your are not in range of any markets!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- no market in range.", SenderSteamId); return; } // TODO: find market with best Sell price that isn't blacklisted. var market = markets.FirstOrDefault(); if (market == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, the market you are accessing does not exist!"); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- no market found.", SenderSteamId); return; } marketItem = market.MarketItems.FirstOrDefault(e => e.TypeId == ItemTypeId && e.SubtypeName == ItemSubTypeName); if (marketItem == null) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, the items you are trying to buy doesn't have a market entry!"); // In reality, this shouldn't happen as all markets have their items synced up on start up of the mod. return; } if (marketItem.IsBlacklisted) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, the item you tried to buy is blacklisted in this market."); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- item is blacklisted in market.", SenderSteamId); return; } // Verify that the items are in the player inventory. // TODO: later check trade block, cockpit inventory, cockpit ship inventory, inventory of targeted cube. if (UseBankSellPrice) { // The player is buying, but the *Market* will *sell* it to the player at this price. ItemPrice = marketItem.SellPrice; } } var accountToBuy = AccountManager.FindOrCreateAccount(SenderSteamId, SenderDisplayName, SenderLanguage); var transactionAmount = ItemPrice * ItemQuantity; // need fix negative amounts before checking if the player can afford it. if (!buyingPlayer.IsAdmin()) { transactionAmount = Math.Abs(transactionAmount); } // TODO: admin check on ability to afford it? //[maybe later, our pay and reset commands let us steal money from npc anyway best to keep admin abuse features to minimum] //[we could put an admin check on blacklist however, allow admins to spawn even blacklisted gear] if (accountToBuy.BankBalance < transactionAmount) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, you cannot afford {0} {1}!", transactionAmount, EconomyScript.Instance.Config.CurrencyName); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- not enough money.", SenderSteamId); return; } if (BuyFromMerchant) // and supply is not exhausted, or unlimited mode is not on. //This is a quick fix, ideally it should do a partial buy of what is left and post a buy offer for remainder { // here we look up item price and transfer items and money as appropriate if (marketItem.Quantity >= ItemQuantity || !EconomyScript.Instance.Config.LimitedSupply) { marketItem.Quantity -= ItemQuantity; // reduce Market content. EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy finalizing by Steam Id '{0}' -- adding to inventory.", SenderSteamId); var remainingToCollect = MessageSell.AddToInventories(buyingPlayer, ItemQuantity, definition.Id); //EconomyScript.Instance.Config.LimitedSupply accountToSell.BankBalance += transactionAmount; accountToSell.Date = DateTime.Now; accountToBuy.BankBalance -= transactionAmount; accountToBuy.Date = DateTime.Now; MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "You just purchased {1} '{2}' for {0} {3}", transactionAmount, ItemQuantity, definition.GetDisplayName(), EconomyScript.Instance.Config.CurrencyName); if (remainingToCollect > 0) { MarketManager.CreateStockHeld(buyingPlayer.SteamUserId, ItemTypeId, ItemSubTypeName, remainingToCollect, ItemPrice); // TODO: there should be a common command to collect items. Not use /sell. MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "There are {0} remaining to collect. Use '/sell collect'", remainingToCollect); } EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy complete by Steam Id '{0}' -- items bought.", SenderSteamId); } else { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "There isn't '{0}' of {1} available to purchase! Only {2} available to buy!", ItemQuantity, definition.GetDisplayName(), marketItem.Quantity); EconomyScript.Instance.ServerLogger.WriteVerbose("Action /Buy aborted by Steam Id '{0}' -- not enough stock.", SenderSteamId); } return; } else if (FindOnMarket) { // TODO: Here we find the best offer on the zone market return; } else { // is it a player then? if (accountToSell.SteamId == buyingPlayer.SteamUserId) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, you cannot buy from yourself!"); return; } // check if selling player is online and in range? var payingPlayer = MyAPIGateway.Players.FindPlayerBySteamId(accountToSell.SteamId); if (EconomyScript.Instance.Config.LimitedRange && !Support.RangeCheck(buyingPlayer, payingPlayer)) { MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Sorry, you are not in range of that player!"); return; } if (payingPlayer == null) { // TODO: other player offline. } else { // TODO: other player is online. } } // this is a fall through from the above conditions not yet complete. MessageClientTextMessage.SendMessage(SenderSteamId, "BUY", "Not yet complete."); }
private static void ProcessLcdBlock(IMyTextPanel textPanel) { //counter++; var checkArray = (textPanel.GetPublicTitle() + " " + textPanel.GetPrivateTitle()).Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var showAll = false; bool showOre = false; bool showIngot = false; bool showComponent = false; bool showAmmo = false; bool showTools = false; bool showStock = false; bool showPrices = true; bool showTest1 = false; bool showTest2 = false; // removed Linq, to reduce the looping through the array. This should only have to do one loop through all items in the array. foreach (var str in checkArray) { if (str.Equals("stock", StringComparison.InvariantCultureIgnoreCase)) { showStock = true; } if (str.Equals("*", StringComparison.InvariantCultureIgnoreCase)) { showAll = true; } if (!showAll) { if (str.Equals("test1", StringComparison.InvariantCultureIgnoreCase)) { showTest1 = true; } if (str.Equals("test2", StringComparison.InvariantCultureIgnoreCase)) { showTest2 = true; } if (str.Equals("ore", StringComparison.InvariantCultureIgnoreCase)) { showOre = true; } if (str.Equals("ingot", StringComparison.InvariantCultureIgnoreCase)) { showIngot = true; } if (str.Equals("component", StringComparison.InvariantCultureIgnoreCase)) { showComponent = true; } if (str.Equals("ammo", StringComparison.InvariantCultureIgnoreCase)) { showAmmo = true; } if (str.Equals("tools", StringComparison.InvariantCultureIgnoreCase)) { showTools = true; } } } bool showHelp = !showAll && !showOre && !showIngot && !showComponent && !showAmmo && !showTools; var writer = TextPanelWriter.Create(textPanel); // Use the update interval on the LCD Panel to determine how often the display is updated. // It can only go as fast as the timer calling this code is. var interval = Math.Max(1f, textPanel.GetValueFloat("ChangeIntervalSlider")); if (writer.LastUpdate > DateTime.Now.AddSeconds(-interval)) { return; } showPrices = !showStock || writer.IsWide; if (showTest1) { Test1(writer); writer.UpdatePublic(); return; } if (showTest2) { Test2(writer); writer.UpdatePublic(); return; } if (showHelp) { writer.AddPublicLine("Please add a tag to the private or public title."); writer.AddPublicLine("ie., * ingot ore component ammo tools."); writer.UpdatePublic(); return; } var buyColumn = TextPanelWriter.LcdLineWidth - 180; var sellColumn = TextPanelWriter.LcdLineWidth - 0; var stockColumn = TextPanelWriter.LcdLineWidth - 0; if (showPrices && showStock) { buyColumn = TextPanelWriter.LcdLineWidth - 280; sellColumn = TextPanelWriter.LcdLineWidth - 180; stockColumn = TextPanelWriter.LcdLineWidth - 0; } // This might be a costly operation to run. var markets = MarketManager.FindMarketsFromLocation(textPanel.WorldMatrix.Translation); if (markets.Count == 0) { writer.AddPublicCenterLine(TextPanelWriter.LcdLineWidth / 2f, "« {0} »", EconomyScript.Instance.Config.TradeNetworkName); writer.AddPublicCenterLine(TextPanelWriter.LcdLineWidth / 2f, "« No market in range »"); } else { // TODO: not sure if we should display all markets, the cheapest market item, or the closet market. var market = markets.FirstOrDefault(); // Build a list of the items, so we can get the name so we can the sort the items by name. var list = new Dictionary <MarketItemStruct, string>(); writer.AddPublicCenterLine(TextPanelWriter.LcdLineWidth / 2f, market.DisplayName); writer.AddPublicText("« Market List"); if (showPrices && showStock) { writer.AddPublicRightText(buyColumn, "Buy"); writer.AddPublicRightText(sellColumn, "Sell"); writer.AddPublicRightLine(stockColumn, "Stock »"); } else if (showStock) { writer.AddPublicRightLine(stockColumn, "Stock »"); } else if (showPrices) { writer.AddPublicRightText(buyColumn, "Buy"); writer.AddPublicRightLine(sellColumn, "Sell »"); } foreach (var marketItem in market.MarketItems) { if (marketItem.IsBlacklisted) { continue; } MyObjectBuilderType result; if (MyObjectBuilderType.TryParse(marketItem.TypeId, out result)) { var id = new MyDefinitionId(result, marketItem.SubtypeName); var content = Support.ProducedType(id); // Cannot check the Type of the item, without having to use MyObjectBuilderSerializer.CreateNewObject(). if (showAll || (showOre && content is MyObjectBuilder_Ore) || (showIngot && content is MyObjectBuilder_Ingot) || (showComponent && content is MyObjectBuilder_Component) || (showAmmo && content is MyObjectBuilder_AmmoMagazine) || (showTools && content is MyObjectBuilder_PhysicalGunObject) || (showTools && content is MyObjectBuilder_GasContainerObject)) // Type check here allows mods that inherit from the same type to also appear in the lists. { MyPhysicalItemDefinition definition = null; if (MyDefinitionManager.Static.TryGetPhysicalItemDefinition(id, out definition)) { list.Add(marketItem, definition == null ? marketItem.TypeId + "/" + marketItem.SubtypeName : definition.GetDisplayName()); } } } } foreach (var kvp in list.OrderBy(k => k.Value)) { writer.AddPublicLeftTrim(buyColumn - 120, kvp.Value); if (showPrices && showStock) { writer.AddPublicRightText(buyColumn, kvp.Key.BuyPrice.ToString("0.00", EconomyScript.ServerCulture)); writer.AddPublicRightText(sellColumn, kvp.Key.SellPrice.ToString("0.00", EconomyScript.ServerCulture)); // TODO: components and tools should be displayed as whole numbers. Will be hard to align with other values. writer.AddPublicRightText(stockColumn, kvp.Key.Quantity.ToString("0.000000", EconomyScript.ServerCulture)); // TODO: recheck number of decimal places. } else if (showStock) { // TODO: components and tools should be displayed as whole numbers. Will be hard to align with other values. writer.AddPublicRightText(stockColumn, kvp.Key.Quantity.ToString("0.000000", EconomyScript.ServerCulture)); // TODO: recheck number of decimal places. } else if (showPrices) { writer.AddPublicRightText(buyColumn, kvp.Key.BuyPrice.ToString("0.00", EconomyScript.ServerCulture)); writer.AddPublicRightText(sellColumn, kvp.Key.SellPrice.ToString("0.00", EconomyScript.ServerCulture)); } writer.AddPublicLine(); } } writer.UpdatePublic(); }