· 7 years ago · Feb 04, 2019, 01:02 PM
1--
2-- Created by CLion.
3-- User: leonardopereira
4-- Date: 17/01/18
5-- Time: 15:30
6--
7
8--[[
9-- LANES =
10 -- Free Account Players
11 1- Choose 5 runes or potions.
12 2- Choose 5 runes or potions.
13 3- One Prey Bonus Rerolls.
14 4- Choose 10 runes or potions.
15 5- Choose 10 runes or potions.
16 6- One temporary Gold Converter with 100 charges.
17 7- 10 minutes 50% XP Boost.
18
19 -- Premium Players
20 1. Choose 10 runes or potions.
21 2. Choose 10 runes or potions.
22 3. Two Prey Bonus Rerolls.
23 4. Choose 20 runes or potions.
24 5. Choose 20 runes or potions.
25 6. One temporary Temple Teleport scroll and one temporary Gold Converter with 100 charges.
26 7. 30 minutes of 50% XP Boost.
27
28-- STREAKS
29-- 1. No bonus for the first day.
30 2. Allow hitpoints regeneration
31 3. Allow mana regeneration
32 4. Stamina regeneration (Premium only)
33 5. Double hitpoints regeneration (Premium only)
34 6. Double mana regeneration (Premium only)
35 7. Soul Points regeneration (Premium only)
36-- ]]
37
38REWARD_TYPE_RUNE_POT = 1
39REWARD_TYPE_PREY_REROLL = 2
40REWARD_TYPE_TEMPORARYITEM = 3
41REWARD_TYPE_XP_BOOST = 4
42
43local MODAL_STATE_MAINMENU = 1
44local MODAL_STATE_VIEWDAILYREWARD_LANE = 2
45local MODAL_STATE_VIEWSTREAKBONUSES_INDEX = 3
46local MODAL_STATE_VIEWSTREAKBONUSES_DETAILS = 4
47local MODAL_STATE_SELECTING_REWARD_ITEMS = 5
48local MODAL_STATE_CONFIRM_REWARD_PICK = 6
49local MODAL_STATE_VIEWREWARDHISTORY = 7
50local MODAL_STATE_VIEWREWARDHISTORY_DETAILS = 8
51
52local dailyRewardStates = {}
53local itemsCache = {}
54
55local potionsIds = {7588, 7589, 7590, 7591, 7618, 7620, 8472, 8473, 26029, 26030, 26031} -- since there's no GetPotionList on sources, this should solve the problem for now
56local rewardShrineIds ={
57 29612,29613,29544,29545,29546,29547
58}
59
60REWARD_LANE = {
61 FREE_ACC = {
62 {
63 description='Choose 5 runes or potions',
64 type = REWARD_TYPE_RUNE_POT,
65 ammount = 5,
66 available = {} --ids das potions e runas disponÃveis para escolher (Não Implementado)
67 },
68 {
69 description='Choose 5 runes or potions',
70 type = REWARD_TYPE_RUNE_POT,
71 ammount = 5,
72 available = {} --ids das potions e runas disponÃveis para escolher
73 },
74 {
75 description = 'One Prey Bonus Reroll',
76 type = REWARD_TYPE_PREY_REROLL,
77 ammount=1,
78 },
79 {
80 description='Choose 10 runes or potions',
81 type = REWARD_TYPE_RUNE_POT,
82 ammount = 10,
83 available = {} --ids das potions e runas disponÃveis para escolher
84 },
85 {
86 description='Choose 10 runes or potions',
87 type = REWARD_TYPE_RUNE_POT,
88 ammount = 10,
89 available = {} --ids das potions e runas disponÃveis para escolher
90 },
91 {
92 description = 'One temporary Gold Converter with 100 charges',
93 type = REWARD_TYPE_TEMPORARYITEM,
94 ammount = 1,
95 items = {
96 {id =29543, ammount=100}
97 },
98 expires = true
99 },
100 {
101 description = 'Ten minutes 50% XP Boost',
102 type = REWARD_TYPE_XP_BOOST,
103 ammount = 10, --*60 ?? xp boost é por minuto ou por segundo??
104 expires = true
105 }
106 },
107 PREMIUM_ACC = {
108 {
109 description='Choose 10 runes or potions',
110 type = REWARD_TYPE_RUNE_POT,
111 ammount = 10,
112 available = {} --ids das potions e runas disponÃveis para escolher
113 },
114 {
115 description='Choose 10 runes or potions',
116 type = REWARD_TYPE_RUNE_POT,
117 ammount = 10,
118 available = {} --ids das potions e runas disponÃveis para escolher
119 },
120 {
121 description = 'Two Prey Bonus Reroll',
122 type = REWARD_TYPE_PREY_REROLL,
123 ammount=2,
124 },
125 {
126 description='Choose 20 runes or potions',
127 type = REWARD_TYPE_RUNE_POT,
128 ammount = 20,
129 available = {} --ids das potions e runas disponÃveis para escolher
130 },
131 {
132 description='Choose 20 runes or potions',
133 type = REWARD_TYPE_RUNE_POT,
134 ammount = 20,
135 available = {} --ids das potions e runas disponÃveis para escolher
136 },
137 {
138 description = 'One temporary Temple Teleport scroll and one temporary Gold Converter with 100 charges.',
139 type = REWARD_TYPE_TEMPORARYITEM,
140 ammount = 1,
141 expires = true,
142 items = {
143 {id =29543, ammount=100},
144 {id =29542, ammount=1 }
145 }
146 },
147 {
148 description = 'Thirty minutes 50% XP Boost',
149 type = REWARD_TYPE_XP_BOOST,
150 ammount = 30, --*60 ?? xp boost é por minuto ou por segundo??
151 expires = true
152 }
153 }
154}
155
156REWARD_STREAK = {
157 {
158 days = 2,
159 description = 'Allow hitpoints regeneration',
160 fullDescription = 'This bonus grants you the ability of regenerate your hitpoints inside resting areas (affects all health regeneration from items/food).'
161 },
162 {
163 days = 3,
164 description = 'Allow mana regeneration',
165 fullDescription = 'This bonus grants you the ability of regenerate your mana inside resting areas (affects all mana regeneration from items/food).'
166 },
167 {
168 days = 4,
169 description = 'Stamina regeneration',
170 fullDescription = 'This bonus grants you the ability of regenerate your stamina inside resting areas. Just like if you were logged out.\n'..
171 '\nIf your stamina is below 40 hours, you recover 1 stamina minute for every 3 minutes inside resting areas;'..
172 '\nIf it is over 40 hours, you recover 1 stamina minute for every 10 minutes.',
173 premium = true
174 },
175 {
176 days = 5,
177 description = 'Double hitpoints regeneration',
178 fullDescription = 'Your current hitpoint regeneration inside resting areas is DOUBLED (affects all health regeneration from items/food).',
179 premium = true
180 },
181 {
182 days = 6,
183 description = 'Mana regeneration',
184 fullDescription = 'Your current mana regeneration inside resting areas is activated (affects all mana regeneration from items/food).',
185 premium = true
186 },
187 {
188 days = 7,
189 description = 'Soul Points regeneration',
190 fullDescription = 'This bonus grants you the ability of regenerate your soul points inside resting areas. Just like if you were killing creatures.'..
191 '\n- Regular characters regenerate 1 Soul point every 2 minutes;'..
192 '\n- Promoted characters regenerate 1 Soul point every 15 seconds;',
193 premium = true
194 }
195}
196
197--forward declared function names
198local getDefaultModalState --(player)
199local sendModalSelectRecursive --(player)
200local getChoiceModalState --(playerid, rewardAmmount)
201-- -----------------
202local function getHours(seconds)
203 return math.floor((seconds/60)/60)
204end
205
206local function getMinutes(seconds)
207 return math.floor(seconds/60)
208end
209
210local function getSeconds(seconds)
211 return seconds%60
212end
213local function getTimeinWords(secs)
214 local hours, minutes, seconds = getHours(secs), getMinutes(secs), getSeconds(secs)
215 if (minutes > 59) then
216 minutes = minutes-hours*60
217 end
218
219 local timeStr = ''
220
221 if hours > 0 then
222 timeStr = timeStr .. string.format('%d hour%s',hours,(hours > 1 and "s" or '') )
223 end
224
225 timeStr = timeStr .. string.format('%d minute%s and %d second%s',minutes,(minutes~=1 and "s" or ''), seconds, (seconds~=1 and 's' or ''))
226
227 return timeStr
228end
229
230local function getDefaultStateData(player, MODAL_STATE)
231 if not player then
232 return false
233 end
234
235 local statedata = {}
236 if MODAL_STATE == MODAL_STATE_MAINMENU then
237 statedata.playerid = player:getId()
238 statedata.title = "Reward Wall"
239
240
241 local currentDayStreak = player:getCurrentDayStreak()
242 local currentLanePlace = player:getCurrentRewardLaneIndex()
243 local instantTokenBalance = player:getInstantRewardTokens()
244
245 statedata.message = string.format("--------------- Welcome to your reward wall! ------------------\n\nYou're in a %d-day streak\nOn the reward #%d\nInstant Reward Access: %d\n\nRemember that you can always open this window with the \"!daily\" command.\n", currentDayStreak, currentLanePlace, instantTokenBalance)
246
247
248 end
249
250 return statedata
251end
252
253local function setModalState(playerid, state)
254 if playerid and state then
255 dailyRewardStates[playerid] = state
256 end
257end
258
259local function clearModalState(playerid)
260 if not playerid or not dailyRewardStates[playerid] then return end
261
262 dailyRewardStates[playerid] = nil
263
264end
265
266local function getDefaultChoices(player)
267 if not player then
268 return false
269 end
270 local defaultChoices = {
271 ids = {},
272 names = {
273 "Resting Area Bonuses ("..tostring(player:getCurrentDayStreak()) .. ")",
274 "Daily Rewards " .. tostring((player:canGetDailyReward()) and "[*]" or "[ ]"),
275 "Reward History"
276 },
277 choicedata = {
278 {tostate = MODAL_STATE_VIEWSTREAKBONUSES_INDEX},
279 {tostate = MODAL_STATE_VIEWDAILYREWARD_LANE},
280 {tostate = MODAL_STATE_VIEWREWARDHISTORY}
281 }
282 }
283
284
285 return defaultChoices
286end
287
288local function getDefaultButtonsNames()
289 local buttonsNames = {
290 "Submit",
291 "Close"
292 }
293
294 return buttonsNames
295end
296
297local function getDefaultEnterButtonName()
298 return "Submit"
299end
300
301local function getDefaultCancelButtonName()
302 return "Close"
303end
304
305local function getStreakStatusText(player, rewardStreak)
306 if not player then
307 return false
308 end
309
310 local isPremiumPlayer = player:isPremium()
311 local message
312 local currentDayStreak = player:getCurrentDayStreak()
313
314 if rewardStreak.premium and not isPremiumPlayer then
315 message = 'locked - Premium only'
316 elseif currentDayStreak >= rewardStreak.days then
317 message = 'active'
318 elseif currentDayStreak == rewardStreak.days - 1 and player:canGetDailyReward() then
319 message = "GET TODAY'S REWARD TO ACTIVATE"
320 else
321 message = 'locked'
322 end
323
324 return message
325end
326
327local function getAvailableRewardItems(pid, forceReload)
328 -- TODO: cache
329 local reward = {}
330 if not forceReload and itemsCache[pid] then
331 return itemsCache[pid]
332 else
333
334
335 local player = Player(pid)
336
337 if not player then
338 return false
339 end
340
341 local runes = player:getRuneSpells(true) --ignore level
342 --[[
343 runes = {
344 {
345 name,
346 level,
347 mlevel,
348 runeid, --itemid
349 spriteid,
350 },
351 (...)
352 }
353 ]]
354 if runes then
355 reward.runes = runes
356 end
357
358 local potions = {}
359 for i=1, #potionsIds do
360 if player:canUsePotion(potionsIds[i],true) then
361 local itype = ItemType(potionsIds[i])
362 local potion = {
363 name = itype:getArticle() .. " " .. itype:getName(),
364 potionid = potionsIds[i],
365 spriteid = itype:getClientId()
366 }
367 table.insert(potions, potion)
368 end
369 end
370
371 if potions then
372 reward.potions = potions
373 end
374
375 itemsCache[pid] = reward
376 return reward
377 end
378end
379
380function Player:getAvailableDailyRewardItems()
381 if not self then
382 return false
383 end
384 return getAvailableRewardItems(self:getId())
385end
386
387local function getStaticState(pid, MODAL_STATE, additional)
388 local state
389
390 if MODAL_STATE == MODAL_STATE_VIEWSTREAKBONUSES_INDEX then
391 local p = Player(pid)
392 if not p then
393 return false
394 end
395 state = {stateId = MODAL_STATE_VIEWSTREAKBONUSES_INDEX}
396 local currentDayStreak = p:getCurrentDayStreak()
397
398 local message = string.format("These are your Resting Area Bonuses!\n" ..
399 "\nYou're in a %d-day streak%s\n",currentDayStreak, currentDayStreak > 2 and "!!" or "." )
400
401 if p:canGetDailyReward() then
402 local timeleft = Game.getLastServerSave() + 24*60*60 - os.time()
403 message = message .. "Hurry up! Pick up your daily reward within the next " .. getTimeinWords(timeleft) ..
404 " (before the next regular server save) to raise your reward streak by one and.\n"..
405 "Raise your reward streak to benefit from bonuses in resting areas."
406 end
407
408 state.statedata = {
409 playerid = pid,
410 title = "Resting Area Bonuses",
411 message = message
412 }
413
414 local names = {}
415 local choicesData = {}
416 for i=1, #REWARD_STREAK do
417 local rs = REWARD_STREAK[i]
418 local isPremiumPlayer = p:isPremium()
419 local status
420
421 if rs.premium and not isPremiumPlayer then
422 status = 'locked - Premium only'
423 elseif currentDayStreak >= rs.days then
424 status = 'active'
425 elseif currentDayStreak == rs.days - 1 and p:canGetDailyReward() then
426 status = "GET TODAY'S REWARD TO ACTIVATE"
427 else
428 status = 'locked'
429 end
430
431 names[i] = string.format("%d - %s [%s]", rs.days,rs.description,status)
432 choicesData[i] = {
433 tostate = MODAL_STATE_VIEWSTREAKBONUSES_DETAILS,
434 streak_index = i
435 }
436 end
437
438 state.choices ={
439 ids ={},
440 names = names,
441 choicedata = choicesData
442 }
443
444
445 state.buttons = {
446 names = {"Close","Back","Details"},
447 defaultEnterName = "Details",
448 defaultCancelName = "Close",
449 callbacks = {
450 function(button, choice) --close
451 clearModalState(pid)
452 end,
453
454 function(button,choice) -- Back
455 local stateDefault = getDefaultModalState(Player(pid))
456 setModalState(pid, stateDefault)
457 sendModalSelectRecursive(Player(pid))
458 end,
459 function(button,choice) --Details
460 local stateDetails = getStaticState(pid, MODAL_STATE_VIEWSTREAKBONUSES_DETAILS,choice.choicedata.streak_index)
461 setModalState(pid, stateDetails)
462 sendModalSelectRecursive(Player(pid))
463 end
464 }
465 }
466
467 elseif MODAL_STATE == MODAL_STATE_VIEWSTREAKBONUSES_DETAILS then
468 local streak_index = additional
469
470 local rewardStreak = REWARD_STREAK[streak_index]
471
472 local message = tostring(rewardStreak.days) .. "-Day streak bonus ("
473
474 local player = Player(pid)
475 if not player then
476 return false
477 end
478 message = message .. getStreakStatusText(player, rewardStreak) ..
479 string.format(")\n\nThis bonus is active if you reached a reward streak of at least %d.\n\n", rewardStreak.days) ..
480 rewardStreak.fullDescription
481 state = { stateId = MODAL_STATE_VIEWSTREAKBONUSES_DETAILS }
482
483 state.statedata = {
484 playerid = pid,
485 title = "Resting Area Bonuses (Details)",
486 message = message
487 }
488
489 -- state.choices absent here (info-only modal)
490
491 state.buttons = {
492 names = {"Back","Close"},
493 defaultEnterName = "Back",
494 defaultCancelName = "Close",
495 callbacks = {
496 function(button,choice) -- Back
497 local stateDetails = getStaticState(pid, MODAL_STATE_VIEWSTREAKBONUSES_INDEX)
498 setModalState(pid, stateDetails)
499 sendModalSelectRecursive(Player(pid))
500 end,
501 function(button, choice) -- Close
502 clearModalState(pid)
503 end
504 }
505 }
506 elseif MODAL_STATE == MODAL_STATE_VIEWDAILYREWARD_LANE then
507 state = { stateId = MODAL_STATE_VIEWDAILYREWARD_LANE }
508
509 local laneIndex = additional
510 local player = Player(pid)
511 if not player then
512 return false
513 end
514 local reward
515 if player:isPremium() then
516 reward = REWARD_LANE.PREMIUM_ACC[laneIndex]
517 else
518 reward = REWARD_LANE.FREE_ACC[laneIndex]
519 end
520
521 local message = ""
522
523 if player:canGetDailyReward() then
524 message = string.format("Your today's reward is:\n\n- %s.\n\n",reward.description)
525 if player:isCloseToRewardShrine() then
526 message = message .. "Since you're close to a reward shrine, this reward pickup is FREE!"
527 else
528 local instantRewardTokens = player:getInstantRewardTokens()
529 if instantRewardTokens > 0 then
530 message = message .. string.format("Caution! You are far from a reward shrine. This reward pickup will use 1 of your %d Instant Reward Access.", instantRewardTokens)
531 else
532 message = message .. "Not enough Instance Reward Access points to pick up this reward.\n"
533 message = message .. "You can purchase an Instant Reward Acces in the store or visit a reward shrine to pick up your daily reward for FREE."
534 --cannot proceed show error message and display only back and close buttons
535 local buttons = {
536 names = {"Back", "Store", "Close"},
537 defaultEnterName = "Store",
538 defaultCancelName = "Close",
539 callbacks = {
540 function(button, choice) -- Back
541 local stateDetails = getDefaultModalState(Player(pid))
542 setModalState(pid, stateDetails)
543 sendModalSelectRecursive(Player(pid))
544 end,
545 function(button, choice) -- Open Store
546 clearModalState(pid)
547
548 local p = Player(pid)
549 if not p then
550 return false
551 end
552 if p~= nil then
553 p:sendStore()
554 --category with the Instant Reward Access offer
555 end
556 end,
557 function(button, choice) -- Close
558 clearModalState(pid)
559 end
560 }
561 }
562
563 state.buttons = buttons
564 state.statedata = {
565 playerid = pid,
566 title = "Daily Reward",
567 message = message
568 }
569
570 return state --halt execution
571 end
572 end
573
574 local buttons
575 if reward.type == REWARD_TYPE_RUNE_POT then
576 buttons = {
577 names = {"Back", "Choose", "Close"},
578 defaultEnterName = "Choose",
579 defaultCancelName = "Close",
580 callbacks = {
581 function(button, choice) -- back
582 local stateDetails = getDefaultModalState(Player(pid))
583 setModalState(pid, stateDetails)
584 sendModalSelectRecursive(Player(pid))
585 end,
586 function(button, choice) -- choose items
587 local stateChooseItems = getStaticState(pid, MODAL_STATE_SELECTING_REWARD_ITEMS, reward)
588 setModalState (pid, stateChooseItems)
589 sendModalSelectRecursive(Player(pid))
590 end,
591 function(button, choice) -- close
592 clearModalState(pid)
593 end,
594 }
595 }
596 else
597 buttons = {
598 names = {"Back", "Claim", "Close"},
599 defaultEnterName = "Claim",
600 defaultCancelName = "Close",
601 callbacks = {
602 function(button, choice) -- back
603 local stateDetails = getDefaultModalState(Player(pid))
604 setModalState(pid, stateDetails)
605 sendModalSelectRecursive(Player(pid))
606 end,
607 function(button, choice) -- claim
608 local stateConfirm = getStaticState(pid, MODAL_STATE_CONFIRM_REWARD_PICK, reward)
609 setModalState (pid, stateConfirm)
610 sendModalSelectRecursive(Player(pid))
611 end,
612 function(button, choice) -- close
613 clearModalState(pid)
614 end,
615 }
616 }
617 end
618 state.buttons = buttons
619 else
620 local laneIndex = player:getCurrentRewardLaneIndex(false)
621 local nextReward = player:isPremium() and REWARD_LANE["PREMIUM_ACC"][laneIndex].description or REWARD_LANE["FREE_ACC"][laneIndex].description
622 message =string.format("Congratulations! You've already taken your daily reward."..
623 "\n\nThe next daily reward will be available in the next server save (in %s).\n\nYour next daily reward will be:\n %s\n", getTimeinWords(player:getNextRewardPick() - os.time()), nextReward )
624
625 state.buttons = {
626 names = {"Back", "Close"},
627 defaultEnterName="Back",
628 defaultCancelName = "Close",
629 callbacks = {
630 function(button, choice) -- back
631 local stateMainMenu = getDefaultModalState(Player(pid))
632 setModalState(pid, stateMainMenu)
633 sendModalSelectRecursive(Player(pid))
634 end,
635 function(button,choice) -- close
636 clearModalState(pid)
637 end
638 }
639 }
640 end
641
642
643
644 state.statedata ={
645 title = "Daily Reward",
646 message = message,
647 playerid = pid
648 }
649
650 elseif MODAL_STATE == MODAL_STATE_CONFIRM_REWARD_PICK then
651 --recheck reward get condition
652 local reward = additional
653 local player = Player(pid)
654 if not player then
655 return false
656 end
657 if reward.type == REWARD_TYPE_RUNE_POT then
658 local current = dailyRewardStates[pid]
659
660 if current and current.statedata and current.statedata.selection then
661 local selectionReward = current.statedata.selection
662 local playerSelection = {}
663 local totalWeight = 0
664 local message = "The following items will be delivered to your store inbox: \n"
665 for itemId, count in pairs(selectionReward) do
666 table.insert(playerSelection,{itemid = itemId, count = count})
667 local ittype = ItemType(itemId)
668 totalWeight = totalWeight + ittype:getWeight(count)
669 message = message .. string.format("%dx %s; ",count, ittype:getName())
670 end
671
672 message = message .. string.format("\n\nTotal weight: %.2f oz.\nMake sure you have enough capacity.\nConfirm selection?\n", totalWeight/100.0)
673
674 local useToken = player:isCloseToRewardShrine() and 0 or 1
675 if useToken > 0 then
676 message = message .. "\nTHIS WILL USE 1 INSTANT REWARD ACCESS."
677 end
678
679 state = {stateId = MODAL_STATE_CONFIRM_REWARD_PICK}
680
681 local buttons = {
682 names = {"Cancel", "Confirm"},
683 defaultEnterName = "Confirm",
684 defaultCancelName = "Cancel",
685 callbacks = {
686 function(button, choice) -- Cancel
687 clearModalState(pid)
688 end,
689 function(button, choice) -- Confirm
690 local player = Player(pid)
691 local useToken = player:isCloseToRewardShrine() and 0 or 1
692 player:receiveReward(useToken, reward.type, playerSelection)
693 clearModalState(pid)
694 end
695 }
696 }
697
698
699 local stateData = {
700 playerid = pid,
701 title = "Reward Selection",
702 message = message
703 }
704
705 state.statedata = stateData
706 state.buttons = buttons
707
708 else --error
709 state = {
710 stateId = MODAL_STATE_CONFIRM_REWARD_PICK,
711 statedata = {
712 playerid = pid,
713 title = "Daily Reward System - Error",
714 message = "Invalid items selection!\n\nTry again with valid items."
715 },
716 buttons = {
717 names= {"Close"},
718 callbacks = {
719 function(button, choice)
720 clearModalState(pid)
721 end
722 },
723 defaultEnterName = "Close",
724 defaultCancelName = "Close"
725 }
726 }
727 end
728
729 elseif reward.type == REWARD_TYPE_TEMPORARYITEM then
730 local items = reward and reward.items
731
732 local playerSelection = {}
733 local totalWeight = 0
734 local message = "The following items will be delivered to your store inbox: \n"
735 for i=1, #items do
736 local itemId, count = items[i].id,items[i].ammount
737
738 table.insert(playerSelection,{itemid = itemId, count = count})
739 local ittype = ItemType(itemId)
740 totalWeight = totalWeight + ittype:getWeight(count)
741 message = message .. string.format("%dx %s; ",count, ittype:getName())
742 end
743
744 message = message .. string.format("\n\nTotal weight: %.2f oz.\nMake sure you have enough capacity.\nConfirm selection?\n", totalWeight/100.0)
745
746 local useToken = player:isCloseToRewardShrine() and 0 or 1
747 if useToken > 0 then
748 message = message .. "\nTHIS WILL USE 1 INSTANT REWARD ACCESS."
749 end
750
751 state = {stateId = MODAL_STATE_CONFIRM_REWARD_PICK}
752
753 local buttons = {
754 names = {"Cancel", "Confirm"},
755 defaultEnterName = "Confirm",
756 defaultCancelName = "Cancel",
757 callbacks = {
758 function(button, choice) -- Cancel
759 clearModalState(pid)
760 end,
761 function(button, choice) -- Confirm
762 local player = Player(pid)
763 if not player then
764 return false
765 end
766 local useToken = player:isCloseToRewardShrine() and 0 or 1
767 player:receiveReward(useToken, reward.type, playerSelection)
768 clearModalState(pid)
769 end
770 }
771 }
772
773
774 local stateData = {
775 playerid = pid,
776 title = "Pick Reward",
777 message = message
778 }
779
780 state.statedata = stateData
781 state.buttons = buttons
782
783 elseif reward.type == REWARD_TYPE_XP_BOOST then
784 if not player then
785 return false
786 end
787 local message = string.format("You will receive: \n\n%d minutes of XP BOOST will be added to your character\nConfirm selection?\n", reward.ammount)
788
789 local useToken = player:isCloseToRewardShrine() and 0 or 1
790 if useToken > 0 then
791 message = message .. "\nTHIS WILL USE 1 INSTANT REWARD ACCESS."
792 end
793
794
795 state = {stateId = MODAL_STATE_CONFIRM_REWARD_PICK}
796
797 local buttons = {
798 names = {"Cancel", "Confirm"},
799 defaultEnterName = "Confirm",
800 defaultCancelName = "Cancel",
801 callbacks = {
802 function(button, choice) -- Cancel
803 clearModalState(pid)
804 end,
805 function(button, choice) -- Confirm
806 local player = Player(pid)
807 if not player then
808 return false
809 end
810 local useToken = player:isCloseToRewardShrine() and 0 or 1
811 player:receiveReward(useToken, reward.type, reward.ammount)
812 clearModalState(pid)
813 end
814 }
815 }
816
817 local stateData = {
818 playerid = pid,
819 title = "Pick Reward",
820 message = message
821 }
822
823 state.statedata = stateData
824 state.buttons = buttons
825
826 elseif reward.type == REWARD_TYPE_PREY_REROLL then
827 if not player then
828 return false
829 end
830 local message = string.format("You will receive: \n\n%d Prey Bonus Reroll%s will be added to your character\nConfirm selection?\n", reward.ammount, reward.ammount>1 and "s" or "")
831
832 local useToken = player:isCloseToRewardShrine() and 0 or 1
833 if useToken > 0 then
834 message = message .. "\nTHIS WILL USE 1 INSTANT REWARD ACCESS."
835 end
836
837
838 state = {stateId = MODAL_STATE_CONFIRM_REWARD_PICK}
839
840 local buttons = {
841 names = {"Cancel", "Confirm"},
842 defaultEnterName = "Confirm",
843 defaultCancelName = "Cancel",
844 callbacks = {
845 function(button, choice) -- Cancel
846 clearModalState(pid)
847 end,
848 function(button, choice) -- Confirm
849 local player = Player(pid)
850 if not player then
851 return false
852 end
853 local useToken = player:isCloseToRewardShrine() and 0 or 1
854 player:receiveReward(useToken, reward.type, reward.ammount)
855 clearModalState(pid)
856 end
857 }
858 }
859
860 local stateData = {
861 playerid = pid,
862 title = "Pick Reward",
863 message = message
864 }
865
866 state.statedata = stateData
867 state.buttons = buttons
868 end
869 elseif MODAL_STATE == MODAL_STATE_SELECTING_REWARD_ITEMS then
870 if not itemsCache[pid] then
871 itemsCache[pid] = getAvailableRewardItems(pid)
872 end
873 local reward = additional
874 state = getChoiceModalState(pid, reward)
875 elseif MODAL_STATE == MODAL_STATE_VIEWREWARDHISTORY_DETAILS then
876 local history = additional
877
878 state = {}
879 state.stateId = MODAL_STATE_VIEWREWARDHISTORY_DETAILS
880
881 state.buttons = {
882 names = {"Back","Close"},
883 defaultEnterName = "Back",
884 defaultCancelName = "Close",
885 callbacks = {
886 function(button,choice) -- Back
887 local stateDefault = getDefaultModalState(Player(pid))
888 setModalState(pid, stateDefault)
889 sendModalSelectRecursive(Player(pid))
890 end,
891 function(button, choice) -- Close
892 clearModalState(pid)
893 end
894 }
895 }
896
897 local pickCost
898
899 if history.instantCost > 0 then
900 pickCost = string.format("This reward pick used %d Instant Reward Access.", history.instantCost)
901 else
902 pickCost = "This reward pick was FREE."
903 end
904 local msg = string.format("History Details\n\nDate: %s\nStreak: %d\nEvent: %s\n\n%s",
905 os.date("%Y-%m-%d %X",history.timestamp), history.streak, history.event, pickCost)
906
907 state.statedata = {
908 playerid = pid,
909 title = "Reward Wall - History Details",
910 message = msg
911 }
912 end
913
914 return state
915end
916
917getChoiceModalState = function(pid, reward)
918 local player = Player(pid)
919 if not player then
920 return false
921 end
922 local state = {stateId = MODAL_STATE_SELECTING_REWARD_ITEMS}
923
924 local potionsSelectable = itemsCache[pid].potions
925 local runesSelectable = itemsCache[pid].runes
926
927 local choices = dailyRewardStates[pid].choices or {ids={}}
928 if not choices.names then
929 local choicesNames = {}
930 local choicesData = {}
931
932 local i=1
933
934 if potionsSelectable then
935 for j=1, #potionsSelectable do
936 choicesNames[i] = potionsSelectable[j].name
937 choicesData[i] = potionsSelectable[j].potionid
938 i = i+1
939 end
940 end
941
942 if runesSelectable then
943 for j=1, #runesSelectable do
944 local itype = ItemType(runesSelectable[j].runeid)
945 choicesNames[i] = itype:getArticle() .. " " ..itype:getName() --get name item name instead of spell name
946 choicesData[i] = runesSelectable[j].runeid
947 i = i+1
948 end
949 end
950
951 choices.names = choicesNames
952 choices.choicedata = choicesData
953 end
954
955 state.choices = choices
956 local currentSelection = dailyRewardStates[pid] and dailyRewardStates[pid].statedata and dailyRewardStates[pid].statedata.selection or nil
957 -- { [itemId] = ammount, [item2Id] = ...}
958
959 local selectionText
960 local selectedItemsCount = 0
961 local totalWeight = 0
962 if currentSelection then
963 selectionText="\nCurrently selected:\n"
964 for itemId, quantity in pairs(currentSelection) do
965 if not selectionText then end
966 local ittype = ItemType(itemId)
967 totalWeight = totalWeight+ittype:getWeight(quantity)
968 selectedItemsCount = selectedItemsCount+quantity
969 selectionText = selectionText .. string.format("%dx %s; ",quantity, ittype:getName())
970 end
971 selectionText = selectionText .. "\n"
972 end
973
974 --Message
975 local message
976
977 message = string.format("You have selected %d of %d reward items.\n",selectedItemsCount, reward.ammount)
978
979 if selectionText then
980 message = message..selectionText
981 end
982
983 message = message .. string.format("\nFree Capacity: %.2f oz.\nTotal weight: %.2f oz", player:getFreeCapacity()/100.0, totalWeight/100.0)
984 state.statedata = {
985 playerid = pid,
986 title = "Pick Reward",
987 message = message
988 }
989
990 if currentSelection then
991 state.statedata.selection = currentSelection
992 end
993
994 local addFunc = function(button, choice, addAmmount, remainingCount)
995 local curSelection = dailyRewardStates[pid] and dailyRewardStates[pid].statedata and dailyRewardStates[pid].statedata.selection or nil
996 if not curSelection then
997 curSelection = {}
998 end
999
1000 local itemId = choice.choicedata
1001
1002 if not curSelection[itemId] then
1003 curSelection[itemId] = addAmmount
1004 else
1005 curSelection[itemId] = curSelection[itemId] + addAmmount
1006 end
1007
1008
1009 local sta = dailyRewardStates[pid]
1010 sta.statedata.selection = curSelection
1011 setModalState(pid, sta)
1012
1013 sta = getChoiceModalState(pid, reward)
1014 setModalState(pid, sta)
1015 if remainingCount - addAmmount == 0 then
1016 local stateReceiveReward = getStaticState(pid, MODAL_STATE_CONFIRM_REWARD_PICK, reward)
1017 setModalState(pid, stateReceiveReward)
1018 end
1019
1020 end
1021
1022 local remaining = reward.ammount - selectedItemsCount
1023
1024 local buttons = {
1025 names= {"Back", "Add", string.format("Add %dx", math.ceil(remaining/2)),string.format("Add %dx", math.ceil(remaining)) },
1026 defaultEnterName = "Add",
1027 defaultCancelName = "Back",
1028 callbacks = {
1029 function(button, choice) --Back
1030 local st = getStaticState(pid, MODAL_STATE_VIEWDAILYREWARD_LANE, player:getCurrentRewardLaneIndex())
1031 setModalState(pid,st)
1032 sendModalSelectRecursive(Player(pid))
1033 end,
1034 function(button, choice) -- Add 1
1035 addFunc(button,choice,1, remaining)
1036 sendModalSelectRecursive(Player(pid))
1037 end,
1038 function(button, choice)-- Add half of remaining (ceil)
1039 addFunc(button,choice, math.ceil(remaining/2), remaining)
1040 sendModalSelectRecursive(Player(pid))
1041 end,
1042 function(button, choice)-- Add remaining
1043 addFunc(button,choice, remaining, remaining)
1044 sendModalSelectRecursive(Player(pid))
1045 end,
1046 }
1047 }
1048
1049 state.buttons = buttons
1050
1051
1052 return state
1053end
1054
1055local function getDefaultCallbacks(player)
1056 if not player then
1057 return false
1058 end
1059 local playerid = player:getId()
1060 local callbacks = {
1061 function(button, choice) -- SubmitCallback
1062 local selection = choice.choicedata.tostate
1063
1064 if selection == MODAL_STATE_VIEWDAILYREWARD_LANE then
1065 local newState = getStaticState(playerid, MODAL_STATE_VIEWDAILYREWARD_LANE, player:getCurrentRewardLaneIndex())
1066 setModalState(playerid, newState)
1067 sendModalSelectRecursive(Player(playerid))
1068 elseif selection == MODAL_STATE_VIEWSTREAKBONUSES_INDEX then
1069 local newState = getStaticState(playerid, MODAL_STATE_VIEWSTREAKBONUSES_INDEX)
1070 setModalState(playerid, newState)
1071 sendModalSelectRecursive(Player(playerid))
1072 elseif selection == MODAL_STATE_VIEWREWARDHISTORY then
1073 local cb = function(history)
1074 local state = {}
1075 state.stateId = MODAL_STATE_VIEWREWARDHISTORY
1076
1077 state.buttons = {
1078 names = {"Back","Details","Close"},
1079 defaultEnterName = "Details",
1080 defaultCancelName = "Close",
1081 callbacks = {
1082 function(button,choice) -- Back
1083 local stateDefault = getDefaultModalState(Player(playerid))
1084 setModalState(playerid, stateDefault)
1085 sendModalSelectRecursive(Player(playerid))
1086 end,
1087 function(button,choice) --details
1088 local stateDetails = getStaticState(playerid, MODAL_STATE_VIEWREWARDHISTORY_DETAILS,choice.choicedata)
1089 setModalState(playerid, stateDetails)
1090 sendModalSelectRecursive(Player(playerid))
1091 end,
1092 function(button, choice) -- Close
1093 clearModalState(playerid)
1094 end
1095 }
1096 }
1097 local message = '---------------------- Reward History ----------------------'
1098 local choices
1099 local cnames,cdata
1100 if history and #history>0 then
1101 for i=1, #history do
1102 if not cnames then
1103 cnames = {}
1104 cdata = {}
1105 end
1106
1107 local dt = os.date("%Y-%m-%d %X",history[i].timestamp)
1108 local choiceName = string.format("%s - strk:%d - %s", dt, history[i].streak ,history[i].event)
1109 table.insert(cnames, choiceName)
1110 table.insert(cdata, history[i])
1111 end
1112 choices = {
1113 ids ={},
1114 names = cnames,
1115 choicedata = cdata
1116 }
1117
1118 state.choices = choices
1119 else
1120 message = message .. "\n\nNo reward history yet."
1121
1122 state.buttons = {
1123 names = {"Back", "Close"},
1124 defaultEnterName = "Back",
1125 defaultCancelName = "Close",
1126 callbacks = {
1127 function(button,choice) -- Back
1128 local stateDefault = getDefaultModalState(Player(playerid))
1129 setModalState(playerid, stateDefault)
1130 sendModalSelectRecursive(Player(playerid))
1131 end,
1132 function(button, choice) -- Close
1133 clearModalState(playerid)
1134 end
1135 }
1136 }
1137
1138 end
1139 state.statedata = {
1140 playerid = playerid,
1141 title = "Reward Wall - History",
1142 message = message
1143 }
1144
1145 setModalState(playerid, state)
1146 sendModalSelectRecursive(Player(playerid))
1147 end
1148 player:getDailyRewardHistory(cb,10)
1149 end
1150
1151 end,
1152 function(button, choice)--closeCallback
1153 clearModalState(playerid)
1154 end
1155 }
1156
1157 return callbacks
1158end
1159
1160local function getDefaultButtons(player)
1161 if not player then
1162 return false
1163 end
1164 local defaultButtons = {}
1165 defaultButtons.names = getDefaultButtonsNames()
1166 defaultButtons.callbacks = getDefaultCallbacks(player)
1167 defaultButtons.defaultEnterName = getDefaultEnterButtonName()
1168 defaultButtons.defaultCancelName = getDefaultCancelButtonName()
1169
1170 return defaultButtons
1171end
1172
1173getDefaultModalState = function (player)
1174 local defaultState = {
1175 stateId = MODAL_STATE_MAINMENU,
1176 choices = getDefaultChoices(player),
1177 buttons = getDefaultButtons(player),
1178 statedata = getDefaultStateData(player,MODAL_STATE_MAINMENU)
1179 }
1180
1181 return defaultState
1182end
1183
1184local function getModalState(playerid)
1185 if not playerid then return nil end
1186 local state
1187
1188 if not dailyRewardStates[playerid] then
1189 state = getDefaultModalState(Player(playerid))
1190 else
1191 state = dailyRewardStates[playerid]
1192 end
1193
1194 return state
1195end
1196
1197local function callbackAddItemModal ()
1198
1199end
1200
1201function Player:initDailyRewardSystem()
1202 if not self then
1203 return false
1204 end
1205 local nextRewardPick = self:getStorageValue(Storage.dailyReward.nextRewardPick)
1206
1207 if nextRewardPick < (Game.getLastServerSave() - (24*60*60)) then -- 24 hours of the limit time has passed, reset streak
1208 self:setCurrentDayStreak(0)
1209 -- print('reset current day streak')
1210 end
1211
1212 self:loadStreakBonuses()
1213 self:sendAvailableTokens()
1214 self:sendDailyRewardBasic()
1215end
1216
1217function Player:getLastRewardPick()
1218 if not self then
1219 return false
1220 end
1221 return math.max(self:getStorageValue(Storage.dailyReward.lastRewardPick),0)
1222end
1223
1224function Player:setLastRewardPick(timestamp)
1225 if not self then
1226 return false
1227 end
1228 if tonumber(timestamp) then
1229 self:setStorageValue(Storage.dailyReward.lastRewardPick, timestamp)
1230 else
1231 print('[WARNING - DAILY REWARD]: Invalid last reward timestamp')
1232 end
1233
1234end
1235
1236function Player:getNextRewardPick()
1237 if not self then
1238 return false
1239 end
1240 return math.max(self:getStorageValue(Storage.dailyReward.nextRewardPick),0)
1241end
1242
1243function Player:setNextRewardPick(timestamp)
1244 if not self then
1245 return false
1246 end
1247 if tonumber(timestamp) then
1248 self:setStorageValue(Storage.dailyReward.nextRewardPick, timestamp)
1249 else
1250 print('[WARNING - DAILY REWARD]: Invalid next reward timestamp')
1251 end
1252
1253end
1254
1255function Player:getCurrentDayStreak()
1256 if not self then
1257 return false
1258 end
1259 return math.max(self:getStorageValue(Storage.dailyReward.streakDays),0)
1260end
1261
1262function Player:setCurrentDayStreak(value)
1263 if not self then
1264 return false
1265 end
1266 self:setStorageValue(Storage.dailyReward.streakDays, value)
1267end
1268
1269function Player:getCurrentRewardLaneIndex(zerobased)
1270 if not self then
1271 return false
1272 end
1273 local rewardIndex = math.max(self:getStorageValue(Storage.dailyReward.currentIndex),0)
1274 if not zerobased then
1275 rewardIndex = rewardIndex+1
1276 end
1277
1278 return rewardIndex
1279end
1280
1281function Player:setCurrentRewardLaneIndex(value)
1282 if not self then
1283 return false
1284 end
1285 self:setStorageValue(Storage.dailyReward.currentIndex, value)
1286end
1287
1288function Player:incrementCurrentRewardLaneIndex()
1289 if not self then
1290 return false
1291 end
1292 local currentIndex = self:getCurrentRewardLaneIndex(true)
1293 local lanelength
1294
1295 if self:isPremium() then
1296 lanelength = #REWARD_LANE["PREMIUM_ACC"] or 1
1297 else
1298 lanelength = #REWARD_LANE["FREE_ACC"] or 1
1299 end
1300
1301 currentIndex = (currentIndex + 1) % lanelength
1302 self:setCurrentRewardLaneIndex(currentIndex)
1303end
1304
1305function Player:addRewardTokens(ammount)
1306 if not self then
1307 return false
1308 end
1309 local current = self:getInstantRewardTokens()
1310 ammount = math.abs(ammount)
1311
1312 self:setInstantRewardTokens(current+ammount)
1313 self:sendAvailableTokens()
1314end
1315
1316function Player:removeRewardTokens(ammount)
1317 if not self then
1318 return false
1319 end
1320 local current = self:getInstantRewardTokens()
1321 ammount = math.abs(ammount)
1322
1323 self:setInstantRewardTokens(current-ammount)
1324 self:sendAvailableTokens()
1325end
1326
1327function Player:useRewardToken()
1328 if not self then
1329 return false
1330 end
1331 self:removeRewardTokens(1)
1332end
1333
1334function Player:isCloseToAnyOfItems(itemList)
1335 if not self then
1336 return false
1337 end
1338 for x = -1, 1 do
1339 for y = -1, 1 do
1340 local posX, posY, posZ = self:getPosition().x+x, self:getPosition().y+y, self:getPosition().z
1341 local tile = Tile(posX, posY, posZ)
1342 if (tile) then
1343 for _, itemId in pairs(itemList) do
1344 if tile:getItemById(itemId) then
1345 return true
1346 end
1347 end
1348 end
1349 end
1350 end
1351
1352 return false
1353end
1354
1355function Player:isCloseToRewardShrine()
1356 if not self then
1357 return false
1358 end
1359 return self:isCloseToAnyOfItems(rewardShrineIds)
1360end
1361
1362function Player:enableSoulRegenInRestAreas()
1363 if not self then
1364 return false
1365 end
1366 local soulCondition = Condition (CONDITION_SOULBONUS, CONDITIONID_DEFAULT)
1367 soulCondition:setTicks((Game.getLastServerSave() + (24*60*60) - os.time()) *1000)
1368 local vocation = self:getVocation()
1369 soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
1370 soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)
1371
1372 self:addCondition(soulCondition)
1373end
1374
1375function Player:enableStaminaRegenInRestAreas()
1376 if not self then
1377 return false
1378 end
1379 local conditionStamina = Condition(CONDITION_STAMINAREGEN, CONDITIONID_DEFAULT)
1380 conditionStamina:setTicks((Game.getLastServerSave() + (24*60*60) - os.time()) *1000) --until next SS
1381
1382
1383 conditionStamina:setParameter(CONDITION_PARAM_STAMINAGAIN, 1)
1384
1385 self:addCondition(conditionStamina);
1386end
1387
1388function Player:enableStreakBonus(day)
1389 if not self then
1390 return false
1391 end
1392 --Nem todos precisam ser ativados, o regen de mana e health já estão prontos nas srcs
1393 if day == 7 then
1394 self:enableSoulRegenInRestAreas()
1395 elseif day == 4 then
1396 self:enableStaminaRegenInRestAreas()
1397 end
1398end
1399
1400function Player:loadStreakBonuses()
1401 if not self then
1402 return false
1403 end
1404 local isPremium = self:isPremium()
1405
1406 local function applyBonusRecursive(day)
1407 if day<2 then
1408 return
1409 elseif day>7 then
1410 day=7
1411 end
1412
1413 self:enableStreakBonus(day)
1414 applyBonusRecursive(day-1)
1415 end
1416
1417 local streakDays = self:getCurrentDayStreak()
1418 if(isPremium) then
1419 streakDays= math.min(7,streakDays)
1420 else
1421 streakDays = math.min(3, streakDays)
1422 end
1423
1424 applyBonusRecursive(streakDays)
1425end
1426
1427function Player:receiveReward(useToken, rewardType, additional)
1428 if not self then
1429 return false
1430 end
1431 local client = self:getClient()
1432 if not client then
1433 return false
1434 end
1435 -- Client 11 only
1436 if ((client.os == CLIENTOS_NEW_WINDOWS or client.os ~= CLIENTOS_FLASH) and client.version >= 1140) then
1437 self:sendCloseRewardWall()
1438 end
1439
1440 if useToken > 0 and self:getInstantRewardTokens() == 0 then
1441 self:getPosition():sendMagicEffect(CONST_ME_POFF)
1442 return self:sendCancelMessage("Not enough instant reward tokens.")
1443 end
1444
1445 local historyExtra =''
1446 if rewardType == REWARD_TYPE_RUNE_POT or rewardType == REWARD_TYPE_TEMPORARYITEM then
1447 local totalWeight = 0
1448 local selection = additional
1449 for i=1, #selection do
1450 totalWeight = totalWeight + ItemType(selection[i].itemid):getWeight(selection[i].count)
1451 end
1452
1453 if self:getFreeCapacity() < totalWeight then
1454 self:getPosition():sendMagicEffect(CONST_ME_POFF)
1455 return self:sendCancelMessage(RETURNVALUE_NOTENOUGHCAPACITY)
1456 end
1457
1458 local inbox = self:getSlotItem(CONST_SLOT_PURSE)
1459 --local inbox = self:getSlotItem(CONST_SLOT_STORE_INBOX)
1460 if not inbox or inbox:getEmptySlots() == 0 then
1461 self:getPosition():sendMagicEffect(CONST_ME_POFF)
1462 return self:sendCancelMessage(RETURNVALUE_CONTAINERNOTENOUGHROOM)
1463 end
1464 for i=1, #selection do
1465 local itype = ItemType(selection[i].itemid)
1466 local adicionarItem = inbox:addItem(selection[i].itemid, selection[i].count, INDEX_WHEREEVER, FLAG_NOLIMIT)
1467 if rewardType == REWARD_TYPE_TEMPORARYITEM and itype.getId() == 29542 then
1468 if adicionarItem then
1469 adicionarItem:decay()
1470 end
1471 end
1472 historyExtra = historyExtra .. string.format(" %dx %s;",selection[i].count, itype:getName())
1473 end
1474 elseif rewardType == REWARD_TYPE_PREY_REROLL then
1475 local bonusCount = additional
1476 --TODO expire after 7 days
1477 -- self:addBonusReroll(math.abs(bonusCount))
1478 self:addPreyBonusRerolls(math.abs(bonusCount))
1479
1480 elseif rewardType == REWARD_TYPE_XP_BOOST then
1481 local minutes = additional
1482 local currentExpBoostTime = self:getStaminaXpBoost()
1483 local boostMinutes = self:getStorageValue(190923)
1484 self:setStaminaXpBoost(currentExpBoostTime + minutes*60);
1485 self:setStoreXpBoost(50) -- 50% de exp
1486 self:setStorageValue(190924, 1) -- storage player.lua
1487 self:setStorageValue(190923, boostMinutes + 30) -- 30 minutos
1488 self:sendStats()
1489 --
1490
1491 end
1492
1493 --validations passed
1494 if useToken > 0 then
1495 self:useRewardToken()
1496 end
1497
1498 --save history message
1499 local historymsg = string.format('Claimed reward no.%d.',self:getCurrentRewardLaneIndex(false))
1500 if rewardType == REWARD_TYPE_RUNE_POT or rewardType == REWARD_TYPE_TEMPORARYITEM then
1501 historymsg = historymsg .. ' Picked items:' .. historyExtra
1502 end
1503
1504 --update values
1505 local nextReward = Game.getLastServerSave() + (24*60*60) -- next day
1506
1507 self:incrementCurrentRewardLaneIndex()
1508 self:setCurrentDayStreak(self:getCurrentDayStreak()+1)
1509 self:setLastRewardPick(os.time())
1510 self:setNextRewardPick(nextReward)
1511 if self:getCurrentDayStreak()<=7 then
1512 self:enableStreakBonus(self:getCurrentDayStreak()) --load the new bonus
1513 end
1514
1515 -- persist history
1516 self:addDailyRewardHistory(self:getCurrentDayStreak(), historymsg , useToken)
1517
1518 -- Client 11 only
1519 if ((client.os == CLIENTOS_NEW_WINDOWS or client.os ~= CLIENTOS_FLASH) and client.version >= 1140) then
1520 self:sendDailyRewardBasic()
1521 self:sendNativeRewardWindow()
1522 end
1523
1524
1525 local effect = math.random(29,31)
1526 self:getPosition():sendMagicEffect(effect)
1527end
1528
1529function Player:canGetDailyReward()
1530 if not self then
1531 return false
1532 end
1533 return os.time() > self:getNextRewardPick()
1534end
1535
1536--[[
1537state = {
1538 stateId = MODAL_STATE_MAINMENU,
1539 choices = {
1540 ids = {},
1541 names ={
1542 "Resting area bonuses",
1543 "DailyRewards"
1544 },
1545 choicedata = {
1546 {} --array of tables (#names == #choicedata)
1547 }
1548 },
1549 buttons = {
1550 names = { "Cancel", "Submit" },
1551 callbacks = { function(button, choice) end, function(button, choice) end}, --#names == # callbacks
1552 defaultEnterName = "Submit",
1553 defaultCancelName = "Cancel"
1554 },
1555 statedata = {
1556 playerid = 123123123
1557 title = "Modal window title",
1558 message = "Modal window message\naccepts multiline\n\n\n nice!",
1559 anyAdditionalFieldData = {}
1560 }
1561}
1562]]
1563sendModalSelectRecursive = function(player)
1564 if not player then
1565 return false
1566 end
1567 local playerid = player:getId()
1568
1569 local state = getModalState(playerid)
1570
1571 local modal = ModalWindow {
1572 title = state.statedata.title,
1573 message = state.statedata.message
1574 }
1575
1576 if state.choices then
1577 for i=1,#state.choices.names do
1578 local choiceId = modal:addChoice(state.choices.names[i])
1579 choiceId.choicedata = state.choices.choicedata[i]
1580 state.choices.ids[i] = choiceId
1581 end
1582 end
1583
1584 local buttonCount = math.min(4, #state.buttons.names) --modal has a limit of 4 buttons
1585 for i=1, buttonCount do
1586 modal:addButton(state.buttons.names[i], state.buttons.callbacks[i])
1587 end
1588
1589 if state.buttons and state.buttons.defaultEnterName then
1590 modal:setDefaultEnterButton(state.buttons.defaultEnterName)
1591 end
1592
1593 if state.buttons and state.buttons.defaultCancelName then
1594 modal:setDefaultEscapeButton(state.buttons.defaultCancelName)
1595 end
1596
1597 modal:sendToPlayer(player)
1598
1599
1600end
1601
1602function Player:sendRewardWindow()
1603 if not self then
1604 return false
1605 end
1606 local client = self:getClient()
1607 if not client then
1608 return false
1609 end
1610 --if modal, verify current prize and prepare appropriate modal window
1611 if ((client.os ~= CLIENTOS_NEW_WINDOWS and client.os ~= CLIENTOS_FLASH) or client.version < 1140) then
1612 -- client 10, flash or 11.40-
1613 self:sendModalRewardWindow()
1614 else
1615 --client 11.40+
1616 self:sendNativeRewardWindow()
1617 end
1618
1619end
1620
1621function Player:sendModalRewardWindow()
1622 if not self then
1623 return false
1624 end
1625 sendModalSelectRecursive(self)
1626end
1627
1628function Player:sendNativeRewardWindow()
1629 if not self then
1630 return false
1631 end
1632 local warnUser = 0
1633 local warnMessage = 'Warning'
1634
1635 if not self:isCloseToRewardShrine() then
1636 warnUser = 1
1637 warnMessage = "Are you sure you want to pick this reward?\n\nTHIS WILL USE 1 INSTANT REWARD ACCESS"
1638 end
1639 self:sendOpenRewardWall(self:isCloseToRewardShrine()and 1 or 0, self:getNextRewardPick(), warnUser,warnMessage)
1640end
1641
1642function Player:addDailyRewardHistory(currentStreak, eventText, instantCost)
1643 if not self then
1644 return false
1645 end
1646 db.query(string.format("INSERT INTO `daily_reward_history`(`streak`,`event`,`instant`,`player_id`) VALUES (%d, %s, %d, %d)",currentStreak, db.escapeString(eventText),instantCost, self:getGuid()))
1647end
1648
1649function Player:getDailyRewardHistory(_callback, limit, page)
1650 if not self then
1651 return false
1652 end
1653 --[[CREATE TABLE IF NOT EXISTS daily_reward_history (
1654 `id` INT NOT NULL PRIMARY KEY auto_increment,
1655 `streak` smallint(2) not null default 0,
1656 `event` varchar(255),
1657 `time` TIMESTAMP NOT NULL default current_timestamp,
1658 `instant` tinyint unsigned NOT NULL DEFAULT 0 ,
1659 `player_id` INT NOT NULL,
1660
1661 FOREIGN KEY(`player_id`) REFERENCES `players`(`id`)
1662 ON DELETE CASCADE
1663 )
1664 ]]
1665 local sql = string.format("SELECT `streak`, `event`, UNIX_TIMESTAMP(`time`) as `time`, `instant`"..
1666 " FROM daily_reward_history WHERE player_id = %d ORDER BY `time` DESC", self:getGuid())
1667
1668 if tonumber(limit) then
1669 sql = sql .. " limit "
1670 if tonumber(page) then
1671 sql = sql .. string.format("%d,", (page*limit))
1672
1673 end
1674 sql = sql .. tostring(tonumber(limit))
1675 end
1676
1677 db.asyncStoreQuery(sql,
1678 function(resultId)
1679 local retTable
1680 if(resultId) then
1681 retTable = {}
1682 repeat
1683 local streak = result.getDataInt(resultId, 'streak')
1684 local event = result.getDataString(resultId, "event")
1685 local timestamp = result.getDataInt(resultId, "time")
1686 local instantCost = result.getDataInt(resultId, "instant")
1687
1688 local t = {
1689 streak = streak,
1690 event = event,
1691 timestamp = timestamp,
1692 instantCost = instantCost
1693 }
1694
1695 table.insert(retTable,t)
1696 until not result.next(resultId)
1697 result.free(resultId)
1698
1699 end
1700
1701 _callback(retTable)
1702 end
1703 )
1704
1705end