1. local npc_id = 0;
  2. --[[
  3. cost_type
  4. 1 - gold
  5. 2 - item
  6. ]]
  7. local cost_type = 1;
  8. --[[
  9. price based on what option you set 'cost_type' to.
  10. 1 - amount in gold
  11. 2 - amount of items of 'item_entry'
  12. ]]
  13. local price = 5;
  14. --[[
  15. item_name, used for the message.
  16. Only set this if you set 'cost_type' to 2 (item).
  17. ]]
  18. local item_name = "";
  19. --[[
  20. item entry, only set this if you set 'cost_type' to 2 (item).
  21. ]]
  22. local item_entry = 0;
  23. --[[
  24. interval, the amount of seconds for a game to finish.
  25. ]]
  26. local interval = 30;
  27. --[[
  28. Script
  29. ]]
  30. local rps = {};
  31. -- Messages
  32. local message_cost = "Cost: %s %s";
  33. local message_attribute = "%s%s chose: %s";
  34. -- Event constant
  35. local PLAYER_EVENT_ON_COMMAND = 42;
  36. -- 'cost_type' constants
  37. local COST_TYPE_GOLD = 1;
  38. local COST_TYPE_ITEM = 2;
  39. -- Attributes the player can choose from.
  40. local attributes = {"rock", "paper", "scissors"};
  41. local function isAttribute(command)
  42. for _, attribute in ipairs(attributes) do
  43. if command == attribute then return true; end
  44. end
  45. return false;
  46. end
  47. -- Might as well do the calculation here.
  48. local copper = cost_type == COST_TYPE_GOLD and price * 10000 or price;
  49. local cost_name = cost_type == COST_TYPE_GOLD and "gold" or item_name;
  50. interval = interval * 1000;
  51. -- Conditions
  52. local conditions = {
  53. ["rockscissors"] = true,
  54. ["rockpaper"] = false,
  55. ["scissorspaper"] = true,
  56. ["scissorsrock"] = false,
  57. ["paperrock"] = true,
  58. ["paperscissors"] = false
  59. };
  60. -- Crazy knockback spell.
  61. local SPELL_KNOCK_BACK = 70966;
  62. -- Function to take and give 'cost_type'.
  63. local function modify(player, amount)
  64. if cost_type == COST_TYPE_ITEM then
  65. if (amount < 0) then
  66. player:RemoveItem(item_entry, math.abs(amount));
  67. else--[[if amount > 0]]
  68. player:AddItem(item_entry, amount);
  69. end
  70. elseif cost_type == COST_TYPE_GOLD then
  71. player:ModifyMoney(amount);
  72. end
  73. end
  74. -- Method to check if the player has the right amount of currency.
  75. local function check(player)
  76. if cost_type == COST_TYPE_GOLD then
  77. return player:GetCoinage() >= copper;
  78. elseif cost_type == COST_TYPE_ITEM then
  79. return player:HasItem(item_entry, price);
  80. end
  81. return false;
  82. end
  83. -- Condition functions
  84. local function win(player)
  85. modify(player, copper);
  86. end
  87. local function lose(player)
  88. player:CastSpell(player, SPELL_KNOCK_BACK);
  89. modify(player, -copper);
  90. end
  91. local function tie(player)
  92. -- Nothing happends.
  93. end
  94. -- Event that handles the game.
  95. local function handle_rps(event_id, _, _, creature)
  96. local creature_attribute = attributes[math.random(#attributes)];
  97. for _, player_data in ipairs(rps[creature:GetGUIDLow()]) do
  98. local player = GetPlayerByGUID(player_data.guid);
  99. if player ~= nil and player:GetMapId() == creature:GetMapId() or creature:GetDistance(player) <= 40 then
  100. local player_attribute = player_data.attribute;
  101. local condition = conditions[player_attribute..creature_attribute];
  102. if condition == nil then
  103. tie(player);
  104. elseif condition then
  105. win(player);
  106. else
  107. lose(player);
  108. end
  109. end
  110. end
  111. rps[creature:GetGUIDLow()] = nil;
  112. creature:SendUnitSay(string.format(message_attribute, "", "I", creature_attribute), 0)
  113. end
  114. -- Function that adds a player to the table.
  115. local function findPlayer(creature, player)
  116. local lowGuid = player:GetGUIDLow();
  117. for _, player_data in ipairs(rps[creature:GetGUIDLow()]) do
  118. if player_data.guid == lowGuid then return true; end
  119. end
  120. return false;
  121. end
  122. local function addPlayer(creature, player, command)
  123. if not findPlayer(creature, player) then
  124. table.insert(rps[creature:GetGUIDLow()], {
  125. guid = player:GetGUIDLow(),
  126. attribute = command
  127. });
  128. return true;
  129. end
  130. return false;
  131. end
  132. -- Function to create the table if needed, and to register the event.
  133. local function creatureAddPlayer(creature, player, command)
  134. if rps[creature:GetGUIDLow()] == nil then
  135. rps[creature:GetGUIDLow()] = {
  136. -- Apparently we don't need this.
  137. --event = creature:RegisterEvent(handle_rps, 30000, 0),
  138. --players = {}
  139. };
  140. creature:RegisterEvent(handle_rps, interval, 1);
  141. end
  142. return addPlayer(creature, player, command);
  143. end
  144. -- Command handler
  145. local function onCommand(_, player, command)
  146. command = string.lower(command);
  147. if isAttribute(command) then
  148. if not check(player) then
  149. player:SendBroadcastMessage(string.format(message_cost, price, cost_name));
  150. return false;
  151. end
  152. local creature = player:GetSelection();
  153. if creature == nil or creature:GetEntry() ~= npc_id then
  154. return false;
  155. end
  156. if creatureAddPlayer(creature, player, command) then
  157. for _, plr in ipairs(player:GetPlayersInRange(40)) do
  158. plr:SendBroadcastMessage(string.format(message_attribute, "|cFFFF8040", player:GetName(), command));
  159. end
  160. player:SendBroadcastMessage(string.format(message_attribute, "|cFFFF8040", "You", command));
  161. end
  162. return false;
  163. end
  164. end
  165. RegisterPlayerEvent(PLAYER_EVENT_ON_COMMAND, onCommand);