You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. --[[
  2. Turn-In Mod
  3. version 2.0
  4. Authored by Ian Friedman
  5. Sabindeus of Smolderthorn/Andre of Argent Dawn (Alliance)
  6. The repeatable quest turn in automating machine.
  7. todo:
  8. make selection work for multiple active quests
  9. ]]
  10. TI_VersionString = "2.0";
  11. local TI_slashtable;
  12. TI_gossipclosed = false;
  13. TI_LoadedNPCIndex = 0;
  14. TI_activenumber = 1;
  15. TI_availnumber = 1;
  16. TI_specnum = 0;
  17. TI_gossipopts = {};
  18. TI_TempNPCList = {};
  19. TI_TempNPCListMaxSize = 5;
  20. TI_NPCInQuestion = nil;
  21. local TI_GossipDefaults = {
  22. availquest ="Available Quests",
  23. activequest = "Active Quests",
  24. gossip = "Gossip",
  25. vendor = "Vendor",
  26. taxi = "Taxi",
  27. trainer = "Trainer",
  28. battlemaster = "Battlemaster",
  29. binder = "Hearthstone Binder",
  30. healer = "Spirit Healer",
  31. banker = "Bank"
  32. };
  33. local TI_FunctionList = {
  34. g = {
  35. availquest = SelectGossipAvailableQuest,
  36. activequest = SelectGossipActiveQuest,
  37. default = SelectGossipOption
  38. },
  39. q = {
  40. availquest = SelectAvailableQuest,
  41. activequest = SelectActiveQuest
  42. }
  43. };
  44. local TI_DefaultStatus = {
  45. state = false,
  46. version = TI_VersionString,
  47. options = {},
  48. debugstate = false,
  49. usedefault=true,
  50. autoadd=false
  51. };
  52. local TI_events = {
  53. "GOSSIP_SHOW",
  54. "GOSSIP_CLOSED",
  55. "QUEST_DETAIL",
  56. "QUEST_COMPLETE",
  57. "QUEST_PROGRESS",
  58. "QUEST_GREETING",
  59. "QUEST_FINISHED"
  60. };
  61. TI_TempNPCList = {};
  62. function TI_message(...)
  63. local x = {...};
  64. for k,v in pairs(x) do
  65. DEFAULT_CHAT_FRAME:AddMessage(tostring(v));
  66. end
  67. end
  68. function TI_debug(...)
  69. if(TI_status.debugstate) then
  70. TI_message(...)
  71. end
  72. end
  73. function TI_OnLoad()
  74. SlashCmdList["TI"]=TI_SlashCmdHandler;
  75. SLASH_TI1="/turnin";
  76. SLASH_TI2="/ti";
  77. tinsert(UISpecialFrames,"TI_OptionsFrame");
  78. TI_message("Turn In loaded");
  79. TI_slashtable = {};
  80. TI_gossipopts = {};
  81. TI_gossipclosed = false;
  82. TurnIn:RegisterEvent("VARIABLES_LOADED");
  83. TI_activenumber = 1;
  84. TI_availnumber = 1;
  85. TI_specnum = 0;
  86. StaticPopupDialogs["TI_NPCINQUESTION"] = {
  87. text = "The NPC %s is already in your NPC Database. Do you wish to replace his gossip options with the current ones? (Note: This will overwrite your settings for this NPC.)",
  88. button1 = "Yes",
  89. button2 = "No",
  90. OnAccept = function()
  91. TI_AddNPCToList(TI_NPCInQuestion.list, TI_NPCInQuestion.name, true);
  92. end,
  93. timeout=0,
  94. whileDead = 1,
  95. hideOnEscape = 1
  96. };
  97. end
  98. function TI_VarInit()
  99. if(not TI_status or TI_status.version ~= TI_VersionString) then
  100. TI_status = TI_copyTable(TI_DefaultStatus);
  101. TI_OptionsInit();
  102. end
  103. if(not TI_status.options or #TI_status.options == 0) then
  104. TI_OptionsInit();
  105. end
  106. if(not TI_NPCDB) then
  107. TI_NPCDB = {};
  108. end
  109. if(not TI_NPCIndex) then
  110. TI_NPCIndexGenerate();
  111. end
  112. TI_PopulateOptions("vars loaded");
  113. end
  114. function TI_OptionsInit()
  115. TI_status.options = {};
  116. for k,v in pairs(TI_GossipDefaults) do
  117. local temp = {};
  118. temp.name = v;
  119. temp.type = k;
  120. temp.state = false;
  121. table.insert(TI_status.options, temp);
  122. end
  123. end
  124. function TI_NPCIndexGenerate()
  125. TI_NPCIndex = {};
  126. for k,v in pairs(TI_NPCDB) do
  127. table.insert(TI_NPCIndex, k);
  128. end
  129. table.sort(TI_NPCIndex);
  130. end
  131. function TI_LoadEvents()
  132. for k,v in pairs(TI_events) do
  133. TurnIn:RegisterEvent(v);
  134. end
  135. end
  136. function TI_ResetPointers()
  137. TI_activenumber = 1;
  138. TI_availnumber = 1;
  139. TI_specnum = 0;
  140. end
  141. function TI_UnloadEvents()
  142. for k,v in pairs(TI_events) do
  143. TurnIn:UnregisterEvent(v);
  144. end
  145. end
  146. function TI_Switch(state)
  147. if(state=="on") then
  148. TI_status.state = true;
  149. TI_LoadEvents();
  150. TI_message("Turn In On");
  151. elseif(state=="off") then
  152. TI_ResetPointers();
  153. TI_status.state = false;
  154. TI_UnloadEvents();
  155. TI_message("Turn In Off");
  156. elseif(state=="toggle") then
  157. if(TI_status.state) then
  158. TI_Switch("off");
  159. else
  160. TI_Switch("on");
  161. end
  162. end
  163. TI_StatusIndicatorUpdate();
  164. end
  165. function TI_SlashCmdHandler(cmd)
  166. cmdlist = {strsplit(" ", cmd)};
  167. local commands = {
  168. on = function ()
  169. TI_Switch("on");
  170. end,
  171. off = function ()
  172. TI_Switch("off");
  173. end,
  174. toggle = function ()
  175. TI_Switch("toggle");
  176. end,
  177. status = function ()
  178. if(TI_status.state) then
  179. TI_message("Turn In On");
  180. else
  181. TI_message("Turn In Off");
  182. end
  183. TI_message(string.format("Option Number set to %d", TI_status.qnum));
  184. end,
  185. window = function ()
  186. TI_OptionsFrame:Show();
  187. end,
  188. recent = function ()
  189. TI_TempNPCListWindow:Show();
  190. end,
  191. debug = function ()
  192. if(TI_status.debugstate) then
  193. TI_status.debugstate = false;
  194. TI_message("debug mode off");
  195. else
  196. TI_status.debugstate = true;
  197. TI_message("debug mode on");
  198. end
  199. end
  200. };
  201. if(commands[cmdlist[1]]) then
  202. commands[cmdlist[1]](cmdlist[2], cmdlist[3], cmdlist[4]);
  203. else
  204. TI_message("Turn In 2.0 Help", "--------------", "/ti on - turns Turn In on", "/ti off - turns Turn In off", "/ti toggle - toggles Turn In on or off", "/ti window - shows the options window", "/ti recent - shows the recently visited NPCs");
  205. end
  206. end
  207. function TI_IsNPCOn(npcname, type)
  208. local opton = false;
  209. if(type ~= nil) then
  210. for k,v in pairs(TI_status.options) do
  211. if(v.type == type and v.state == true) then
  212. opton = true;
  213. end
  214. end
  215. else
  216. opton = true;
  217. end
  218. if(TI_NPCDB[npcname] == nil and TI_status.usedefault == true and opton == true) then
  219. TI_debug("case 1");
  220. return true;
  221. elseif(TI_NPCDB[npcname] ~= nil and TI_NPCDB[npcname].state) then
  222. TI_debug("case 2");
  223. return true;
  224. elseif(TI_NPCDB[npcname] ~= nil and TI_status.usedefault == true and not TI_NPCDB[npcname].state and opton == true) then
  225. TI_debug("case 4");
  226. return true;
  227. else
  228. TI_debug("case 3");
  229. return false;
  230. end
  231. end
  232. function TI_OnEvent(event)
  233. if(event == "VARIABLES_LOADED") then
  234. TI_VarInit();
  235. if(TI_status.state) then
  236. TI_LoadEvents();
  237. end
  238. end
  239. if(TI_status.state and not IsShiftKeyDown()) then
  240. if(event == "QUEST_GREETING") then
  241. TI_debug("Quest Greeting");
  242. TI_lastquestframe = "greeting";
  243. if(QuestFrame:IsVisible()) then
  244. if(TI_gossipclosed) then
  245. TI_debug("resetting pointers");
  246. TI_gossipclosed = false;
  247. TI_ResetPointers();
  248. end
  249. TI_HandleGossipWindow("q");
  250. end
  251. end
  252. if(event == "GOSSIP_SHOW") then
  253. TI_debug("Gossip Show");
  254. if(GossipFrame:IsVisible()) then
  255. if(TI_gossipclosed) then
  256. TI_debug("resetting pointers");
  257. TI_gossipclosed = false;
  258. TI_ResetPointers();
  259. end
  260. TI_HandleGossipWindow("g");
  261. end
  262. end
  263. if(event == "GOSSIP_CLOSED") then
  264. TI_debug("Gossip Closed");
  265. if(not GossipFrame:IsVisible()) then
  266. TI_gossipclosed = true;
  267. end;
  268. end
  269. if(event == "QUEST_COMPLETE") then
  270. TI_debug("Quest Complete");
  271. if(TI_IsNPCOn(UnitName("npc"), "activequest")) then
  272. if(not (GetNumQuestChoices() > 1)) then
  273. GetQuestReward(1);
  274. end
  275. end
  276. TI_ResetPointers();
  277. end
  278. if(event == "QUEST_PROGRESS") then
  279. TI_debug("Quest Progress");
  280. TI_gossipclosed = false;
  281. TI_lastquestframe = "progress";
  282. TI_HandleQuestProgress();
  283. end
  284. if(event == "QUEST_DETAIL") then
  285. TI_debug("Quest Detail");
  286. TI_gossipclosed = false;
  287. if(TI_IsNPCOn(UnitName("npc"), "availquest")) then
  288. AcceptQuest();
  289. end
  290. TI_ResetPointers();
  291. end
  292. if(event == "QUEST_FINISHED") then
  293. TI_debug("Quest Finished");
  294. if(not QuestFrame:IsVisible() and TI_lastquestframe == "greeting") then
  295. TI_debug("looks like the quest frame closed, resetting pointers on next open");
  296. TI_gossipclosed = true;
  297. end
  298. end
  299. end
  300. end
  301. function TI_HandleQuestProgress()
  302. local questname = GetTitleText();
  303. local npcname = UnitName("npc");
  304. if(QuestFrame:IsVisible()) then
  305. if(TI_NPCDB[npcname]) then
  306. local thisnpc = TI_NPCDB[npcname];
  307. if(thisnpc.state) then
  308. for i,current in ipairs(thisnpc) do
  309. if(current.name == questname and current.state) then
  310. TI_CompleteQuest();
  311. end
  312. end
  313. else
  314. if(TI_IsNPCOn(UnitName("npc"), "activequest")) then
  315. TI_CompleteQuest();
  316. end
  317. end
  318. else
  319. if(TI_IsNPCOn(UnitName("npc"), "activequest")) then
  320. TI_CompleteQuest();
  321. end
  322. end
  323. end
  324. end
  325. function TI_CompleteQuest()
  326. if(IsQuestCompletable()) then
  327. CompleteQuest();
  328. TI_ResetPointers();
  329. else
  330. DeclineQuest();
  331. end
  332. end
  333. function TI_GetQuests(type)
  334. local numQuests = (getglobal("GetNum"..type.."Quests"))();
  335. local qfn = getglobal("Get"..type.."Title");
  336. local ret = {};
  337. local qname;
  338. local i=1;
  339. for i=1,numQuests do
  340. qname = qfn(i);
  341. ret[i] = {name=qname};
  342. end
  343. return ret;
  344. end
  345. function TI_HandleGossipWindow(gorq)
  346. local SAcQ;
  347. local SAvQ;
  348. local AvailableQuests;
  349. local ActiveQuests;
  350. local GossipOptions;
  351. if(gorq == "g") then
  352. AvailableQuests = TI_Tabulate(GetGossipAvailableQuests());
  353. ActiveQuests = TI_Tabulate(GetGossipActiveQuests());
  354. GossipOptions = TI_Tabulate(GetGossipOptions());
  355. SAcQ = SelectGossipActiveQuest;
  356. SAvQ = SelectGossipAvailableQuest;
  357. elseif(gorq == "q") then
  358. AvailableQuests = TI_GetQuests("Available");
  359. ActiveQuests = TI_GetQuests("Active");
  360. GossipOptions = {};
  361. SAcQ=SelectActiveQuest;
  362. SAvQ=SelectAvailableQuest;
  363. end
  364. local ListEntry = {};
  365. for i,v in ipairs(AvailableQuests) do
  366. local x={};
  367. x.name = v.name;
  368. x.gorq = gorq;
  369. x.args = i;
  370. x.type = "availquest";
  371. x.state = false;
  372. table.insert(ListEntry, x);
  373. end
  374. for i,v in ipairs(ActiveQuests) do
  375. local x={};
  376. x.name = v.name;
  377. x.gorq = gorq;
  378. x.args = i;
  379. x.type = "activequest";
  380. x.state = false;
  381. table.insert(ListEntry, x);
  382. end
  383. for i,v in ipairs(GossipOptions) do
  384. local x={};
  385. x.name = v.name;
  386. x.gorq = gorq;
  387. x.args = i;
  388. x.type = v.type;
  389. x.state = false;
  390. table.insert(ListEntry, x);
  391. end
  392. ListEntry.state = false;
  393. local TotalOptions = #AvailableQuests+#ActiveQuests+#GossipOptions;
  394. --if(TI_activenumber > ActiveQuests.getn()) TI_activenumber = 1;
  395. if(TotalOptions < 1) then
  396. return;
  397. end
  398. local name = UnitName("npc");
  399. TI_AddNPCToTempList(name, ListEntry);
  400. if(TI_status.autoadd and (not TI_NPCDB[name])) then
  401. TI_debug("autoadd on, adding this NPC", TI_status.autoadd, TI_NPCDB[name]);
  402. TI_AddNPCToList(ListEntry, name);
  403. end
  404. if(TI_availnumber > TotalOptions or TI_activenumber > TotalOptions) then
  405. TI_ResetPointers();
  406. return;
  407. end
  408. --Legacy shit here
  409. --[[
  410. if(TI_status.qnum ~= 0 and TI_status.qnum<TotalOptions) then
  411. if(TI_status.qnum <= #AvailableQuests) then
  412. SAvQ(TI_status.qnum);
  413. return;
  414. elseif(TI_status.qnum <= #AvailableQuests+#ActiveQuests) then
  415. SAcQ(TI_status.qnum-AvailableQuests.n);
  416. return;
  417. elseif(TI_status.qnum <= #AvailableQuests+#ActiveQuests+#GossipOptions) then
  418. SelectGossipOption(TI_status.qnum-#AvailableQuests-#ActiveQuests);
  419. return;
  420. end
  421. end
  422. ]]--
  423. local npcname = UnitName("npc");
  424. TI_debug(npcname);
  425. if(TI_NPCDB[npcname]) then
  426. local thisnpc = TI_NPCDB[npcname];
  427. if(thisnpc.state) then
  428. TI_debug("npc is active, using his options");
  429. for i,current in ipairs(thisnpc) do
  430. TI_debug(i);
  431. if(current.state) then
  432. if (TI_specnum == 0 or i > TI_specnum) then
  433. TI_specnum = i;
  434. TI_debug("Setting specnum to "..TI_specnum.." nothing under that will be picked");
  435. local flist = TI_FunctionList[current.gorq];
  436. if(flist[current.type]) then
  437. flist[current.type](current.args);
  438. else
  439. flist["default"](current.args);
  440. end
  441. return;
  442. end
  443. end
  444. end
  445. return;
  446. else
  447. TI_debug("npc in list, but not active");
  448. end
  449. else
  450. TI_debug("npc not in list");
  451. end
  452. if(TI_status.usedefault == false) then
  453. TI_debug("npc not in list, default set to off, returning.");
  454. return;
  455. end;
  456. TI_debug("using default config");
  457. for i,current in ipairs(TI_status.options) do
  458. if(current.state) then
  459. if(current.type == "availquest" and #AvailableQuests > 0 and TI_availnumber <= #AvailableQuests) then
  460. TI_availnumber = TI_availnumber + 1;
  461. SAvQ(TI_availnumber-1);
  462. TI_debug("Selecting Available Quest ".. TI_availnumber-1);
  463. return;
  464. elseif(current.type == "activequest" and #ActiveQuests > 0 and TI_activenumber <= #ActiveQuests) then
  465. TI_activenumber = TI_activenumber + 1;
  466. SAcQ(TI_activenumber-1);
  467. TI_debug("Selecting Active Quest ".. TI_activenumber-1);
  468. return;
  469. elseif(#GossipOptions > 0) then
  470. for j,val in ipairs(GossipOptions) do
  471. if(val.type == current.type) then
  472. TI_ResetPointers();
  473. SelectGossipOption(j);
  474. return;
  475. end
  476. end
  477. end
  478. end
  479. end
  480. end
  481. function TI_AddNPCToList(OptList, npcname, confirminquestion)
  482. --~ NPClist = {
  483. --~ "Joe" = {
  484. --~ 0 = {
  485. --~ name = "Option 1"
  486. --~ accessor = SelectGossipOption
  487. --~ args = 0
  488. --~ }
  489. --~ }
  490. --~ }
  491. if (npcname == nil) then
  492. npcname = UnitName("npc");
  493. end
  494. if(#OptList > 0) then
  495. if(TI_NPCDB[npcname] == nil) then
  496. TI_NPCDB[npcname] = TI_copyTable(OptList);
  497. table.insert(TI_NPCIndex, npcname);
  498. table.sort(TI_NPCIndex);
  499. TI_PopulateOptions("npclist updated");
  500. elseif(confirminquestion == true) then
  501. TI_NPCDB[npcname] = TI_copyTable(OptList);
  502. TI_PopulateOptions("npclist updated");
  503. else
  504. TI_NPCInQuestion = {name=npcname, list=OptList};
  505. StaticPopup_Show("TI_NPCINQUESTION", npcname);
  506. end
  507. end
  508. end
  509. function TI_AddNPCToTempList(name, list)
  510. local temp = {};
  511. temp.name = name;
  512. temp.list = list;
  513. temp.location = GetSubZoneText() .. ", " .. GetRealZoneText();
  514. table.insert(TI_TempNPCList, 1, temp);
  515. if(#TI_TempNPCList > TI_TempNPCListMaxSize) then
  516. table.remove(TI_TempNPCList, TI_TempNPCListMaxSize);
  517. end
  518. TI_TempNPCListUpdate();
  519. end
  520. function TI_DeleteTempNPCIndex(index)
  521. table.remove(TI_TempNPCList, index);
  522. TI_TempNPCListUpdate();
  523. end
  524. function TI_AddTempNPCIndex(index)
  525. TI_AddNPCToList(TI_TempNPCList[index].list, TI_TempNPCList[index].name);
  526. end
  527. function TI_DeleteNPC(index)
  528. local name = TI_NPCIndex[index];
  529. table.remove(TI_NPCIndex, index);
  530. TI_NPCDB[name] = nil;
  531. end
  532. function TI_StripDescriptors(...)
  533. local x = {};
  534. local arg = {...};
  535. for i=1, #arg, 2 do
  536. table.insert(x,arg[i]);
  537. end
  538. return x;
  539. end
  540. function TI_Tabulate(...)
  541. local x = {};
  542. local arg = {...};
  543. for i=1, #arg, 2 do
  544. local temp = {};
  545. temp.name = arg[i];
  546. temp.type = arg[i+1];
  547. table.insert(x, temp);
  548. end
  549. return x;
  550. end
  551. --[[this function stolen from WhisperCast by Sarris, whom I love dearly for his contribution to Paladins everywhere.
  552. ]]
  553. function TI_copyTable( src )
  554. local copy = {}
  555. for k1,v1 in pairs(src) do
  556. if ( type(v1) == "table" ) then
  557. copy[k1]=TI_copyTable(v1)
  558. else
  559. copy[k1]=v1
  560. end
  561. end
  562. return copy
  563. end
  564. function toggle(arg)
  565. if(arg) then
  566. return false;
  567. else
  568. return true;
  569. end
  570. end