Advertisement
Guest User

Untitled

a guest
Feb 15th, 2014
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 76.19 KB | None | 0 0
  1.  
  2. /*
  3. * DAWN OF LIGHT - The first free open source DAoC server emulator
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. *
  19. */
  20. /*
  21. * Created by VaNaTiC@gmx.net
  22. * for Thidranki Classic (http://www.thidrankiclassic.de)
  23. *
  24. * Some notes:
  25. * - ...
  26. *
  27. * Features:
  28. * - ...
  29. *
  30. * ChangeLog:
  31. * 2007-06-27, Sio:
  32. * - PvP-Zone -> Albion SI (RegionID: 51)
  33. * - Safe-Zone -> Mid SI Aegir (new SetupZone, RegionID: 151)
  34. * 2007-06-12, VaNaTiC:
  35. * - PvP-Zone -> Celestius (Stars ML10 Spot RegionID: 91)
  36. * - PvE-Zone -> Passage of Conflict (RegionID: 244)
  37. * - PvE-Zone -> Darkness Falls (RegionID: 249)
  38. * - added changes from PvPServerRules.IsSameRealm() Rev 676
  39. * 2007-06-08, VaNaTiC:
  40. * - added colorhandling on GameEntered
  41. * - added LevelUpSound to RegionChanged and GamEntered to update NPCs color
  42. * 2007-06-04, VaNaTiC:
  43. * - added changes from PvPServerRules.IsSameRealm() Rev 664
  44. * - added changes from AbstractServerRules.IsAllowedToAttack() Rev 664
  45. * 2007-06-02, VaNaTiC:
  46. * - added check for xrealm+disband in event PlayerRegionChanged
  47. * - IsAllowedToCastSpell(): added complete handling PvE, PvP, RvR and SafeZones
  48. * - IsAllowedToUnderstand(): added complete handling PvE, PvP, RvR and SafeZones
  49. * - IsAllowedToTrade(): added complete handling PvE, PvP, RvR and SafeZones
  50. * - IsAllowedToGroup(): added complete handling PvE, PvP, RvR and SafeZones
  51. * - IsSameRealm(): added complete handling PvE, PvP, RvR and SafeZones
  52. * - IsAllowedToAttack(): added complete handling PvE, PvP, RvR and SafeZones
  53. * - added handling PvE-Zones
  54. * 2007-06-01, VaNaTiC:
  55. * - added preparing for PvE-zones
  56. * 2007-05-31, VaNaTiC:
  57. * - renamed ThidrankiClassicServerRules -> TCServerRules
  58. * - added PvE (safe-zone), PvP(pvp-zone) name-coloring and name-handling
  59. * - added m_pvpRegions and related code
  60. * - changed m_safeRegions from int[] to ushort[] and edited related m_safeRegions-Code
  61. * 2007-05-29, VaNaTiC:
  62. * - added PvE name/lastname/guild-handling in safe-zones
  63. * - added experimental PvE color-handling in safe-zones
  64. * 2007-05-22, VaNaTiC:
  65. * - allowed trading for all realms in safe-zones (setup-zone)
  66. * - allowed broadcast for all realms in safe-zones (setup-zone)
  67. * 2007-05-14, Lordy:
  68. * - added configuration Values: CLAIM_STATUS, CLAIM_BONUS, CLAIM_Logging
  69. * - added GuildClaimBonus(int RP, int BP, GamePlayer pl) method Line
  70. * - added in onplayerkilled() line 572 GuildClaimBonus() call
  71. * 2007-04-24, VaNaTiC:
  72. * - OnPlayerKilled(): fixed some things in LOGGING-Section
  73. * 2007-04-19, VaNaTiC:
  74. * - OnPlayerKilled(): fixed bug in handling XPGainers
  75. * - OnPlayerKilled(): added Logging
  76. * - OnPlayerKilled(): recalc for values with percent-based rate
  77. * - OnPlayerKilled(): counting of Friends/Enemies based upon XPGainers
  78. * - OnPlayerKilled(): consts for better configurability
  79. * - OnPlayerKilled(): dont count GMs to Friends/Enemies anymore
  80. * 2007-04-18, VaNaTiC:
  81. * - overridden IsAllowedToConnect() for vip-access
  82. * - added vip-access based upon account.Mail
  83. * - overridden IsAllowedToAttack() for safezones
  84. * - added safezones based upon PvP-RuleSet, as it was implemented in our old AbstractServerRules.cs
  85. * 2007-04-17, VaNaTiC:
  86. * - added in my OnPlayerKilled() handling for both grps
  87. * - handled in my OnPlayerKilled() mali for zergers :D
  88. * - added copy of NormalServerRules.OnPlayerKilled()
  89. * - created ( copy&paste&edit of NormalServerRules :-D )
  90. */
  91. using System;
  92. using System.Net;
  93. using System.Text;
  94. using System.Reflection;
  95. using System.Collections;
  96.  
  97.  
  98.  
  99. using DOL.Database;
  100. using DOL.AI.Brain;
  101. using DOL.Events;
  102. using DOL.Language;
  103. using DOL.GS;
  104. using DOL.GS.Keeps;
  105. using DOL.GS.Scripts;
  106. using DOL.GS.ServerRules;
  107. using DOL.GS.PacketHandler;
  108. using DOL.GS.ServerProperties;
  109.  
  110. using log4net;
  111. using System.Collections.Generic;
  112.  
  113. namespace DOL.GS.ServerRules
  114. {
  115. /// <summary>
  116. /// Set of rules for ThidrankiClassic "RvR" server type.
  117. /// </summary>
  118. [ServerRules(eGameServerType.GST_Test)]
  119. public class TCServerRules : NormalServerRules
  120. {
  121. #region configuration flags
  122. /// <summary>
  123. /// if it is 0.75 it means that only 75% of the whole RP-worth is recalculated
  124. /// </summary>
  125. public readonly double CALC_RATE = 0.75;
  126. /// <summary>
  127. /// if ENEMIES (Killer and Friends) > FRIENDS (Dead Player and Friends)
  128. /// and this property is true then the ENEMIES get a penalty
  129. /// </summary>
  130. public readonly bool CALC_PENALTY = true;
  131. /// <summary>
  132. /// if ENEMIES (Killer and Friends) < FRIENDS (Dead Player and Friends)
  133. /// and this property is true then the ENEMIES get a bonus
  134. /// </summary>
  135. public readonly bool CALC_BONUS = false;
  136. /// <summary>
  137. /// Enable/Disable Logging in GameServer-Logs as [INFO]
  138. /// </summary>
  139. public readonly bool LOGGING = false;
  140. /// <summary>
  141. /// If set true, the Player get a RP/BP bonus if The Guild Claim the Keep/Tower.
  142. /// </summary>
  143. public readonly bool CLAIM_STATUS = true;
  144. /// <summary>
  145. /// The % Value the player will get RPs/BPs to the Normal Amount.
  146. /// </summary>
  147. public readonly double CLAIM_BONUS = 0.10;
  148. /// <summary>
  149. /// ClaimBonus Logging
  150. /// Enable/Disable Logging in GameServer-Logs as [INFO]
  151. /// </summary>
  152. public readonly bool CLAIM_LOGGING = false;
  153.  
  154. #endregion
  155.  
  156. /// <summary>
  157. /// Defines a logger for this class.
  158. /// </summary>
  159. private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  160.  
  161. public override string RulesDescription()
  162. {
  163. return "ThidrankiClassic RvR Server Rules Fair-Play-System";
  164. }
  165.  
  166. #region configuration here your safe/pvp-regions for setup/event-zone
  167.  
  168. /// <summary>
  169. /// our declared safe-zones (based upon PvP-RuleSet)
  170. /// </summary>
  171. protected static int[] m_safeRegions =
  172. {
  173. 335, //Setup
  174. };
  175.  
  176. /// <summary>
  177. /// our declared pvp-zones (based upon PvP-RuleSet)
  178. /// </summary>
  179. protected static int[] m_pvpRegions =
  180. {
  181.  
  182.  
  183. };
  184.  
  185. /// <summary>
  186. /// our declared pve-zones (based upon PvE-RuleSet)
  187. /// </summary>
  188. protected static int[] m_pveRegions =
  189. {
  190.  
  191.  
  192. 91,
  193. };
  194.  
  195. #endregion
  196.  
  197. #region functions and handling for safe/pvp-regions
  198.  
  199. /// <summary>
  200. /// returns true if the given region is a safe-zone
  201. /// </summary>
  202. /// <param name="regionId"></param>
  203. /// <returns></returns>
  204. public static bool IsSafeZone(int regionId)
  205. {
  206. if (m_safeRegions != null && m_safeRegions.Length > 0)
  207. foreach (int reg in m_safeRegions)
  208. if (reg == regionId)
  209. return true;
  210. return false;
  211. }
  212.  
  213. /// <summary>
  214. /// returns true if the given region is a pvp-zone
  215. /// </summary>
  216. /// <param name="regionId"></param>
  217. /// <returns></returns>
  218. public static bool IsPvPZone(int regionId)
  219. {
  220. if (m_pvpRegions != null && m_pvpRegions.Length > 0)
  221. foreach (int reg in m_pvpRegions)
  222. if (reg == regionId)
  223. return true;
  224. return false;
  225. }
  226.  
  227. /// <summary>
  228. /// returns true if the given region is a pve-zone
  229. /// </summary>
  230. /// <param name="regionId"></param>
  231. /// <returns></returns>
  232. public static bool IsPvEZone(int regionId)
  233. {
  234. if (m_pveRegions != null && m_pveRegions.Length > 0)
  235. foreach (int reg in m_pveRegions)
  236. if (reg == regionId)
  237. return true;
  238. return false;
  239. }
  240.  
  241. #endregion
  242.  
  243. #region IsAllowedToAttack() merge of PvE, PvP, SafeZone and NormalRvR
  244.  
  245. /// <summary>
  246. /// AbstractServerRules: Is attacker allowed to attack defender.
  247. /// </summary>
  248. /// <param name="attacker">living that makes attack</param>
  249. /// <param name="defender">attacker's target</param>
  250. /// <param name="quiet">should messages be sent</param>
  251. /// <returns>true if attack is allowed</returns>
  252. protected virtual bool Abstract_IsAllowedToAttack(GameLiving attacker, GameLiving defender, bool quiet)
  253. {
  254. if (attacker == null || defender == null)
  255. return false;
  256.  
  257. //dead things can't attack
  258. if (!defender.IsAlive || !attacker.IsAlive)
  259. return false;
  260.  
  261. GamePlayer playerAttacker = attacker as GamePlayer;
  262. GamePlayer playerDefender = defender as GamePlayer;
  263.  
  264. if (playerDefender != null && playerDefender.Client.ClientState == GameClient.eClientState.WorldEnter)
  265. {
  266. if (!quiet)
  267. MessageToLiving(attacker, defender.Name + " is entering the game and is temporarily immune to PvP attacks!");
  268. return false;
  269. }
  270.  
  271. if (playerAttacker != null && playerDefender != null)
  272. {
  273. // Attacker immunity
  274. if (playerAttacker.IsInvulnerableToAttack)
  275. {
  276. if (quiet == false) MessageToLiving(attacker, "You can't attack players until your PvP invulnerability timer wears off!");
  277. return false;
  278. }
  279.  
  280. // Defender immunity
  281. if (playerDefender.IsInvulnerableToAttack)
  282. {
  283. if (quiet == false) MessageToLiving(attacker, defender.Name + " is temporarily immune to PvP attacks!");
  284. return false;
  285. }
  286. }
  287.  
  288. // PEACE NPCs can't be attacked/attack
  289. if (attacker is GameNPC)
  290. if ((((GameNPC)attacker).Flags & GameNPC.eFlags.PEACE) != 0)
  291. return false;
  292.  
  293. if (defender is GameNPC)
  294. if ((((GameNPC)defender).Flags & GameNPC.eFlags.PEACE) != 0)
  295. return false;
  296.  
  297. //GMs can't be attacked
  298. if (playerDefender != null && playerDefender.Client.Account.PrivLevel > 1)
  299. return false;
  300.  
  301. //safe area support for defender
  302. foreach (AbstractArea area in defender.CurrentAreas)
  303. {
  304. if (!area.IsSafeArea)
  305. continue;
  306.  
  307. if (quiet == false) MessageToLiving(attacker, "You can't attack someone in a safe area!");
  308. return false;
  309. }
  310.  
  311. //safe area support for attacker
  312. foreach (AbstractArea area in attacker.CurrentAreas)
  313. {
  314. if (area.IsSafeArea)
  315. {
  316. if (quiet == false) MessageToLiving(attacker, "You can't attack someone in a safe area!");
  317. return false;
  318. }
  319. }
  320.  
  321. //I don't want mobs attacking guards
  322. if (defender is GameKeepGuard && attacker is GameNPC && attacker.Realm == 0)
  323. return false;
  324.  
  325. return true;
  326. }
  327.  
  328. /// <summary>
  329. /// PvEServerRules: Is attacker allowed to attack defender.
  330. /// </summary>
  331. /// <param name="attacker">living that makes attack</param>
  332. /// <param name="defender">attacker's target</param>
  333. /// <param name="quiet">should messages be sent</param>
  334. /// <returns>true if attack is allowed</returns>
  335. protected virtual bool PvE_IsAllowedToAttack(GameLiving attacker, GameLiving defender, bool quiet)
  336. {
  337. if (!Abstract_IsAllowedToAttack(attacker, defender, quiet))
  338. return false;
  339.  
  340. // if controlled NPC - do checks for owner instead
  341. if (attacker is GameNPC)
  342. {
  343. IControlledBrain controlled = ((GameNPC)attacker).Brain as IControlledBrain;
  344. if (controlled != null)
  345. {
  346. attacker = controlled.Owner;
  347. quiet = true; // silence all attacks by controlled npc
  348. }
  349. }
  350. if (defender is GameNPC)
  351. {
  352. IControlledBrain controlled = ((GameNPC)defender).Brain as IControlledBrain;
  353. if (controlled != null)
  354. defender = controlled.Owner;
  355. }
  356.  
  357. //"You can't attack yourself!"
  358. if (attacker == defender)
  359. {
  360. if (quiet == false) MessageToLiving(attacker, "You can't attack yourself!");
  361. return false;
  362. }
  363.  
  364. if (attacker.Realm != 0 && defender.Realm != 0)
  365. {
  366. if (attacker is GamePlayer && ((GamePlayer)attacker).DuelTarget != defender)
  367. {
  368. // allow mobs to attack mobs
  369. if (attacker.Realm == 0)
  370. return true;
  371.  
  372. if (quiet == false) MessageToLiving(attacker, "You can not attack other players on this server!");
  373. return false;
  374. }
  375. }
  376.  
  377. // mobs can't attack mobs
  378. if (attacker.Realm == 0 && defender.Realm == 0)
  379. return false;
  380.  
  381. return true;
  382. }
  383.  
  384. /// <summary>
  385. /// PvPServerRules: Is attacker allowed to attack defender.
  386. /// </summary>
  387. /// <param name="attacker">living that makes attack</param>
  388. /// <param name="defender">attacker's target</param>
  389. /// <param name="quiet">should messages be sent</param>
  390. /// <returns>true if attack is allowed</returns>
  391. protected virtual bool PvP_IsAllowedToAttack(GameLiving attacker, GameLiving defender, bool quiet)
  392. {
  393. if (!Abstract_IsAllowedToAttack(attacker, defender, quiet))
  394. return false;
  395.  
  396. // if controlled NPC - do checks for owner instead
  397. if (attacker is GameNPC)
  398. {
  399. IControlledBrain controlled = ((GameNPC)attacker).Brain as IControlledBrain;
  400. if (controlled != null)
  401. {
  402. attacker = controlled.Owner;
  403. quiet = true; // silence all attacks by controlled npc
  404. }
  405. }
  406. if (defender is GameNPC)
  407. {
  408. IControlledBrain controlled = ((GameNPC)defender).Brain as IControlledBrain;
  409. if (controlled != null)
  410. defender = controlled.Owner;
  411. }
  412.  
  413. // can't attack self
  414. if (attacker == defender)
  415. {
  416. if (quiet == false) MessageToLiving(attacker, "You can't attack yourself!");
  417. return false;
  418. }
  419.  
  420. //ogre: sometimes other players shouldn't be attackable
  421. GamePlayer playerAttacker = attacker as GamePlayer;
  422. GamePlayer playerDefender = defender as GamePlayer;
  423. if (playerAttacker != null && playerDefender != null)
  424. {
  425. //check group
  426. if (playerAttacker.Group != null && playerAttacker.Group.IsInTheGroup(playerDefender))
  427. {
  428. if (!quiet) MessageToLiving(playerAttacker, "You can't attack your group members.");
  429. return false;
  430. }
  431.  
  432. if (playerAttacker.DuelTarget != defender)
  433. {
  434. //check guild
  435. if (playerAttacker.Guild != null && playerAttacker.Guild == playerDefender.Guild)
  436. {
  437. if (!quiet) MessageToLiving(playerAttacker, "You can't attack your guild members.");
  438. return false;
  439. }
  440.  
  441. //todo: battlegroups
  442.  
  443. // Safe regions
  444. if (m_safeRegions != null)
  445. {
  446. foreach (int reg in m_safeRegions)
  447. if (playerAttacker.CurrentRegionID == reg)
  448. {
  449. if (quiet == false) MessageToLiving(playerAttacker, "You're currently in a safe zone, you can't attack other players here.");
  450. return false;
  451. }
  452. }
  453.  
  454. /********************************** DISABLED by VaNaTiC cause of special TCServerRules
  455. // Players with safety flag can not attack other players
  456. if (playerAttacker.Level < m_safetyLevel && playerAttacker.SafetyFlag)
  457. {
  458. if (quiet == false) MessageToLiving(attacker, "Your PvP safety flag is ON.");
  459. return false;
  460. }
  461.  
  462. // Players with safety flag can not be attacked in safe regions
  463. if (playerDefender.Level < m_safetyLevel && playerDefender.SafetyFlag)
  464. {
  465. bool unsafeRegion = false;
  466. foreach (int regionID in m_unsafeRegions)
  467. {
  468. if (regionID == playerDefender.CurrentRegionID)
  469. {
  470. unsafeRegion = true;
  471. break;
  472. }
  473. }
  474. if (unsafeRegion == false)
  475. {
  476. //"PLAYER has his safety flag on and is in a safe area, you can't attack him here."
  477. if (quiet == false) MessageToLiving(attacker, playerDefender.Name + " has " + playerDefender.GetPronoun(1, false) + " safety flag on and is in a safe area, you can't attack " + playerDefender.GetPronoun(2, false) + " here.");
  478. return false;
  479. }
  480. }
  481. ******************************************************************************/
  482. }
  483. }
  484.  
  485. // allow mobs to attack mobs
  486. if (attacker.Realm == 0 && defender.Realm == 0)
  487. return true;
  488.  
  489. //allow confused mobs to attack same realm
  490. if (attacker is GameNPC && (attacker as GameNPC).IsConfused && attacker.Realm == defender.Realm)
  491. return true;
  492.  
  493. // "friendly" NPCs can't attack "friendly" players
  494. if (defender is GameNPC && defender.Realm != 0 && attacker.Realm != 0 && defender is GameKeepGuard == false)
  495. {
  496. if (quiet == false) MessageToLiving(attacker, "You can't attack a friendly NPC!");
  497. return false;
  498. }
  499. // "friendly" NPCs can't be attacked by "friendly" players
  500. if (attacker is GameNPC && attacker.Realm != 0 && defender.Realm != 0 && attacker is GameKeepGuard == false)
  501. {
  502. return false;
  503. }
  504.  
  505. #region Keep Guards
  506. //guard vs guard / npc
  507. if (attacker is GameKeepGuard)
  508. {
  509. if (defender is GameKeepGuard)
  510. return false;
  511.  
  512. if (defender is GameNPC && (defender as GameNPC).Brain is IControlledBrain == false)
  513. return false;
  514. }
  515.  
  516. //player vs guard
  517. if (defender is GameKeepGuard && attacker is GamePlayer
  518. && GameServer.KeepManager.IsEnemy(defender as GameKeepGuard, attacker as GamePlayer) == false)
  519. {
  520. if (quiet == false) MessageToLiving(attacker, "You can't attack a friendly NPC!");
  521. return false;
  522. }
  523.  
  524. //guard vs player
  525. if (attacker is GameKeepGuard && defender is GamePlayer
  526. && GameServer.KeepManager.IsEnemy(attacker as GameKeepGuard, defender as GamePlayer) == false)
  527. {
  528. return false;
  529. }
  530. #endregion
  531.  
  532. return true;
  533. }
  534.  
  535. /// <summary>
  536. /// Is attacker allowed to attack defender.
  537. /// ThidrankiClassic: PvE, PvP, RvR and SafeRegions in One for our SetupZone Caer Sidi
  538. /// </summary>
  539. /// <param name="attacker">living that makes attack</param>
  540. /// <param name="defender">attacker's target</param>
  541. /// <param name="quiet">should messages be sent</param>
  542. /// <returns>true if attack is allowed</returns>
  543. public override bool IsAllowedToAttack(GameLiving attacker, GameLiving defender, bool quiet)
  544. {
  545. if (attacker == null || defender == null)
  546. return false;
  547.  
  548. if (TCServerRules.IsPvPZone(attacker.CurrentRegionID))
  549. return PvP_IsAllowedToAttack(attacker, defender, quiet);
  550. else if (TCServerRules.IsPvEZone(attacker.CurrentRegionID))
  551. return PvE_IsAllowedToAttack(attacker, defender, quiet);
  552.  
  553. bool allowed = base.IsAllowedToAttack(attacker, defender, true);
  554. // ONLY check safe-zones if allowed from base
  555. if (allowed && TCServerRules.IsSafeZone(attacker.CurrentRegionID))
  556. {
  557. if (defender is GamePlayer
  558. && (attacker is GamePlayer || !(attacker is GameTrainingDummy)))
  559. {
  560. if (!quiet)
  561. MessageToLiving(attacker, "You're currently in a safe zone, you can't attack other players here.");
  562. return false;
  563. }
  564. }
  565. return allowed;
  566. }
  567.  
  568. #endregion
  569.  
  570. #region IsSameRealm merge for PvE, PvP, RvR and SafeRegions
  571.  
  572. /// <summary>
  573. /// PvEServerRules: Does source considers target "friendly".
  574. /// Used for spells with "Realm" and "Group" spell types, friend list.
  575. /// </summary>
  576. /// <param name="source">spell source, considering object</param>
  577. /// <param name="target">spell target, considered object</param>
  578. /// <param name="quiet"></param>
  579. /// <returns></returns>
  580. protected virtual bool PvE_IsSameRealm(GameLiving source, GameLiving target, bool quiet)
  581. {
  582. if (source == null || target == null) return false;
  583.  
  584. // if controlled NPC - do checks for owner instead
  585. if (source is GameNPC)
  586. {
  587. IControlledBrain controlled = ((GameNPC)source).Brain as IControlledBrain;
  588. if (controlled != null)
  589. {
  590. source = controlled.Owner;
  591. quiet = true; // silence all attacks by controlled npc
  592. }
  593. }
  594. if (target is GameNPC)
  595. {
  596. IControlledBrain controlled = ((GameNPC)target).Brain as IControlledBrain;
  597. if (controlled != null)
  598. target = controlled.Owner;
  599. }
  600.  
  601. // clients with priv level > 1 are considered friendly by anyone
  602. if (target is GamePlayer && ((GamePlayer)target).Client.Account.PrivLevel > 1) return true;
  603.  
  604. // mobs can heal mobs, players heal players/NPC
  605. if (source.Realm == 0 && target.Realm == 0) return true;
  606. if (source.Realm != 0 && target.Realm != 0) return true;
  607.  
  608. //Peace flag NPCs are same realm
  609. if (target is GameNPC)
  610. if ((((GameNPC)target).Flags & GameNPC.eFlags.PEACE) != 0)
  611. return true;
  612.  
  613. if (source is GameNPC)
  614. if ((((GameNPC)source).Flags & GameNPC.eFlags.PEACE) != 0)
  615. return true;
  616.  
  617. if (quiet == false) MessageToLiving(source, target.GetName(0, true) + " is not a member of your realm!");
  618. return false;
  619. }
  620.  
  621. /// <summary>
  622. /// PvPServerRules: Does source considers target "friendly".
  623. /// Used for spells with "Realm" and "Group" spell types, friend list.
  624. /// </summary>
  625. /// <param name="source">spell source, considering object</param>
  626. /// <param name="target">spell target, considered object</param>
  627. /// <param name="quiet"></param>
  628. /// <returns></returns>
  629. protected virtual bool PvP_IsSameRealm(GameLiving source, GameLiving target, bool quiet)
  630. {
  631. if (source == null || target == null) return false;
  632.  
  633. // if controlled NPC - do checks for owner instead
  634. if (source is GameNPC)
  635. {
  636. IControlledBrain controlled = ((GameNPC)source).Brain as IControlledBrain;
  637. if (controlled != null)
  638. {
  639. source = controlled.Owner;
  640. quiet = true; // silence all attacks by controlled npc
  641. }
  642. }
  643. if (target is GameNPC)
  644. {
  645. IControlledBrain controlled = ((GameNPC)target).Brain as IControlledBrain;
  646. if (controlled != null)
  647. target = controlled.Owner;
  648. }
  649.  
  650. // clients with priv level > 1 are considered friendly by anyone
  651. if (target is GamePlayer && ((GamePlayer)target).Client.Account.PrivLevel > 1) return true;
  652. // checking as a gm, targets are considered friendly
  653. if (source is GamePlayer && ((GamePlayer)source).Client.Account.PrivLevel > 1) return true;
  654.  
  655. // mobs can heal mobs, players heal players/NPC
  656. if (source.Realm == 0 && target.Realm == 0) return true;
  657.  
  658. //keep guards
  659. if (source is GameKeepGuard && target is GamePlayer)
  660. {
  661. if (!GameServer.KeepManager.IsEnemy(source as GameKeepGuard, target as GamePlayer))
  662. return true;
  663. }
  664.  
  665. if (target is GameKeepGuard && source is GamePlayer)
  666. {
  667. if (!GameServer.KeepManager.IsEnemy(target as GameKeepGuard, source as GamePlayer))
  668. return true;
  669. }
  670.  
  671. //doors need special handling
  672. if (target is GameKeepDoor && source is GamePlayer)
  673. return GameServer.KeepManager.IsEnemy(target as GameKeepDoor, source as GamePlayer);
  674.  
  675. if (source is GameKeepDoor && target is GamePlayer)
  676. return GameServer.KeepManager.IsEnemy(source as GameKeepDoor, target as GamePlayer);
  677.  
  678. //components need special handling
  679. if (target is GameKeepComponent && source is GamePlayer)
  680. return GameServer.KeepManager.IsEnemy(target as GameKeepComponent, source as GamePlayer);
  681.  
  682. //Peace flag NPCs are same realm
  683. if (target is GameNPC)
  684. if ((((GameNPC)target).Flags & GameNPC.eFlags.PEACE) != 0)
  685. return true;
  686.  
  687. if (source is GameNPC)
  688. if ((((GameNPC)source).Flags & GameNPC.eFlags.PEACE) != 0)
  689. return true;
  690.  
  691. if (source is GamePlayer && target is GamePlayer)
  692. return true;
  693.  
  694. if (source is GamePlayer && target is GameNPC && target.Realm != 0)
  695. return true;
  696.  
  697. if (quiet == false) MessageToLiving(source, target.GetName(0, true) + " is not a member of your realm!");
  698. return false;
  699. }
  700.  
  701. /// <summary>
  702. /// Does source considers target "friendly".
  703. /// Used for spells with "Realm" and "Group" spell types, friend list.
  704. /// </summary>
  705. /// <param name="source">spell source, considering object</param>
  706. /// <param name="target">spell target, considered object</param>
  707. /// <param name="quiet"></param>
  708. /// <returns></returns>
  709. public override bool IsSameRealm(GameLiving source, GameLiving target, bool quiet)
  710. {
  711.  
  712.  
  713.  
  714. if (source == null || target == null) return false;
  715.  
  716. if (TCServerRules.IsPvPZone(source.CurrentRegionID))
  717. return PvP_IsSameRealm(source, target, quiet);
  718. else if (TCServerRules.IsPvEZone(source.CurrentRegionID))
  719. return PvE_IsSameRealm(source, target, quiet);
  720. else
  721. return base.IsSameRealm(source, target, quiet);
  722. }
  723.  
  724. #endregion
  725.  
  726. #region IsAllowedToCastSpell() merge for PvE, PvP, RvR and SafeZones
  727.  
  728. /// <summary>
  729. /// Is caster allowed to cast a spell
  730. /// </summary>
  731. /// <param name="caster"></param>
  732. /// <param name="target"></param>
  733. /// <param name="spell"></param>
  734. /// <param name="spellLine"></param>
  735. /// <returns>true if allowed</returns>
  736. public override bool IsAllowedToCastSpell(GameLiving caster, GameLiving target, Spell spell, SpellLine spellLine)
  737. {
  738. if (!base.IsAllowedToCastSpell(caster, target, spell, spellLine))
  739. return false;
  740. if (!TCServerRules.IsPvPZone(caster.CurrentRegionID))
  741. return true;
  742. // if reached here, we have to know we are in pvp and check if allowed there
  743.  
  744. GamePlayer casterPlayer = caster as GamePlayer;
  745. if (casterPlayer != null)
  746. {
  747. if (casterPlayer.IsInvulnerableToAttack)
  748. {
  749. // always allow selftargeted spells
  750. if (spell.Target == "Self") return true;
  751.  
  752. // only caster can be the target, can't buff/heal other players
  753. // PBAE/GTAE doesn't need a target so we check spell type as well
  754. if (caster != target || spell.Target == "Area" || spell.Target == "Enemy" || (spell.Target == "Group" && spell.SpellType != "SpeedEnhancement"))
  755. {
  756. MessageToLiving(caster, "You can only cast spells on yourself until your PvP invulnerability timer wears off!", eChatType.CT_Important);
  757. return false;
  758. }
  759. }
  760.  
  761. }
  762. return true;
  763. }
  764.  
  765. #endregion
  766.  
  767. #region possible to grp mates from all realms in safe/pvp-zone (setup or pvp-regions)
  768.  
  769. /// <summary>
  770. /// Is source allowed to group target.
  771. /// </summary>
  772. /// <param name="source"></param>
  773. /// <param name="target"></param>
  774. /// <param name="quiet"></param>
  775. /// <returns></returns>
  776. public override bool IsAllowedToGroup(GamePlayer source, GamePlayer target, bool quiet)
  777. {
  778. bool allowed = base.IsAllowedToGroup(source, target, true);
  779. // ONLY check safe/pvp-zones if NOT allowed from base
  780. if (!allowed
  781. && source != null
  782. && target != null
  783. && source is GamePlayer
  784. && target is GamePlayer
  785. && source.Realm != target.Realm
  786. && source.CurrentRegionID == target.CurrentRegionID)
  787. {
  788. if (TCServerRules.IsSafeZone(target.CurrentRegionID) ||
  789. TCServerRules.IsPvEZone(target.CurrentRegionID) ||
  790. TCServerRules.IsPvPZone(target.CurrentRegionID))
  791. return true;
  792.  
  793. if (!quiet)
  794. MessageToLiving(source, "You can't invite a player of another realm.");
  795. return false;
  796. }
  797.  
  798. return allowed;
  799. }
  800.  
  801. #endregion
  802.  
  803. #region all realms can communicate in safe/pvp-zone (setup or pvp-regions)
  804.  
  805. /// <summary>
  806. /// Is target allowed to understand source.
  807. /// </summary>
  808. /// <param name="source"></param>
  809. /// <param name="target"></param>
  810. /// <returns></returns>
  811. public override bool IsAllowedToUnderstand(GameLiving source, GamePlayer target)
  812. {
  813. bool allowed = base.IsAllowedToUnderstand(source, target);
  814. // ONLY check safe/pvp-zones if NOT allowed from base
  815. if (!allowed
  816. && source != null
  817. && target != null
  818. && source is GamePlayer)
  819. if (TCServerRules.IsSafeZone(target.CurrentRegionID) ||
  820. TCServerRules.IsPvEZone(target.CurrentRegionID) ||
  821. TCServerRules.IsPvPZone(target.CurrentRegionID))
  822. return true;
  823. return allowed;
  824. }
  825.  
  826. #endregion
  827.  
  828. #region all realms can trade in safe/pvp-zone (setup or pvp-regions)
  829.  
  830. /// <summary>
  831. /// Is source allowed to trade with target.
  832. /// </summary>
  833. /// <param name="source"></param>
  834. /// <param name="target"></param>
  835. /// <param name="quiet"></param>
  836. /// <returns></returns>
  837. public override bool IsAllowedToTrade(GameLiving source, GameLiving target, bool quiet)
  838. {
  839. bool allowed = base.IsAllowedToTrade(source, target, true);
  840. // ONLY check safe/pvp-zones if NOT allowed from base
  841. if (!allowed
  842. && source != null
  843. && target != null
  844. && source is GamePlayer
  845. && target is GamePlayer
  846. && source.Realm != target.Realm
  847. && source.CurrentRegionID == target.CurrentRegionID)
  848. {
  849. if (TCServerRules.IsSafeZone(target.CurrentRegionID) ||
  850. TCServerRules.IsPvEZone(target.CurrentRegionID) ||
  851. TCServerRules.IsPvPZone(target.CurrentRegionID))
  852. return true;
  853.  
  854. if (!quiet)
  855. MessageToLiving(source, "You can't trade with enemy realm!");
  856. return false;
  857. }
  858.  
  859. return allowed;
  860. }
  861.  
  862. #endregion
  863.  
  864. #region PvE/PvP name- and color-handling in safe/pvp-zones
  865.  
  866. /// <summary>
  867. /// Gets the server type color handling scheme
  868. ///
  869. /// ColorHandling: this byte tells the client how to handle color for PC and NPC names (over the head)
  870. /// 0: standard way, other realm PC appear red, our realm NPC appear light green
  871. /// 1: standard PvP way, all PC appear red, all NPC appear with their level color
  872. /// 2: Same realm livings are friendly, other realm livings are enemy; nearest friend/enemy buttons work
  873. /// 3: standard PvE way, all PC friendly, realm 0 NPC enemy rest NPC appear light green
  874. /// 4: All NPC are enemy, all players are friendly; nearest friend button selects self, nearest enemy don't work at all
  875. /// </summary>
  876. /// <param name="client">The client asking for color handling</param>
  877. /// <returns>The color handling</returns>
  878. public override byte GetColorHandling(GameClient client)
  879. {
  880. if (client != null && client.Player != null)
  881. {
  882. if (TCServerRules.IsSafeZone(client.Player.CurrentRegionID))
  883. return 3;
  884. else if (TCServerRules.IsPvEZone(client.Player.CurrentRegionID))
  885. return 3;
  886. else if (TCServerRules.IsPvPZone(client.Player.CurrentRegionID))
  887. return 1;
  888. }
  889. return base.GetColorHandling(client);
  890. }
  891.  
  892. /// <summary>
  893. /// Gets the player name based on server type and safe/pvp-zone
  894. /// </summary>
  895. /// <param name="source">The "looking" player</param>
  896. /// <param name="target">The considered player</param>
  897. /// <returns>The name of the target</returns>
  898. public override string GetPlayerName(GamePlayer source, GamePlayer target)
  899. {
  900. if (source != null
  901. && target != null
  902. && source is GamePlayer
  903. && target is GamePlayer
  904. && source.Realm != target.Realm
  905. && source.CurrentRegionID == target.CurrentRegionID)
  906. {
  907. if (TCServerRules.IsSafeZone(target.CurrentRegionID) ||
  908. TCServerRules.IsPvEZone(target.CurrentRegionID) ||
  909. TCServerRules.IsPvPZone(target.CurrentRegionID))
  910. return target.Name;
  911. }
  912. return base.GetPlayerName(source, target);
  913. }
  914.  
  915. /// <summary>
  916. /// Gets the player last name based on server type and safe/pvp-zone
  917. /// </summary>
  918. /// <param name="source">The "looking" player</param>
  919. /// <param name="target">The considered player</param>
  920. /// <returns>The last name of the target</returns>
  921. public override string GetPlayerLastName(GamePlayer source, GamePlayer target)
  922. {
  923. if (source != null
  924. && target != null
  925. && source is GamePlayer
  926. && target is GamePlayer
  927. && source.Realm != target.Realm
  928. && source.CurrentRegionID == target.CurrentRegionID)
  929. {
  930. if (TCServerRules.IsSafeZone(target.CurrentRegionID) ||
  931. TCServerRules.IsPvEZone(target.CurrentRegionID) ||
  932. TCServerRules.IsPvPZone(target.CurrentRegionID))
  933. return target.LastName;
  934. }
  935. return base.GetPlayerLastName(source, target);
  936. }
  937.  
  938. /// <summary>
  939. /// Gets the player guild name based on server type and safe/pvp-zone
  940. /// </summary>
  941. /// <param name="source">The "looking" player</param>
  942. /// <param name="target">The considered player</param>
  943. /// <returns>The guild name of the target</returns>
  944. public override string GetPlayerGuildName(GamePlayer source, GamePlayer target)
  945. {
  946. if (source != null
  947. && target != null
  948. && source is GamePlayer
  949. && target is GamePlayer
  950. && source.Realm != target.Realm
  951. && source.CurrentRegionID == target.CurrentRegionID)
  952. {
  953. if (TCServerRules.IsSafeZone(target.CurrentRegionID) ||
  954. TCServerRules.IsPvEZone(target.CurrentRegionID) ||
  955. TCServerRules.IsPvPZone(target.CurrentRegionID))
  956. return target.GuildName;
  957. }
  958. return base.GetPlayerGuildName(source, target);
  959. }
  960.  
  961. #endregion
  962.  
  963. #region vip-handling with account.Mail
  964.  
  965. /// <summary>
  966. /// Allows or denies a client from connecting to the server ...
  967. /// For ThidrankiClassic: Account.Mail != "" -> VIP
  968. /// NOTE: The client has not been fully initialized when this method is called.
  969. /// For example, no account or character data has been loaded yet.
  970. /// </summary>
  971. /// <param name="client">The client that sent the login request</param>
  972. /// <param name="username">The username of the client wanting to connect</param>
  973. /// <returns>true if connection allowed, false if connection should be terminated</returns>
  974. /// <remarks>You can only send ONE packet to the client and this is the
  975. /// LoginDenied packet before returning false. Trying to send any other packet
  976. /// might result in unexpected behaviour on server and client!</remarks>
  977. public override bool IsAllowedToConnect(GameClient client, string username)
  978. {
  979. if (!client.Socket.Connected)
  980. return false;
  981. string accip = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString();
  982.  
  983. // Ban account
  984. IList<DBBannedAccount> objs;
  985. //objs = GameServer.Database.SelectObjects<DBBannedAccount>("(Type ='Account' AND Account ='" + GameServer.Database.Escape(username) + "') OR (Type ='Account+Ip' AND Account ='" + GameServer.Database.Escape(username) + "')");
  986. objs = GameServer.Database.SelectObjects<DBBannedAccount>("((Type='A' OR Type='B') AND Account ='" + GameServer.Database.Escape(username) + "')");
  987. if (objs.Count > 0)
  988. {
  989. client.Out.SendLoginDenied(eLoginError.AccountIsBannedFromThisServerType);
  990. return false;
  991. }
  992.  
  993. // Ban IP Adress
  994. //objs = GameServer.Database.SelectObjects<DBBannedAccount>("(Type = 'Ip' AND Ip ='" + GameServer.Database.Escape(accip) + "') OR (Type ='Account+Ip' AND Ip ='" + GameServer.Database.Escape(accip) + "')");
  995. objs = GameServer.Database.SelectObjects<DBBannedAccount>("((Type='I' OR Type='B') AND Ip ='" + GameServer.Database.Escape(accip) + "')");
  996. if (objs.Count > 0)
  997. {
  998. client.Out.SendLoginDenied(eLoginError.AccountIsBannedFromThisServerType);
  999. return false;
  1000. }
  1001.  
  1002. GameClient.eClientVersion min = (GameClient.eClientVersion)Properties.CLIENT_VERSION_MIN;
  1003. if (min != GameClient.eClientVersion.VersionNotChecked && client.Version < min)
  1004. {
  1005. client.Out.SendLoginDenied(eLoginError.ClientVersionTooLow);
  1006. return false;
  1007. }
  1008.  
  1009. GameClient.eClientVersion max = (GameClient.eClientVersion)Properties.CLIENT_VERSION_MAX;
  1010. if (max != GameClient.eClientVersion.VersionNotChecked && client.Version > max)
  1011. {
  1012. client.Out.SendLoginDenied(eLoginError.ClientVersionTooLow);
  1013. return false;
  1014. }
  1015.  
  1016. if (Properties.CLIENT_TYPE_MAX > -1)
  1017. {
  1018. GameClient.eClientType type = (GameClient.eClientType)Properties.CLIENT_TYPE_MAX;
  1019. if ((int)client.ClientType > (int)type)
  1020. {
  1021. client.Out.SendLoginDenied(eLoginError.ExpansionPacketNotAllowed);
  1022. return false;
  1023. }
  1024. }
  1025.  
  1026. /* Example to limit the connections from a certain IP range!
  1027. if(client.Socket.RemoteEndPoint.ToString().StartsWith("192.168.0."))
  1028. {
  1029. client.Out.SendLoginDenied(eLoginError.AccountNoAccessAnyGame);
  1030. return false;
  1031. }
  1032. */
  1033.  
  1034.  
  1035. /* Example to deny new connections on saturdays
  1036. if(DateTime.Now.DayOfWeek == DayOfWeek.Saturday)
  1037. {
  1038. client.Out.SendLoginDenied(eLoginError.GameCurrentlyClosed);
  1039. return false;
  1040. }
  1041. */
  1042.  
  1043. /* Example to deny new connections between 10am and 12am
  1044. if(DateTime.Now.Hour >= 10 && DateTime.Now.Hour <= 12)
  1045. {
  1046. client.Out.SendLoginDenied(eLoginError.GameCurrentlyClosed);
  1047. return false;
  1048. }
  1049. */
  1050.  
  1051. IList<Account> accountobjs;
  1052. if (Properties.MAX_PLAYERS > 0)
  1053. {
  1054. if (WorldMgr.GetAllClients().Count > Properties.MAX_PLAYERS)
  1055. {
  1056. // GMs are still allowed to enter server
  1057. accountobjs = GameServer.Database.SelectObjects<Account>(string.Format("Name = '{0}'", GameServer.Database.Escape(username)));
  1058. if (accountobjs.Count > 0)
  1059. {
  1060. Account account = accountobjs[0] as Account;
  1061. if (account.PrivLevel > 1) return true;
  1062. if (account.Mail != "") return true;
  1063. }
  1064.  
  1065. // Normal Players will not be allowed over the max
  1066. client.Out.SendLoginDenied(eLoginError.TooManyPlayersLoggedIn);
  1067. return false;
  1068. }
  1069. }
  1070.  
  1071. if (Properties.STAFF_LOGIN)
  1072. {
  1073. // GMs are still allowed to enter server
  1074. accountobjs = GameServer.Database.SelectObjects<Account>(string.Format("Name = '{0}'", GameServer.Database.Escape(username)));
  1075. if (accountobjs.Count > 0)
  1076. {
  1077. Account account = accountobjs[0] as Account;
  1078. if (account.PrivLevel > 1) return true;
  1079. }
  1080.  
  1081. // Normal Players will not be allowed to log in
  1082. client.Out.SendLoginDenied(eLoginError.GameCurrentlyClosed);
  1083. return false;
  1084. }
  1085.  
  1086. return true;
  1087. }
  1088.  
  1089. #endregion
  1090.  
  1091. #region special anti-zerg-handling on calculating RP/BP-worth on player killed
  1092.  
  1093. /// <summary>
  1094. /// Invoked on Player death and deals out
  1095. /// experience/realm points if needed
  1096. /// </summary>
  1097. /// <param name="killedPlayer">player that died</param>
  1098. /// <param name="killer">killer</param>
  1099. public override void OnPlayerKilled(GamePlayer killedPlayer, GameObject killer)
  1100. {
  1101. #region "player has been killed recently"
  1102. killedPlayer.LastDeathRealmPoints = 0;
  1103. // "player has been killed recently"
  1104. long noExpSeconds = ServerProperties.Properties.RP_WORTH_SECONDS;
  1105. if (killedPlayer.DBCharacter.DeathTime + noExpSeconds > killedPlayer.PlayedTime)
  1106. {
  1107. lock (killedPlayer.XPGainers.SyncRoot)
  1108. {
  1109. foreach (DictionaryEntry de in killedPlayer.XPGainers)
  1110. {
  1111. if (de.Key is GamePlayer)
  1112. {
  1113. ((GamePlayer)de.Key).Out.SendMessage(killedPlayer.Name + " has been killed recently and is worth no realm points!", eChatType.CT_Important, eChatLoc.CL_SystemWindow);
  1114. ((GamePlayer)de.Key).Out.SendMessage(killedPlayer.Name + " has been killed recently and is worth no experience!", eChatType.CT_Important, eChatLoc.CL_SystemWindow);
  1115. }
  1116. }
  1117. }
  1118. return;
  1119. }
  1120. #endregion "player has been killed recently"
  1121.  
  1122. lock (killedPlayer.XPGainers.SyncRoot)
  1123. {
  1124. #region "You gain no experience from this kill!"
  1125. bool dealNoXP = false;
  1126. float totalDamage = 0;
  1127. //Collect the total damage
  1128. foreach (DictionaryEntry de in killedPlayer.XPGainers)
  1129. {
  1130. GameObject obj = (GameObject)de.Key;
  1131. if (obj is GamePlayer)
  1132. {
  1133. //If a gameplayer with privlevel > 1 attacked the
  1134. //mob, then the players won't gain xp ...
  1135. if (((GamePlayer)obj).Client.Account.PrivLevel > 1)
  1136. {
  1137. dealNoXP = true;
  1138. break;
  1139. }
  1140. }
  1141. totalDamage += (float)de.Value;
  1142. }
  1143.  
  1144. if (dealNoXP)
  1145. {
  1146. foreach (DictionaryEntry de in killedPlayer.XPGainers)
  1147. {
  1148. GamePlayer player = de.Key as GamePlayer;
  1149. if (player != null)
  1150. player.Out.SendMessage("You gain no experience from this kill!", eChatType.CT_System, eChatLoc.CL_SystemWindow);
  1151. }
  1152. return;
  1153. }
  1154. #endregion "You gain no experience from this kill!"
  1155.  
  1156. #region calculating the base-amount of XP,RP+BP
  1157. long playerExpValue = killedPlayer.ExperienceValue;
  1158. playerExpValue = (long)(playerExpValue * ServerProperties.Properties.XP_RATE);
  1159. int playerRPValue = killedPlayer.RealmPointsValue;
  1160. int playerBPValue = 0;
  1161. bool BG = false;
  1162. foreach (AbstractGameKeep keep in GameServer.KeepManager.GetKeepsOfRegion(killedPlayer.CurrentRegionID))
  1163. {
  1164. if (keep.DBKeep.BaseLevel < 50)
  1165. {
  1166. BG = true;
  1167. break;
  1168. }
  1169. }
  1170. if (!BG)
  1171. playerBPValue = killedPlayer.BountyPointsValue;
  1172. long playerMoneyValue = killedPlayer.MoneyValue;
  1173. #endregion calculating the base-amount
  1174.  
  1175. #region RECALCULATING the amount of XP,RP+BP based upon count of friends and enemies
  1176.  
  1177. // getting all attackers for died player
  1178. // (better performance if we do it only once)
  1179. Hashtable attackersOfKilledPlayer = new Hashtable();
  1180. // getting all attackers for the enemies of died player
  1181. Hashtable attackersOfKiller = new Hashtable();
  1182. lock (killedPlayer.XPGainers.SyncRoot)
  1183. {
  1184. foreach (DictionaryEntry de in killedPlayer.XPGainers)
  1185. if (de.Key is GameLiving)
  1186. {
  1187. attackersOfKilledPlayer[de.Key] = killedPlayer;
  1188. GameLiving living = (GameLiving)de.Key;
  1189. lock (living.XPGainers.SyncRoot)
  1190. {
  1191. foreach (DictionaryEntry de2 in living.XPGainers)
  1192. attackersOfKiller[de2.Key] = living;
  1193. }
  1194. }
  1195. }
  1196.  
  1197. // Counting friends and enemies in radius of 1500
  1198. int nFriends = 1; // should be min 1 (killedPlayer itself) + others
  1199. int nEnemies = 1; // should be min 1 (killer itself) + others
  1200.  
  1201. // try to parse killers player grp (if its a player and if it has a grp)
  1202. Group killerPlayerGrp = null;
  1203. if (killer is GamePlayer)
  1204. killerPlayerGrp = ((GamePlayer)killer).Group;
  1205. else if (killer is GameNPC && ((GameNPC)killer).Brain is ControlledNpcBrain)
  1206. killerPlayerGrp = ((ControlledNpcBrain)((GameNPC)killer).Brain).Owner.Group;
  1207.  
  1208. // add killed players grp to friends (itself, not)
  1209. if (killedPlayer.Group != null)
  1210. nFriends += killedPlayer.Group.MemberCount - 1;
  1211. if (killerPlayerGrp != null)
  1212. nEnemies += killerPlayerGrp.MemberCount - 1;
  1213.  
  1214. // handle all players in radius
  1215. foreach (GamePlayer player in killedPlayer.GetPlayersInRadius(1500))
  1216. {
  1217. // check if killer or killedPlayer itself (we already counted both above)
  1218. if (player == killer || player == killedPlayer)
  1219. continue;
  1220. // check if player is GM
  1221. if (player.Client.Account.PrivLevel >= (uint)ePrivLevel.GM)
  1222. continue;
  1223. // check if player is in killed players grp
  1224. if (killedPlayer.Group != null && killedPlayer.Group.IsInTheGroup(player))
  1225. continue;
  1226. // check if player is in killer players grp
  1227. if (killerPlayerGrp != null && killerPlayerGrp.IsInTheGroup(player))
  1228. continue;
  1229.  
  1230. //->new code (2007-04-19)
  1231. // look if this player is in the XPGainers-List of the died player
  1232. // -> enemy
  1233. if (attackersOfKilledPlayer.ContainsKey(player))
  1234. nEnemies++;
  1235. // look if this player is in the list of attackers of killedPlayers enemies (created&filled above)
  1236. if (attackersOfKiller.ContainsKey(player))
  1237. nFriends++;
  1238. //<-new code (2007-04-19)
  1239.  
  1240. //->OBSOLETE as of above new code (2007-04-19)
  1241. /*
  1242. // else count it to the right side
  1243. if ( killedPlayer.Realm == player.Realm )
  1244. ++nFriends;
  1245. else
  1246. ++nEnemies;
  1247. */
  1248. //<-OBSOLETE as of above new code (2007-04-19)
  1249. }
  1250.  
  1251. if (LOGGING)
  1252. {
  1253. StringBuilder sb = new StringBuilder();
  1254. sb.Append("OnPlayerKilled(): ");
  1255. if (killedPlayer != null) sb.Append(killedPlayer.Name); else sb.Append("???");
  1256. sb.Append(" was killed by ");
  1257. if (killer != null) sb.Append(killer.Name); else sb.Append("???");
  1258.  
  1259. if (killer != null && killer is GameNPC && ((GameNPC)killer).Brain is ControlledNpcBrain)
  1260. sb.Append("(").Append(((ControlledNpcBrain)((GameNPC)killer).Brain).Owner.Name).Append(")");
  1261.  
  1262. sb.Append(" RP=").Append(playerRPValue).Append("->").Append(ReCalc(playerRPValue, nEnemies, nFriends, CALC_RATE));
  1263. sb.Append(" Friends=").Append(nFriends).Append(" Enemies=").Append(nEnemies);
  1264. if (CALC_PENALTY && nEnemies > nFriends)
  1265. sb.Append(" PENALTY");
  1266. else if (CALC_BONUS && nEnemies < nFriends)
  1267. sb.Append(" BONUS");
  1268. log.Info(sb.ToString());
  1269. }
  1270. // penalty or bonus for enemies
  1271. // if they are more or less as friends
  1272. // of died player
  1273. if ((CALC_PENALTY && nEnemies > nFriends) ||
  1274. (CALC_BONUS && nEnemies < nFriends))
  1275. {
  1276. playerExpValue = ReCalc(playerExpValue, nEnemies, nFriends, CALC_RATE);
  1277. playerRPValue = (int)ReCalc(playerRPValue, nEnemies, nFriends, CALC_RATE);
  1278. playerBPValue = (int)ReCalc(playerBPValue, nEnemies, nFriends, CALC_RATE);
  1279. playerMoneyValue = ReCalc(playerMoneyValue, nEnemies, nFriends, CALC_RATE);
  1280. /*
  1281. playerExpValue /= nEnemies * nFriends;
  1282. playerRPValue /= nEnemies * nFriends;
  1283. playerBPValue /= nEnemies * nFriends;
  1284. playerMoneyValue /= nEnemies * nFriends;
  1285. */
  1286. }
  1287.  
  1288. #endregion RECALCULATING the amount of XP,RP+BP based upon grp-sizes
  1289.  
  1290. #region Now deal the XP and RPs to all livings
  1291. foreach (DictionaryEntry de in killedPlayer.XPGainers)
  1292. {
  1293. GameLiving living = de.Key as GameLiving;
  1294. GamePlayer expGainPlayer = living as GamePlayer;
  1295. if (living == null) continue;
  1296. if (living.ObjectState != GameObject.eObjectState.Active) continue;
  1297. /*
  1298. * http://www.camelotherald.com/more/2289.shtml
  1299. * Dead players will now continue to retain and receive their realm point credit
  1300. * on targets until they release. This will work for solo players as well as
  1301. * grouped players in terms of continuing to contribute their share to the kill
  1302. * if a target is being attacked by another non grouped player as well.
  1303. */
  1304. //if (!living.Alive) continue;
  1305. if (!WorldMgr.CheckDistance(living, killedPlayer, WorldMgr.MAX_EXPFORKILL_DISTANCE)) continue;
  1306.  
  1307.  
  1308. double damagePercent = (float)de.Value / totalDamage;
  1309. if (!living.IsAlive)//Dead living gets 25% exp only
  1310. damagePercent *= 0.25;
  1311.  
  1312. // realm points
  1313. int rpCap = living.RealmPointsValue * 2;
  1314. int realmPoints = (int)(playerRPValue * damagePercent);
  1315. //rp bonuses from RR and Group
  1316. //20% if R1L0 char kills RR10,if RR10 char kills R1L0 he will get -20% bonus
  1317. //100% if full group,scales down according to player count in group and their range to target
  1318. if (living is GamePlayer)
  1319. {
  1320. GamePlayer killerPlayer = living as GamePlayer;
  1321. realmPoints = (int)(realmPoints * (1.0 + 2.0 * (killedPlayer.RealmLevel - killerPlayer.RealmLevel) / 900.0));
  1322. if (killerPlayer.Group != null && killerPlayer.Group.MemberCount > 1)
  1323. {
  1324. lock (killerPlayer.Group)
  1325. {
  1326. int count = 0;
  1327. foreach (GamePlayer player in killerPlayer.Group.GetPlayersInTheGroup())
  1328. {
  1329. if (!WorldMgr.CheckDistance(player, killedPlayer, WorldMgr.MAX_EXPFORKILL_DISTANCE)) continue;
  1330. count++;
  1331. }
  1332. realmPoints = (int)(realmPoints * (1.0 + count * 0.125));
  1333. }
  1334. }
  1335. }
  1336. if (realmPoints > rpCap)
  1337. realmPoints = rpCap;
  1338. if (realmPoints > 0)
  1339. {
  1340. if (living is GamePlayer)
  1341. killedPlayer.LastDeathRealmPoints += realmPoints;
  1342. living.GainRealmPoints(realmPoints);
  1343. }
  1344.  
  1345. // bounty points
  1346. int bpCap = living.BountyPointsValue * 2;
  1347. int bountyPoints = (int)(playerBPValue * damagePercent);
  1348. if (bountyPoints > bpCap)
  1349. bountyPoints = bpCap;
  1350.  
  1351. #warning this is guessed, i do not believe this is the right way, we will most likely need special messages to be sent
  1352. //apply the keep bonus for bounty points
  1353. if (killer != null)
  1354. {
  1355. if (Keeps.KeepBonusMgr.RealmHasBonus(eKeepBonusType.Bounty_Points_5, (eRealm)killer.Realm))
  1356. bountyPoints += (bountyPoints / 100) * 5;
  1357. else if (Keeps.KeepBonusMgr.RealmHasBonus(eKeepBonusType.Bounty_Points_3, (eRealm)killer.Realm))
  1358. bountyPoints += (bountyPoints / 100) * 3;
  1359. }
  1360.  
  1361. if (bountyPoints > 0)
  1362. {
  1363. living.GainBountyPoints(bountyPoints);
  1364. }
  1365.  
  1366. //Claim Bonus RP/BP if Player Guild have a keep/tower.
  1367. GamePlayer pl = living as GamePlayer;
  1368. if (pl != null && pl.Guild != null && pl.Guild.ClaimedKeeps != null)
  1369. {
  1370. foreach (AbstractGameKeep keep in pl.Guild.ClaimedKeeps)
  1371. {
  1372. if (pl.CurrentRegionID == keep.Region)
  1373. {
  1374. GuildClaimBonus(realmPoints, bountyPoints, pl, keep);
  1375. }
  1376. }
  1377. }
  1378.  
  1379.  
  1380.  
  1381. // experience
  1382. // TODO: pets take 25% and owner gets 75%
  1383. long xpReward = (long)(playerExpValue * damagePercent); // exp for damage percent
  1384.  
  1385. long expCap = (long)(living.ExperienceValue * 1.25);
  1386. if (xpReward > expCap)
  1387. xpReward = expCap;
  1388.  
  1389. //outpost XP
  1390. //1.54 http://www.camelotherald.com/more/567.shtml
  1391. //- Players now receive an exp bonus when fighting within 16,000
  1392. //units of a keep controlled by your realm or your guild.
  1393. //You get 20% bonus if your guild owns the keep or a 10% bonus
  1394. //if your realm owns the keep.
  1395.  
  1396. long outpostXP = 0;
  1397.  
  1398. if (!BG && living is GamePlayer)
  1399. {
  1400. AbstractGameKeep keep = GameServer.KeepManager.GetKeepCloseToSpot(living.CurrentRegionID, living, 16000);
  1401. if (keep != null)
  1402. {
  1403. byte bonus = 0;
  1404. if (keep.Guild != null && keep.Guild == (living as GamePlayer).Guild)
  1405. bonus = 20;
  1406. else if (GameServer.Instance.Configuration.ServerType == eGameServerType.GST_Normal &&
  1407. keep.Realm == living.Realm)
  1408. bonus = 10;
  1409.  
  1410. outpostXP = (xpReward / 100) * bonus;
  1411. }
  1412. }
  1413. xpReward += outpostXP;
  1414.  
  1415. living.GainExperience(GameLiving.eXPSource.Player, xpReward);
  1416.  
  1417. //gold
  1418. if (living is GamePlayer)
  1419. {
  1420. long money = (long)(playerMoneyValue * damagePercent);
  1421. //long money = (long)(Money.GetMoney(0, 0, 17, 85, 0) * damagePercent * killedPlayer.Level / 50);
  1422. ((GamePlayer)living).AddMoney(money, "You recieve {0}");
  1423. }
  1424.  
  1425. if (killedPlayer.ReleaseType != GamePlayer.eReleaseType.Duel && expGainPlayer != null)
  1426. {
  1427. switch ((eRealm)killedPlayer.Realm)
  1428. {
  1429. case eRealm.Albion:
  1430. expGainPlayer.KillsAlbionPlayers++;
  1431. if (expGainPlayer == killer)
  1432. {
  1433. expGainPlayer.KillsAlbionDeathBlows++;
  1434. if ((float)de.Value == totalDamage)
  1435. expGainPlayer.KillsAlbionSolo++;
  1436. }
  1437. break;
  1438.  
  1439. case eRealm.Hibernia:
  1440. expGainPlayer.KillsHiberniaPlayers++;
  1441. if (expGainPlayer == killer)
  1442. {
  1443. expGainPlayer.KillsHiberniaDeathBlows++;
  1444. if ((float)de.Value == totalDamage)
  1445. expGainPlayer.KillsHiberniaSolo++;
  1446. }
  1447. break;
  1448.  
  1449. case eRealm.Midgard:
  1450. expGainPlayer.KillsMidgardPlayers++;
  1451. if (expGainPlayer == killer)
  1452. {
  1453. expGainPlayer.KillsMidgardDeathBlows++;
  1454. if ((float)de.Value == totalDamage)
  1455. expGainPlayer.KillsMidgardSolo++;
  1456. }
  1457. break;
  1458. }
  1459. killedPlayer.DeathsPvP++;
  1460. }
  1461. }
  1462. #endregion Now deal the XP and RPs to all livings
  1463. }
  1464. }
  1465.  
  1466. #region recalculation method
  1467. /// <summary>
  1468. /// it returns (value * rate / devisor * factor) + value * (1-rate)
  1469. /// </summary>
  1470. /// <param name="value">the value which should be recalculated</param>
  1471. /// <param name="divisor">the divisor for the rate of value</param>
  1472. /// <param name="factor">the factor for the rate of value</param>
  1473. /// <param name="rate">rate in percent [0..1]</param>
  1474. /// <returns></returns>
  1475. private long ReCalc(long value, int divisor, int factor, double rate)
  1476. {
  1477. if (rate < 0.0)
  1478. rate = 0.0;
  1479. else if (rate > 1.0)
  1480. rate = 1.0;
  1481. if (divisor == 0)
  1482. divisor = 1;
  1483. return (long)Math.Round(value * rate / divisor * factor + value * (1.0 - rate));
  1484. }
  1485. #endregion
  1486.  
  1487. #region GuildClaimBonus
  1488.  
  1489. /// <summary>
  1490. /// Will add a RP bonus if your guild claim a Tower or Keep.
  1491. /// </summary>
  1492. /// <param name="RP">The RealmPoints the Player will earn.</param>
  1493. /// <param name="BP">The BountyPoints the Player will earn.</param>
  1494. /// <param name="pl">The Player that earn the bonus.</param>
  1495. private void GuildClaimBonus(int RP, int BP, GamePlayer pl, AbstractGameKeep keep)
  1496. {
  1497. if (RP == 0
  1498. && BP == 0
  1499. && pl == null)
  1500. return;
  1501.  
  1502. int RPbonus = (int)(RP * CLAIM_BONUS);
  1503. int BPbonus = (int)(BP * CLAIM_BONUS);
  1504. if (CLAIM_STATUS)
  1505. {
  1506. pl.Out.SendMessage("Your Guild have claimed the " + keep.Name + " therefore you receives " + RPbonus.ToString() + " realmpoints and " + BPbonus.ToString() + " bountypoints as a bonus.", eChatType.CT_Important, eChatLoc.CL_SystemWindow);
  1507. pl.BountyPoints += BPbonus;
  1508. pl.RealmPoints += RPbonus;
  1509. }
  1510. if (CLAIM_LOGGING)
  1511. log.Info("ClaimBonus: Player=" + pl.Name + " Acc: " + pl.Client.Account.Name + " Guild: " + pl.Guild.Name + " HasClaimed: " + keep.Name + " RP/BP Bonus: " + RPbonus.ToString() + " / " + BPbonus.ToString());
  1512.  
  1513. return;
  1514. }
  1515.  
  1516. #endregion GuildClaimBonus
  1517.  
  1518. #endregion
  1519. }
  1520. }
  1521.  
  1522. #region send name-coloring on regionchanged
  1523.  
  1524. namespace DOL.GS.GameEvents
  1525. {
  1526. /// <summary>
  1527. ///
  1528. /// </summary>
  1529. public class ColorHandlingRegionChangedEvent
  1530. {
  1531. /// <summary>
  1532. /// Defines a logger for this class.
  1533. /// </summary>
  1534. public static readonly ILog LOG = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  1535.  
  1536. /// <summary>
  1537. /// Event handler fired when server is started
  1538. /// </summary>
  1539. [GameServerStartedEvent]
  1540. public static void OnServerStart(DOLEvent e, object sender, EventArgs arguments)
  1541. {
  1542. GameEventMgr.AddHandler(GamePlayerEvent.RegionChanged, new DOLEventHandler(PlayerRegionChanged));
  1543. GameEventMgr.AddHandler(GamePlayerEvent.GameEntered, new DOLEventHandler(PlayerGameEntered));
  1544. }
  1545.  
  1546. /// <summary>
  1547. /// Event handler fired when server is stopped
  1548. /// </summary>
  1549. [GameServerStoppedEvent]
  1550. public static void OnServerStop(DOLEvent e, object sender, EventArgs arguments)
  1551. {
  1552. GameEventMgr.RemoveHandler(GamePlayerEvent.RegionChanged, new DOLEventHandler(PlayerRegionChanged));
  1553. GameEventMgr.RemoveHandler(GamePlayerEvent.GameEntered, new DOLEventHandler(PlayerGameEntered));
  1554. }
  1555.  
  1556. private static void ResetColorHandling(GamePlayer player)
  1557. {
  1558. if (player == null) return;
  1559. lock (player)
  1560. {
  1561. player.Out.SendLoginGranted();
  1562. player.Out.SendLevelUpSound();
  1563. }
  1564. }
  1565.  
  1566. private static void CheckGroup(GamePlayer player)
  1567. {
  1568. if (player == null || player.Group == null) return;
  1569. lock (player)
  1570. {
  1571. foreach (GamePlayer p in player.Group.GetPlayersInTheGroup())
  1572. if (p != null
  1573. && p != player
  1574. && !GameServer.ServerRules.IsAllowedToGroup(p, player, true))
  1575. {
  1576. player.Group.SendMessageToGroupMembers("You are not allowed to group other realmmates here!", eChatType.CT_Important, eChatLoc.CL_ChatWindow);
  1577. player.Group.RemoveMember(player);
  1578. break;
  1579. }
  1580. }
  1581. }
  1582.  
  1583. /// <summary>
  1584. /// Event handler fired when players changed region
  1585. /// </summary>
  1586. /// <param name="e"></param>
  1587. /// <param name="sender"></param>
  1588. /// <param name="arguments"></param>
  1589. private static void PlayerRegionChanged(DOLEvent e, object sender, EventArgs arguments)
  1590. {
  1591. ResetColorHandling(sender as GamePlayer);
  1592. CheckGroup(sender as GamePlayer);
  1593. }
  1594.  
  1595. /// <summary>
  1596. /// Event handler fired when players enters the game
  1597. /// </summary>
  1598. /// <param name="e"></param>
  1599. /// <param name="sender"></param>
  1600. /// <param name="arguments"></param>
  1601. private static void PlayerGameEntered(DOLEvent e, object sender, EventArgs arguments)
  1602. {
  1603. ResetColorHandling(sender as GamePlayer);
  1604. }
  1605. }
  1606. }
  1607.  
  1608. #endregion
  1609.  
  1610. #region special examine-handling for safe-zones
  1611.  
  1612. namespace DOL.GS.PacketHandler.Client.v168
  1613. {
  1614. /// <summary>
  1615. /// Handles player target changes
  1616. /// </summary>
  1617. [PacketHandlerAttribute(PacketHandlerType.TCP, 0x18 ^ 168, "Handles player target changes")]
  1618. public class TCPlayerTargetHandler : IPacketHandler
  1619. {
  1620. public void HandlePacket(GameClient client, GSPacketIn packet)
  1621. {
  1622. ushort targetID = packet.ReadShort();
  1623. ushort flags = packet.ReadShort();
  1624. /*
  1625. * 0x8000 = 'examine' bit
  1626. * 0x4000 = LOS1 bit; is 0 if no LOS
  1627. * 0x2000 = LOS2 bit; is 0 if no LOS
  1628. * 0x0001 = players attack mode bit (not targets!)
  1629. */
  1630.  
  1631. ChangeTargetAction action = new ChangeTargetAction(
  1632. client.Player,
  1633. targetID,
  1634. !((flags & (0x4000 | 0x2000)) == 0),
  1635. (flags & 0x8000) != 0);
  1636.  
  1637. action.Start(1);
  1638.  
  1639.  
  1640. }
  1641.  
  1642.  
  1643. /// <summary>
  1644. /// Handles every received packet
  1645. /// </summary>
  1646. /// <param name="client">The client that sent the packet</param>
  1647. /// <param name="packet">The received packet data</param>
  1648. /// <returns></returns>
  1649.  
  1650.  
  1651. /// <summary>
  1652. /// Changes players target
  1653. /// </summary>
  1654. protected class ChangeTargetAction : RegionAction
  1655. {
  1656. /// <summary>
  1657. /// The new target OID
  1658. /// </summary>
  1659. protected readonly int m_newTargetId;
  1660. /// <summary>
  1661. /// The 'target in view' flag
  1662. /// </summary>
  1663. protected readonly bool m_targetInView;
  1664. /// <summary>
  1665. /// The 'examine target' bit
  1666. /// </summary>
  1667. protected readonly bool m_examineTarget;
  1668.  
  1669. /// <summary>
  1670. /// Constructs a new TargetChangeAction
  1671. /// </summary>
  1672. /// <param name="actionSource">The action source</param>
  1673. /// <param name="newTargetId">The new target OID</param>
  1674. /// <param name="targetInView">The target LOS bit</param>
  1675. /// <param name="examineTarget">The 'examine target' bit</param>
  1676. public ChangeTargetAction(GamePlayer actionSource, int newTargetId, bool targetInView, bool examineTarget)
  1677. : base(actionSource)
  1678. {
  1679. m_newTargetId = newTargetId;
  1680. m_targetInView = targetInView;
  1681. m_examineTarget = examineTarget;
  1682. }
  1683.  
  1684. /// <summary>
  1685. /// Called on every timer tick
  1686. /// </summary>
  1687. protected override void OnTick()
  1688. {
  1689. GamePlayer player = (GamePlayer)m_actionSource;
  1690.  
  1691. GameObject myTarget = player.CurrentRegion.GetObject((ushort)m_newTargetId);
  1692. player.TargetObject = myTarget;
  1693. player.TargetInView = m_targetInView;
  1694.  
  1695. if (myTarget != null)
  1696. {
  1697. // Send target message text only if 'examine' bit is set.
  1698. if (m_examineTarget)
  1699. {
  1700. IList messages = myTarget.GetExamineMessages(player);
  1701. if (myTarget is GamePlayer)
  1702. {
  1703. GamePlayer targetPlayer = myTarget as GamePlayer;
  1704. if (player.Client.Account.PrivLevel < (uint)ePrivLevel.GM
  1705. && targetPlayer.Client.Account.PrivLevel < (uint)ePrivLevel.GM)
  1706. {
  1707. if (TCServerRules.IsSafeZone(myTarget.CurrentRegionID))
  1708. {
  1709. messages.RemoveAt(messages.Count - 1);
  1710. messages.Add(string.Format(LanguageMgr.GetTranslation(player.Client, "GamePlayer.GetExamineMessages.RealmMember", player.GetName(targetPlayer), targetPlayer.GetPronoun(player.Client, 0, true), targetPlayer.CharacterClass.Name)));
  1711. }
  1712. else if (TCServerRules.IsPvEZone(myTarget.CurrentRegionID))
  1713. {
  1714. messages.RemoveAt(messages.Count - 1);
  1715. messages.Add(string.Format(LanguageMgr.GetTranslation(player.Client, "GamePlayer.GetExamineMessages.RealmMember", player.GetName(targetPlayer), targetPlayer.GetPronoun(player.Client, 0, true), targetPlayer.CharacterClass.Name)));
  1716. }
  1717. else if (TCServerRules.IsPvPZone(myTarget.CurrentRegionID))
  1718. {
  1719. messages.RemoveAt(messages.Count - 1);
  1720. messages.Add(string.Format(LanguageMgr.GetTranslation(player.Client, "GamePlayer.GetExamineMessages.RealmMember", player.GetName(targetPlayer), targetPlayer.GetPronoun(player.Client, 0, true), targetPlayer.CharacterClass.Name)));
  1721. }
  1722. }// if both players are no GMs
  1723. }// if myTarget is GamePlayer
  1724.  
  1725. foreach (string message in messages)
  1726. {
  1727. player.Out.SendMessage(message, eChatType.CT_System, eChatLoc.CL_SystemWindow);
  1728. }
  1729. }
  1730. // Then no LOS message; not sure which bit to use so use both :)
  1731. // should be sent if targeted is using group panel to change the target
  1732. if (!m_targetInView)
  1733. {
  1734. player.Out.SendMessage("Target is not in view.", eChatType.CT_System, eChatLoc.CL_SystemWindow);
  1735. }
  1736.  
  1737. player.Out.SendObjectUpdate(myTarget);
  1738. }
  1739.  
  1740. if (player.IsPraying)
  1741. {
  1742. GameGravestone gravestone = myTarget as GameGravestone;
  1743. if (gravestone == null || !gravestone.InternalID.Equals(player.InternalID))
  1744. {
  1745. player.Out.SendMessage("You are no longer targetting your grave. Your prayers fail.", eChatType.CT_System, eChatLoc.CL_SystemWindow);
  1746. player.PrayTimerStop();
  1747. }
  1748. }
  1749. }
  1750. }
  1751.  
  1752.  
  1753. }
  1754. }
  1755.  
  1756.  
  1757. #endregion
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement