/// <summary> /// Runs when a player dies, and hands out penalties if enabled, and rewards for PVP /// </summary> protected void ProcessDeath(int DeadPlayerSlot, bool PVPDeath) { TSPlayer murderer = null, murdered = null; IBankAccount murderedAccount, murdererAccount; Money penalty = default(Money); int lastHitterSlot = default(int); Journal.CachedTransaction worldToPlayerTx = null, playerToWorldTx = null; //get the last hitter ID out of the dictionary lock (__pvpDictMutex) { if (PVPDamage.ContainsKey(DeadPlayerSlot)) { lastHitterSlot = PVPDamage[DeadPlayerSlot]; PVPDamage.Remove(DeadPlayerSlot); } } if ((murdered = TShockAPI.TShock.Players.ElementAtOrDefault(DeadPlayerSlot)) == null || murdered.Group.HasPermission("seconomy.world.bypassdeathpenalty") == true || (murderedAccount = Parent.GetBankAccount(murdered)) == null || (penalty = GetDeathPenalty(murdered)) == 0) { return; } playerToWorldTx = new Journal.CachedTransaction() { DestinationBankAccountK = Parent.WorldAccount.BankAccountK, SourceBankAccountK = murderedAccount.BankAccountK, Message = "dying", Options = Journal.BankAccountTransferOptions.MoneyTakenOnDeath | Journal.BankAccountTransferOptions.AnnounceToSender, Amount = penalty }; //the dead player loses money unconditionally Parent.TransactionCache.AddCachedTransaction(playerToWorldTx); //but if it's a PVP death, the killer gets the losers penalty if enabled if (PVPDeath && WorldConfiguration.MoneyFromPVPEnabled && WorldConfiguration.KillerTakesDeathPenalty) { if ((murderer = TShockAPI.TShock.Players.ElementAtOrDefault(lastHitterSlot)) == null || (murdererAccount = Parent.GetBankAccount(murderer)) == null) { return; } worldToPlayerTx = new Journal.CachedTransaction() { SourceBankAccountK = Parent.WorldAccount.BankAccountK, DestinationBankAccountK = murdererAccount.BankAccountK, Amount = penalty, Message = "killing " + murdered.Name, Options = Journal.BankAccountTransferOptions.AnnounceToReceiver, }; Parent.TransactionCache.AddCachedTransaction(worldToPlayerTx); } }
/// <summary> /// Processes all elements in the queue and transfers them /// </summary> protected async Task ProcessQueueAsync() { List <CachedTransaction> aggregatedFunds = new List <CachedTransaction>(); CachedTransaction fund; while (CachedTransactions.TryDequeue(out fund)) { //The idea of this is that the concurrent queue will aggregate everything with the same message. //So instead of spamming eye of ctaltlatlatututlutultu (shut up) it'll just agg them into one //and print something like "You gained 60 silver from 20 eyes" instead of spamming both the chat log //and the journal with bullshit CachedTransaction existingFund = aggregatedFunds.FirstOrDefault(i => i.Message == fund.Message && i.SourceBankAccountK == fund.SourceBankAccountK && i.DestinationBankAccountK == fund.DestinationBankAccountK); if (existingFund != null) { existingFund.Amount += fund.Amount; //indicate that this is an aggregate of a previous uncommitted fund existingFund.Aggregations++; } else { aggregatedFunds.Add(fund); } } foreach (CachedTransaction aggregatedFund in aggregatedFunds) { Journal.IBankAccount sourceAccount = SEconomyPlugin.Instance.RunningJournal.GetBankAccount(aggregatedFund.SourceBankAccountK); Journal.IBankAccount destAccount = SEconomyPlugin.Instance.RunningJournal.GetBankAccount(aggregatedFund.DestinationBankAccountK); if (sourceAccount != null && destAccount != null) { StringBuilder messageBuilder = new StringBuilder(aggregatedFund.Message); if (aggregatedFund.Aggregations > 1) { messageBuilder.Insert(0, aggregatedFund.Aggregations + " "); messageBuilder.Append("s"); } //transfer the money BankTransferEventArgs transfer = await sourceAccount.TransferToAsync(destAccount, aggregatedFund.Amount, aggregatedFund.Options, messageBuilder.ToString(), messageBuilder.ToString()); if (!transfer.TransferSucceeded) { if (transfer.Exception != null) { TShock.Log.ConsoleError(string.Format("seconomy cache: error source={0} dest={1}: {2}", aggregatedFund.SourceBankAccountK, aggregatedFund.DestinationBankAccountK, transfer.Exception)); } } } else { TShock.Log.ConsoleError(string.Format("seconomy cache: transaction cache has no source or destination. source key={0} dest key={1}", aggregatedFund.SourceBankAccountK, aggregatedFund.DestinationBankAccountK)); } } }
/// <summary> /// Adds a fund to the uncommitted cache /// </summary> public void AddCachedTransaction(CachedTransaction Fund) { CachedTransactions.Enqueue(Fund); }
/// <summary> /// Should occur when an NPC dies; gives rewards out to all the players that hit it. /// </summary> protected void GiveRewardsForNPC(OTAPI.Terraria.NPC NPC) { List <PlayerDamage> playerDamageList = null; IBankAccount account; TSPlayer player; Money rewardMoney = 0L; lock (__dictionaryMutex) { if (DamageDictionary.ContainsKey(NPC)) { playerDamageList = DamageDictionary[NPC]; if (DamageDictionary.Remove(NPC) == false) { TShock.Log.ConsoleError("[SEconomy World] Removal of NPC after reward failed. This is an internal error."); } } } if (playerDamageList == null) { return; } if (((NPC.boss && WorldConfiguration.MoneyFromBossEnabled) || (!NPC.boss && WorldConfiguration.MoneyFromNPCEnabled)) && !(NPC.SpawnedFromStatue && WorldConfiguration.IgnoreSpawnedFromStatue)) { foreach (PlayerDamage damage in playerDamageList) { if (damage.Player == null || (player = TShockAPI.TShock.Players.FirstOrDefault(i => i != null && i.Index == damage.Player.whoAmI)) == null || (account = Parent.GetBankAccount(player)) == null) { continue; } rewardMoney = CustomMultiplier * Convert.ToInt64(Math.Round(Convert.ToDouble(WorldConfiguration.MoneyPerDamagePoint) * damage.Damage)); //load override by NPC type, this allows you to put a modifier on the base for a specific mob type. Configuration.WorldConfiguration.NPCRewardOverride overrideReward = WorldConfiguration.Overrides.FirstOrDefault(i => i.NPCID == NPC.type); if (overrideReward != null) { rewardMoney = CustomMultiplier * Convert.ToInt64(Math.Round(Convert.ToDouble(overrideReward.OverridenMoneyPerDamagePoint) * damage.Damage)); } if (rewardMoney <= 0 || player.Group.HasPermission("seconomy.world.mobgains") == false) { continue; } Journal.CachedTransaction fund = new Journal.CachedTransaction() { Aggregations = 1, Amount = rewardMoney, DestinationBankAccountK = account.BankAccountK, Message = NPC.FullName, SourceBankAccountK = Parent.WorldAccount.BankAccountK }; if ((NPC.boss && WorldConfiguration.AnnounceBossKillGains) || (!NPC.boss && WorldConfiguration.AnnounceNPCKillGains)) { fund.Options |= Journal.BankAccountTransferOptions.AnnounceToReceiver; } //commit it to the transaction cache Parent.TransactionCache.AddCachedTransaction(fund); } } }
/// <summary> /// Should occur when an NPC dies; gives rewards out to all the players that hit it. /// </summary> protected void GiveRewardsForNPC(Terraria.NPC NPC) { List<PlayerDamage> playerDamageList = null; IBankAccount account; TSPlayer player; Money rewardMoney = 0L; lock (__dictionaryMutex) { if (DamageDictionary.ContainsKey(NPC)) { playerDamageList = DamageDictionary[NPC]; if (DamageDictionary.Remove(NPC) == false) { TShock.Log.ConsoleError("seconomy: world economy: Remove of NPC after reward failed. This is an internal error."); } } } if (playerDamageList == null) { return; } if ((NPC.boss && WorldConfiguration.MoneyFromBossEnabled) || (!NPC.boss && WorldConfiguration.MoneyFromNPCEnabled)) { foreach (PlayerDamage damage in playerDamageList) { if (damage.Player == null || (player = TShockAPI.TShock.Players.FirstOrDefault(i => i != null && i.Index == damage.Player.whoAmI)) == null || (account = Parent.GetBankAccount(player)) == null) { continue; } rewardMoney = CustomMultiplier * Convert.ToInt64(Math.Round(Convert.ToDouble(WorldConfiguration.MoneyPerDamagePoint) * damage.Damage)); //load override by NPC type, this allows you to put a modifier on the base for a specific mob type. Configuration.WorldConfiguration.NPCRewardOverride overrideReward = WorldConfiguration.Overrides.FirstOrDefault(i => i.NPCID == NPC.type); if (overrideReward != null) { rewardMoney = CustomMultiplier * Convert.ToInt64(Math.Round(Convert.ToDouble(overrideReward.OverridenMoneyPerDamagePoint) * damage.Damage)); } if (rewardMoney <= 0 || player.Group.HasPermission("seconomy.world.mobgains") == false) { continue; } Journal.CachedTransaction fund = new Journal.CachedTransaction() { Aggregations = 1, Amount = rewardMoney, DestinationBankAccountK = account.BankAccountK, Message = NPC.name, SourceBankAccountK = Parent.WorldAccount.BankAccountK }; if ((NPC.boss && WorldConfiguration.AnnounceBossKillGains) || (!NPC.boss && WorldConfiguration.AnnounceNPCKillGains)) { fund.Options |= Journal.BankAccountTransferOptions.AnnounceToReceiver; } //commit it to the transaction cache Parent.TransactionCache.AddCachedTransaction(fund); } } }