summaryrefslogtreecommitdiff
path: root/npc/functions/clientversion.txt
blob: c206a24a4dae81429df22a4f59e58f2ed5242318 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
// TMW2 Scripts
// Evol functions.
// Author:
//    4144
//    Jesusalva
// Description:
//    Function checking the client version and reports if it is too old.
//    This also handles all updates, and usually have priority.

function	script	clientupdater	{
	// Bugfix
	if (!TUT_VAR && UPDATE)
		TUT_VAR=UPDATE;
    // Skip any update for newcomers
    if (compare(getmap(), "000-0") || $@NOUPDATES) {
        UPDATE=gettimetick(2);
    }
    // If you're in Jail, show a minor message
    if (getmap() == "sec_pri") {
        dispbottom l("You seem to be jailed. We cannot unjail offline players, so please don't logout.");
        dispbottom l("You have the right to defend yourself if you believe we were wrong. If we find out it's true, you'll receive an apology gift.");
        dispbottom l("Note: Unless you were doing something REALLY bad which is harmful to player community (eg. scamming, hacking, DDoS'ing, etc.)");
        dispbottom l("Please contact a GM as soon as possible so we can make out a compromise. You should be liberated even if found guilty.");
    }

    .@dg=0;
    /*
    // New skills introduced
    if (UPDATE < 1531786864) {
        UPDATE=1531786864;
        skill TMW2_FAKESKILL, 1, 0;
        skill TMW2_FAKESKILL2, 1, 0;
    }
    // Gallery Contest and 2019-12-29 no-drop incident
    // ter jan  8 03:52:20 -02 2019
    if (UPDATE < 1546926740) {
        UPDATE=1546926740;
        .@u$=strtolower(strcharinfo(0));
        setarray .@apology$, "jesusalva", "mrhedx", "ziah", "soren xd", "warblade", "yuxin", "xtreem", "monking", "demure gm", "se francisc";
        setarray .@gallery$, "jesusalva", "mishana", "bobr", "demure", "lawncable";

        // Users connected during nodrop incident (2018-12-29)
        // Jesusalva Mrhedx Ziah "Soren xd" WarBlade
        // yuxin Xtreem monking "demure GM" "Se Francisc"
        if (array_exists(.@apology$, .@u$)) {
                getitembound GoldenGift, 1, 1;
                Zeny=Zeny+570;
                .@dg=1;
                showavatar NPC_LOF_RICH;
                mesn ("TMW2 Staff");
                mesc l("Hello, @@! We just looked up and found out you were active during 2018-12-29!", strcharinfo(0)), 3;
                mesc l("And during that time, item dropped was bugged! We wanted to deliver you a token of apology!"), 3;
                mesc l("Sorry, and enjoy the game! Your TMW2 Staff Team."), 3;
                mesc l("Token Of Apology: 1x @@, 570 GP", getitemlink(GoldenGift));
                next;
        }

        // 1st Gallery Contest Participants
        // Mishana LawnCable bObr Jesusalva demure
        if (array_exists(.@gallery$, .@u$)) {
                getitem StrangeCoin, 30;
                .@dg=1;
                showavatar NPC_LOF_RICH;
                mesn ("TMW2 Staff");
                mesc l("Hello, @@! We are proud to announce the @@ RESULTS!", strcharinfo(0) , b(l("1° Screenshooting Contest"))), 3;
                mesc l("Participants: Jesusalva * mishana * bObr * demure * LawnCable"), 3;
                next;
                mesc ("Mishana Entries: Happy"), 3;
                mesc ("LawnCable Entries: Login Screen, TMW2 Field"), 3;
                mesc ("Demure Entries: Buggy Map"), 3;
                mesc ("Jesusalva Entries: LoF Secret Island, GM Plotting Evil Scheme For Next Event, Crazyfefe Cave"), 3;
                mesc ("bObr Entries: My Very Own Tiny Orchard"), 3;
                next;
                mesc l("1st Place - Mishana, LawnCable, Jesusalva, bObr");
                mesc l("5th Place - Demure");
                mes "";
                mesc l("Hey, look, a tie happened!");
                mesc l("How's that even possible? Well, 30 @@ for all contestants!", getitemlink(StrangeCoin));
                next;
        }
    }
    // Valentine Day Event Bug
    // sex fev 15 18:04:00 -02 2019
    if (UPDATE < 1550261040) {
        UPDATE=1550261040;
        if (#VALENTINE_POINTS) {
            .@dg=1;
            showavatar NPC_LOF_RICH;
            mesn ("TMW2 Staff");
            mesc l("Hello, @@! We just looked up and found out you that you were affected on a Valentine Event bug!", strcharinfo(0)), 3;
            mesc l("Due this bug, you didn't got a proper amount of points per sent. We wanted to deliver you a token of apology!"), 3;
            mesc l("Sorry, and enjoy the game! Your TMW2 Staff Team."), 3;
            mesc l("Token Of Apology: 1x @@, 1x @@", getitemlink(SilverGift), getitemlink(MercBoxB));
            getitem SilverGift, 1;
            getitem MercBoxB, 1;
            #VALENTINE_POINTS=0;
            next;
        }
    }
    // Limited bots
    // sex fev 15 23:22:21 -02 2019
    if (UPDATE < 1550280141) {
        UPDATE=1550280141;

        .@dg=1;
        mesc l("Game Rules were updated!"), 1;
        mesc l("Use @@ to read the new version.", "@rules"), 1;
        mes "";
        //GameRules S_NO_NPC_NAME | S_LAST_NEXT;
    }
    // Msawis bug
    // ter fev 19 12:15:00 -03 2019
    if (UPDATE < 1550589300) {
        UPDATE=1550589300;
        // Unclaimed Rewards
        // 2000283 Msawis 10 points
        // 2000552 Mrhedx 4 points
        // 2000299 vilbou 1 point
        setarray .@apology, 2000552, 2000283, 2000299;
        if (array_exists(.@apology, getcharid(3)) && (#VALENTINE_SENT+#VALENTINE_OPENED) > 0) {
            if (getcharid(3) == 2000552) {
                getitem BronzeGift, 1;
            } else if (getcharid(3) == 2000283) {
                getitem GoldenGift, 1;
            } else if (getcharid(3) == 2000299) {
                getitem StrangeCoin, 1;
            }
            dispbottom l("Valentine Day Event Reward automatically claimed");
            #VALENTINE_SENT=0;
            #VALENTINE_OPENED=0;
            #VALENTINE_RECEIVED=0;
        }
    }
    // Update Tycoon quest exp
    // dom mar  3 12:22:04 -03 2019
    if (UPDATE < 1551626524) {
        UPDATE=1551626524;
        if (getq(MineQuest_Tycoon) >= 15)
            getexp 43000, 0;
    }
    // Shovel Auto-dig option
    // seg mai 27 21:22:55 -03 2019
    if (UPDATE < 1559002975) {
        UPDATE=1559002975;
        if (countitem(IronShovel) + countitem(SteelShovel))
            dispbottom l("Shovel have been changed, right-click it to bury items.");
    }
    // General Updates
    // sex jun 21 13:20:21 -03 2019
    if (UPDATE < 1561134021) {
        UPDATE=1561134021;
        if (getq(General_Narrator) >= 3)
            getitem MercBoxAA, 1;
        // Well, you don't need this crap I hope...
        if (BaseLevel < 40)
            getitem TulimMap, 1;
        if (getq(TulimsharQuest_Sailors) == 4)
            getexp 1508, 15;
        .@cr=countitem(CroconutBox);
        if (.@cr) {
            getitem CroconutBox, .@cr;
            dispbottom l("Croconut Box magically became two in inventory. Storage unaffected."); // Too much hassle affecting storage/cart/etc.
        }
    }
    // General Updates
    // seg jul 15 16:41:35 -03 2019
    if (UPDATE < 1565039378) {
        UPDATE=1565039378;
        .@dg=true;
        mesc l(".:: This is Release 9.5 Academy ::."), 0;
        //mesc l(".:: This is Release 10.0 Infinity ::."), 0;
        // Fix mounts
        unequip(EQI_SHADOW_SHOES);
		setmount 0;
        // You got recipe book by BSS Quest - mark as complete and get Blueprint
        if (getq(NivalisQuest_BlueSageSlimes) == 2) {
            getitem any(AncientBlueprint, AlchemyBlueprintA, EquipmentBlueprintA), 1;
            CRAFTQUEST=1;
            mesc l("You got a blueprint as reward for Blue Sage Slimes Quest completion."), 3;
        }
        // If you have TMW2_CRAFT skill, you need the bonus recipe
        if (getskilllv(TMW2_CRAFT)) {
            RECIPES_EQUIPMENT[CraftDagger]=true;
            mesc l("Dagger Crafting recipe learnt."), 2;
        }
        // Bounty Hunter Helmet
        if (MERCENARY_DAILYQUEST > 100) {
            getitem BountyHunterHelmet, 1;
            mesc l("You got a @@ for completing 100+ daily bountyhunter quests!", getitemlink(BountyHunterHelmet)), 2;
        }
        // Cindy quest new rewards
        if (getq(NivalisQuest_Cindy) >= 3) {
            getexp 120000, 0;
            mesc l("You got 120,000 XP for completing Mercury's quest."), 2;
        }
        // Mercenary Rank removed
        if (MERC_RANK) {
            THIEF_RANK=MERC_RANK;
            THIEF_EXP=MERC_EXP;
            MERC_RANK=0;
            MERC_EXP=0;
            mesc l("Your class has been changed from %s to %s.", b(l("Merchant Police")), b(l("Thief"))), 1;
        }
        if (getskilllv(ALL_INCCARRY)) {
            skill TF_STEAL, getskilllv(ALL_INCCARRY);
            skill ALL_INCCARRY, 0, 0;
            mesc l("Increase Weight skill replaced with Stealing.");
        }
        // NEW MAGIC SYSTEM
        if (getskilllv(SN_SHARPSHOOTING)) {
            skill AC_CHARGEARROW, getskilllv(SN_SHARPSHOOTING);
            skill AC_CHARGEARROW, 0, 0;
            getexp 2000, 150;
            mesc l("Sharpshooting skill replaced with Charged Arrow."), 1;
            mesc l("You've got 2000 xp and 150 job xp in apology tokens.");
        }
        getskilllist();
        for (.@i=0; .@i < @skilllist_count; .@i++) {
            // skip temporary skills
            if (@skilllist_flag[.@i] != 0)
                continue;
            // Only “paid” skills will result in a Scholarship Badge
            .@id=@skilllist_id[.@i];
            .@am=0;
            switch (.@id) {
                case SM_BASH:
                case TMW2_DEMURE:
                case MG_FIREBALL:
                case MG_SRECOVERY:
                case AL_DP:
                    .@am=1;
                case SM_ENDURE:
                case KN_AUTOCOUNTER:
                case KN_TWOHANDQUICKEN:
                case AL_ANGELUS:
                case CR_TRUST:
                case CR_DEFENDER:
                case AL_HOLYLIGHT:
                case TF_DETOXIFY:
                case ALL_RESURRECTION:
                case SM_RECOVERY:
                case PR_ASPERSIO:
                case AB_HIGHNESSHEAL:
                case SA_FREECAST:
                case SA_DRAGONOLOGY:
                case TMW2_SAGE:
                case SA_FLAMELAUNCHER:
                case SA_FROSTWEAPON:
                case SA_LIGHTNINGLOADER:
                case SA_SEISMICWEAPON:
                case MG_ENERGYCOAT:
                case MG_NAPALMBEAT:
                case MG_FIREBOLT:
                case MG_COLDBOLT:
                case MG_LIGHTNINGBOLT:
                case WZ_EARTHSPIKE:
                    mesc l("A skill has been replaced with an @@.", getitemlink(ScholarshipBadge));
                    if (!.@am)
                        .@am=min(5, @skilllist_lv[.@i]);

                    getitem ScholarshipBadge, .@am;
                    skill @skilllist_id[.@i], 0, 0;
                    getexp 5, (@skilllist_lv[.@i]-1)*1000;
                    break;
                // Free skills (AL_HEAL and mass provoke) will result in XP
                // Only Jakod's skills with level 3+ will result in a badge
                case AL_HEAL:
                case EVOL_MASS_PROVOKE:
                    if (@skilllist_lv[.@i] >= 3)
                        getitem ScholarshipBadge, 1;
                case SM_PROVOKE:
                case NV_TRICKDEAD:
                    .@delval=@skilllist_lv[.@i];
                    mesc l("A skill has been removed, you got @@ job exp and @@ Strange Coin as an apology token.", .@delval*100, .@delval);
                    skill @skilllist_id[.@i], 0, 0;
                    getexp .@delval, .@delval*100;
                    getitem StrangeCoin, .@delval;
                    break;
            }
        }
        // Grant you AL_DP based on magic level
        if (MAGIC_LVL) {
            skill AL_DP, MAGIC_LVL, 0;
            mesc l("You have learnt \"Divine Protection\" level @@.", MAGIC_LVL), 3;
        }
        // Grant you Thief Skill Tier 3
        if (THIEF_RANK >= 3) {
            skill(ALL_INCCARRY,1,0);
            mesc l("You have learnt \"Increase Weight\" in Thief Skills."), 2;
        }
        // If you got a Scholarship Badge, you need to travel to Tulimshar.
        // Give you a Warp Crystal to do so.
        if (countitem(ScholarshipBadge)) {
            getitem TulimWarpCrystal, 1;
            mesc l("You've obtained a @@ to visit Magic Academy.", getitemlink(TulimWarpCrystal)), 1;
        }
        // Cleanup
        deletearray RNGTREASURE_DATE;

        // Open Beta 2019 Main Event Rewards
        .@u$=strtolower(strcharinfo(0));
        setarray .@officialnick$, "jesusalva", "kolchak", "xanthem", "seeds", "dangerduck", "test123", "sertrop", "lawncable", "pookie", "saulc",
        "apane", "omatt";
        setarray .@expval, 211625, 1955041, 938439, 59663, 73899, 10338, 7494, 7857, 1992, 360, 443, 193, 5180;
        setarray .@gpval,   150321, 863215,   3263, 973137,   5650,  18343,  45227,  42002, 37381, 50000, 50450, 50275, 49988;
        setarray .@summer, 19, 30, 55, 0, 4, 2, 3, 4, 0, 0, 0, 0, 2;
        /* Data for python
        # import exp from exptable
        i=0
        THEARRAY=[]
        while i < len(names):
            raw=overflow[i]
            c=0
            while c < level[i]:
                raw+=exp[c]
                c+=1
            print("%s: %d exp" % (names[i], raw))
            THEARRAY.append(int(raw*0.3))
            i+=1

        setarray .@levelval,    48,     66,     60,     39,     40,     28,     25,     26,    17,    10,    10,     8,    23;
        setarray .@overflow, 25762, 338713,  55746,   1275,  14516,    504,   2855,    640,   360,     0,   277,    18,   598;
        * /

        // Open Beta 2019
        .@ranking=array_find(.@officialnick$, .@u$);
        // Mishana LawnCable bObr Jesusalva demure
        showavatar NPC_LOF_RICH;
        mes "";
        mes "*************************************";
        mes "";
        mesn ("TMW2 Staff");
        mesc l("Hello, @@! We are proud to announce the @@ RESULTS!", strcharinfo(0) , b(l("Open Beta 2019"))), 3;
        mes "";
        mesc l("1st Place - Jesusalva (65)");
        mesc l("2nd Place - Kolchak (63)");
        mesc l("3rd Place - Xanthem (56)");
        mesc l("4th Place - seeds (43)");
        mesc l("5th Place - dangerDuck (23)");
        mesc l("6th Place - test123 (20)");
        mesc l("7th Place - Sertrop (17)");
        mesc l("8th Place - Pookie (13)");
        mesc l("9th Place - LawnCable (13)");
        mesc l("10th Place - Saulc (8)");
        mes "";
        mesc l("It was a reeeeeealy close dispute for the podium, but Jesusalva crafted an item at the last minute and took the first place!");
        mesc l("Although KOLCHAK managed to rank first in almost every ranking, Jesusalva was too close, and the Crafting gave him the edge he needed to take first place.");
        mesc l("Congratulations to everyone who participated on the event, even those who didn't made to the top 10!");
        if (.@ranking >= 0) {
            #ADD_LVL=.@expval[.@ranking];

            // Force Ched quest start if you haven't done so already
            .@year=getq(SQuest_Ched);
            if (.@year != (gettime(GETTIME_YEAR)-2000))
                setq SQuest_Ched, (gettime(GETTIME_YEAR)-2000), 0, 0;


            @ched=getq2(SQuest_Ched);
            .@pts=.@summer[.@ranking];
            if (.@pts) {
                getexp rand2(.@pts-1, .@pts*11/10), rand2(0,.@pts/25);
                setq2 SQuest_Ched, @ched+.@pts;
            }

            switch (.@ranking+1) {
                case 1:
                    getitembound Tyranny, 1, 1;
                    getitem MercBoxEE, 1;
                    getitem EquipmentBlueprintE, 1;
                    getitem HousingLetterI, 1;
                    getitem StrangeCoin, 150;
                    break;
                case 2:
                    getitem MercBoxEE, 1;
                    getitem EquipmentBlueprintE, 1;
                    getitem HousingLetterI, 1;
                    getitem StrangeCoin, 100;
                    break;
                case 3:
                    getitem MercBoxDD, 1;
                    getitem EquipmentBlueprintD, 1;
                    getitem HousingLetterI, 1;
                    getitem StrangeCoin, 100;
                    break;
                case 4:
                case 5:
                    getitem MercBoxCC, 1;
                    getitem EquipmentBlueprintC, 1;
                    getitem HousingLetterI, 1;
                    getitem StrangeCoin, 50;
                    break;
                case 6:
                case 7:
                    getitem MercBoxBB, 1;
                    getitem StrangeCoin, 30;
                    break;
                case 8:
                case 9:
                    getitem MercBoxAA, 1;
                    getitem StrangeCoin, 10;
                    break;
                case 10:
                    getitem MercBoxAA, 1;
                    break;
            } // switch(ranking)

            // GP conversion rules
            // if you have less than 50k, we'll return you to initial amount
            // Because it is a thankyou for participating on the event ;-)
            .@trugp=max(50000, .@gpval[.@ranking]);

            // You get to carry over 1 GP for each 1000 GP too (max 1000 GP bonus)
            Zeny+=min(1000, .@trugp/1000);

            // You'll get 1 Rare Point for every 1k GP obtained
            // Top was 1,000,000 → 1000 rare points
            //#RARE_POINTS+=.@trugp/1000;

        } // if ranking
    }
    // Negative Karma = good. And positive karma allows PvP. So...
    // sex ago  9 18:10:20 -03 2019
    if (UPDATE < 1565385020) {
        UPDATE=1565385020;
        // PVP bugfix
        Karma=0;
        // Allow to skip quest if you already have the Grimorium
        if (countitem(JesusalvaGrimorium) && getskilllv(TMW2_SKILLPERMIT) == 2) {
            skill TMW2_SKILLPERMIT, 3, 0;
        }
        // This can't happen but anyway, just in case...
        if (getskilllv(TMW2_TRANSMIGRATION) > 10) {
            skill TMW2_TRANSMIGRATION, 10, 0;
        }
        // Magic Skill Points for this skill went from 3 to 2
        if (getskilllv(ASC_METEORASSAULT))
            MAGIC_PTS-=1;
        // Treasure Key from Lua
        if (getq(General_Narrator) >= 3)
            getitem TreasureKey, 1;

        // Post-poned Referral Rewards
        if (#REFERRAL_PROG && BaseLevel >= 25 && #REFERRAL_CTRL < 1) {
            #REFERRAL_CTRL=1;
        	rodex_sendmail(gf_charid(#REFERRAL_PROG), "TMW2 Team", "Recruited Player got Lv 25!", strcharinfo(0)+" just got level 25!\nAs they get stronger, more rewards will be sent to you!", 0, SilverGift, 1);
        }
        if (#REFERRAL_PROG && BaseLevel >= 50 && #REFERRAL_CTRL < 2) {
            #REFERRAL_CTRL=2;
        	rodex_sendmail(gf_charid(#REFERRAL_PROG), "TMW2 Team", "Recruited Player got Lv 50!", strcharinfo(0)+" just got level 50!\nAs they get stronger, more rewards will be sent to you!", 0, ArcmageBoxset, 1);
        }
            #REFERRAL_CTRL=3;
        if (#REFERRAL_PROG && BaseLevel >= 75 && #REFERRAL_CTRL < 3) {
        	rodex_sendmail(gf_charid(#REFERRAL_PROG), "TMW2 Team", "Recruited Player got Lv 75!", strcharinfo(0)+" just got level 75!\nAs they get stronger, more rewards will be sent to you!", 0, PrismGift, 1);
        }
        // Eisten Rewards
        if (BaseLevel >= 50 && getq(TulimsharQuest_Eistein) == 2)
            getitem SilverGift, 1;
        if (BaseLevel >= 75 && getq(TulimsharQuest_Eistein) == 3)
            getitem GoldenGift, 1;
        if (BaseLevel >= 75 && getq(TulimsharQuest_Eistein) >= 3)
            getitem GraduationRobe, 1;
        // Grant you Thief Skill Tier 4
        if (THIEF_RANK >= 4) {
            skill(MC_OVERCHARGE,1,0);
            dispbottom l("You have learnt \"Barter\" in Thief Skills.");
        }
        // Update Crafting Score
        CRAFTING_SCORE_COMPLETE=CRAFTING_SCORE*39;
        // Water bug
        if (strcharinfo(0) == "JulieWarhawk") {
            .@dg=true;

            // Sell Bottles
            if (countitem(BottleOfWoodlandWater) > 1) {
                delitem BottleOfWoodlandWater, (countitem(BottleOfWoodlandWater)/2)+1;
            }
            if (countitem(EmptyBottle)) {
                delitem EmptyBottle, countitem(EmptyBottle);
            }
            if (countitem(IcedBottle)) {
                delitem IcedBottle, countitem(IcedBottle);
            }
            getitem ArcmageBoxset, 1;

            // Unjail player
            atcommand "@unjail "+strcharinfo(0);
            mesn "Jesusalva";
            mesq l("You're right, you never sold any Water Bottle ever. I'm unjailing you.");
            mesc l("As an Apology Token, you're also receiving one @@.", getitemlink(ArcmageBoxset));
            next;
        }

        // Bug reward (FF)
        if (strcharinfo(0) == "seeds") {
            getitembound LegendaryMouboo, 1, 1;
        }
    }
    // Old regex messed things up
    // All updates in August are invalid
    // inv ali  d --:--:-- +-- ----
    if (UPDATE > 1564617600 && UPDATE < 1567295999 && UPDATE != 1565385020) {
        UPDATE=1565039378;
        mesn "Narrator";
        mesc l("Warning."), 1;
        mesc l("Warning."), 1;
        mesc l("Warning: Invalid UNIX EPOCH time detected."), 1;
        next;
        mesc l("We'll be correcting this bug automatically now.");
        mesc l("YOU WILL BE DISCONNECTED BY FORCE."), 1;
        mesc l("Please login right after, and this error should not happen again.");
        next;
        // Force user to disconnect
        atcommand "@kick "+strcharinfo(0);
    }
    // Leather Quiver price update
    // qua set  4 11:07:12 -03 2019
    if (UPDATE < 1567606032) {
        UPDATE=1567606032;
        // Leather Quiver update
        if (countitem(LeatherQuiver)) {
            getitem TitaniumOre, countitem(LeatherQuiver)*3;
            getitem Coal, countitem(LeatherQuiver)*2;
            dispbottom l("Titanium Ore and Coal refunded on Leather Quiver update.");
        }
        // Braknar shield recipe
        if (getq(NivalisQuest_Baktar) >= 3) {
            RECIPES_EQUIPMENT[CraftBraknarShield]=true;
            dispbottom l("Braknar Shield Recipe unlocked!");
        }
        // Orby's fix
        if (strcharinfo(0) == "Orby") {
            delinventorylist(); // Needed, because we'll rely on rfind()
            getinventorylist();
            .@index=array_rfind(@inventorylist_id, IronQuiver);
            setitemoptionbyindex(.@index, 0, VAR_VITAMOUNT, 1);
            setitemoptionbyindex(.@index, 1, IOPT_RICHNESS, 1);
            dispbottom l("Iron Quiver stats restored");
            // As Orby is Hurnscald Mayor for this term, fix Hurnscald
            .@df=$HURNS_TAX-100;
            $HURNS_MONEY+=.@df;
            $HURNS_TAX=100;
        }
        // Crazyfefe's fix
        if (strcharinfo(0) == "Crazyfefe") {
            CRAFTING_SCORE_COMPLETE+=30*39;
            CRAFTING_SCORE=CRAFTING_SCORE_COMPLETE/40;
        }
        // Karma fix (double check
        Karma=0;
    }
    // Baktar changes
    // seg out 21 19:32:55 -03 2019
    if (UPDATE < 1571697175) {
        UPDATE=1571697175;
        .@q2=getq2(NivalisQuest_Baktar);
        if (.@q2 & 4)
            setq2 NivalisQuest_Baktar, .@q2^4;
        if (.@q2 & 2)
            Zeny+=1000;
        if (.@q2 & 1)
            Zeny+=1350;
    }
    // Ryan reward remaster + Monthly Reward rewrite
    // qua nov  6 21:15:41 -03 2019
    if (UPDATE < 1573085741) {
        UPDATE=1573085741;
		// Login reward fix
		if (#LOGIN_ALLTIME >= 6 && #UPDATE < 1573085741) {
            dispbottom l("CONGRATULATIONS! For a semester worth of logins, you're getting a pet!");
            makepet Piou;
		}
        #UPDATE=1573085741;

		// Ryan Quest
		if (getq(HalinarzoQuest_LifeDelight) >= 3)
            getitem MylarinDust, 1;

		// Impossible...
		if (getq(HalinarzoQuest_LifeDelight) >= 4)
            getitem SunnyCrystal, 1;
    }
    // Registration Date
    // sáb jan 25 18:30:00 BRT 2020
    if (UPDATE < 1579987800) {
        UPDATE=1579987800;
        if (!#REG_DATE) {
            #REG_DATE=gettimetick(2); // 1520046000 : sáb mar  3 00:00:00 BRT 2018
            // A thank-you for being with us for almost 2 years
            getitem StrangeCoin, 1;
            dispbottom l("Thank you for being with us for so long. You gained a %s as a random good-hearted action from the team!", getitemlink(StrangeCoin));
        }
    }
    // Language over simplification
    // dom fev 16 14:54:30 BRT 2020
    if (UPDATE < 1581875670) {
        UPDATE=1581875670;
        switch (Lang) {
            case 0:
                break;
            case 1: // Old French
                Lang=LANG_FR; break;
            case 3: // Old Spanish
                Lang=LANG_ES; break;
            case 4: // Old Portuguese
                Lang=LANG_PTBR; break;
            case 5: // Old German
                Lang=LANG_DE; break;
            default:
                Lang=99; break;
        }

        if (Lang > MAX_LANG) {
            .@dg=1;
            Lang=0;
            asklanguage();
            mes l("Ok, done.");
        }
    }
    // AFK Time fix
    // dom mar  1 22:05:00 BRT 2020
    if (UPDATE < 1583111100) {
        UPDATE=1583111100;
        unequipbyid(Slippers);
        unequipbyid(AFKCap);
        unequipbyid(Blanket);
        unequipbyid(Bathrobe);
        skill TMW2_SPEECH, 0, 0;
        // PS. All values are ÷ 3
        if (AFKING >= 28800)
            sk_lvup(TMW2_SPEECH); // 24 hours mark
        if (AFKING >= 201600)
            sk_lvup(TMW2_SPEECH); // 7 days mark
        if (AFKING >= 864000)
            sk_lvup(TMW2_SPEECH); // 30 days mark
        if (AFKING >= 2592000)
            sk_lvup(TMW2_SPEECH); // 90 days mark
    }
    // Deprecate event points
    // dom abr 26 12:41:55 BRT 2020
    if (UPDATE < 1587915715) {
        UPDATE=1587915715;

        if (EVENT_POINTS) {
            getitem StrangeCoin, EVENT_POINTS/2;
            EVENT_POINTS=0;
        }

    }
    // Magic v3
    // dom jun 21 05:55:00 BRT 2020
    if (UPDATE < 1592729700) {
        UPDATE=1592729700;
        #FIRST_TIME=true;

        if (getskilllv(TMW2_CRAFT) > 5) {
            // Refund part of the money spent
            Zeny+=35000+(getskilllv(TMW2_CRAFT) > 6 ? 40000 : 0);
            // Update crafting
            skill TMW2_CRAFT, 5, 0;
            dispbottom l("Crafting rules changed! Your crafting skill was lowered to Level 5, talk to Craftmaster to recover it!");
        }

        // Rebirth Heroics
        if (strcharinfo(0) == "Crazyfefe") {
            getitem SupremeGift, 1;
            channelmes("#world", $REBIRTH_WINNER$+" is the first player to REBIRTH!! They are so OP! %%N");
            announce "All hail ##B"+$REBIRTH_WINNER$+"##b, first player to REBIRTH and become OP!", bc_all|bc_npc;
        }

        // Mass Provoke replacement
        if (getskilllv(EVOL_AREA_PROVOKE)) {
            getitembound ScholarshipBadge, getskilllv(EVOL_AREA_PROVOKE), 4;
            MAGIC_PTS-=getskilllv(EVOL_AREA_PROVOKE)+1;
            skill EVOL_AREA_PROVOKE, 0, 0;
            dispbottom col(l("MSP for Area Provoke was refunded."), 1);
        }
        if (getskilllv(EVOL_MASS_PROVOKE)) {
            skill EVOL_AREA_PROVOKE, getskilllv(EVOL_MASS_PROVOKE), 0;
            skill EVOL_MASS_PROVOKE, 0, 0;
            dispbottom col(l("Mass Provoke replaced with Area Provoke."), 1);
        }

        // MG_LIGHTNINGBOLT and TMW2_LIGHTNINGBOLT MSP cost differ, refund
        if (getskilllv(MG_LIGHTNINGBOLT)) {
            getitembound ScholarshipBadge, getskilllv(MG_LIGHTNINGBOLT), 4;
            MAGIC_PTS-=getskilllv(MG_LIGHTNINGBOLT);
            skill MG_LIGHTNINGBOLT, 0, 0;
            dispbottom col(l("MSP for Lightning Strike was refunded."), 1);
        }

        //  SN_WINDWALK MSP cost differ, refund
        if (getskilllv(SN_WINDWALK)) {
            getitembound ScholarshipBadge, getskilllv(SN_WINDWALK), 4;
            MAGIC_PTS-=getskilllv(SN_WINDWALK)+2;
            skill CR_TRUST, 0, 0;
            dispbottom col(l("MSP for Wind Walker was refunded."), 1);
        }

        //  CR_TRUST MSP cost differ, refund
        if (getskilllv(CR_TRUST)) {
            getitembound ScholarshipBadge, getskilllv(CR_TRUST), 4;
            MAGIC_PTS-=getskilllv(CR_TRUST)+2;
            skill CR_TRUST, 0, 0;
            dispbottom col(l("MSP for Last Man Standing was refunded."), 1);
        }


        // Eisten Update
        if (getq(TulimsharQuest_Eistein) > 3) {
            getitem GraduationAlbum, 1;
            dispbottom l("You've got a Graduation Album for Eistein levels!");
        }

    }
    // Magic v3 regression
    // ter jul  7 18:42:22 BRT 2020
    if (UPDATE < 1594158142) {
        UPDATE=1594158142;

        for (.@i=0; .@i < getarraysize($@MSK_MAGIC) ; .@i++) {
            /*
            debugmes "Debug skill %s - Lv %d",
                    getskillname($@MSK_MAGIC[.@i]), getskilllv($@MSK_MAGIC[.@i]);
            * /
            if (getskilllv($@MSK_MAGIC[.@i]) > 1) {
                .@msp=(getskilllv($@MSK_MAGIC[.@i])-1);
                MAGIC_PTS-=.@msp;
                skill $@MSK_MAGIC[.@i], 1, 0;
                dispbottom l("%s refunded to level 1 for %d MSP",
                           getskillname($@MSK_MAGIC[.@i]), .@msp);
            }
        }

    }
    // AFKing bugfix
    // qua jul 29 06:52:00 BRT 2020
    if (UPDATE < 1596016320) {
        UPDATE=1596016320;
        .@x=(AFKING >= 2592000 ? 4 : (
            AFKING >= 864000 ? 3 : (
            AFKING >= 201600 ? 2 : (
            AFKING >= 28800 ? 1 : 0
            ))));
        skill(TMW2_SPEECH, .@x, 0);
        dispbottom l("AFK skill levels fixed.");
    }
    // Magic RP bugfix
    // sáb ago  1 05:45:00 BRT 2020
    if (UPDATE < 1596271500) {
        UPDATE=1596271500;
        .@x=(AFKING >= 2592000 ? 4 : (
            AFKING >= 864000 ? 3 : (
            AFKING >= 201600 ? 2 : (
            AFKING >= 28800 ? 1 : 0
            ))));
        skill(TMW2_SPEECH, .@x, 0);
        dispbottom l("AFK skill levels fixed.");
        for (.@i=0; .@i < getarraysize($@MSK_MAGIC) ; .@i++) {
            if (getskilllv($@MSK_MAGIC[.@i]) > 1) {
                .@msp=max(0, getskilllv(@menuret)-5);
                MAGIC_PTS-=.@msp;
                skill $@MSK_MAGIC[.@i], 1, 0;
                dispbottom l("%s removed - YOU NOOB STOP CHEATING %%e%%Q",
                           getskillname($@MSK_MAGIC[.@i]), .@msp);
            }
        }
    }
    // Skill RP Patch [Magic v3 delayed]
    // ter ago 25 20:20:20 BRT 2020
    if (UPDATE < 1598397620) {
        UPDATE=1598397620;

        // Skills deleted or with poor equivalence
        skillInvoke[EVOL_AREA_PROVOKE]+=skillInvoke[EVOL_MASS_PROVOKE];
        skillInvoke[EVOL_MASS_PROVOKE]=0;

        skillInvoke[TMW2_LIGHTNINGBOLT]+=skillInvoke[MG_LIGHTNINGBOLT];
        skillInvoke[MG_LIGHTNINGBOLT]=0;

        // Skills replaced
        skillInvoke[TMW2_FIREARROW]+=skillInvoke[MG_FIREBALL];
        skillInvoke[MG_FIREBALL]=0;

        skillInvoke[TMW2_NAPALMBEAT]+=skillInvoke[AL_HOLYLIGHT];
        skillInvoke[AL_HOLYLIGHT]=0;

        skillInvoke[TMW2_HOLYLIGHT]+=skillInvoke[MG_NAPALMBEAT];
        skillInvoke[MG_NAPALMBEAT]=0;

        skillInvoke[TMW2_MAGICSTRIKE]+=skillInvoke[MG_SOULSTRIKE];
        skillInvoke[MG_SOULSTRIKE]=0;

        skillInvoke[TMW2_METEORSTRIKE]+=skillInvoke[WZ_EARTHSPIKE];
        skillInvoke[WZ_EARTHSPIKE]=0;

        skillInvoke[TMW2_FROSTDIVER]+=skillInvoke[MG_COLDBOLT];
        skillInvoke[MG_COLDBOLT]=0;

        skillInvoke[TMW2_FROSTNOVA]+=skillInvoke[MG_FROSTDIVER];
        skillInvoke[MG_FROSTDIVER]=0;

        skillInvoke[TMW2_NILFHEIM]+=skillInvoke[WZ_FROSTNOVA];
        skillInvoke[WZ_FROSTNOVA]=0;

        skillInvoke[TMW2_FIRSTAID]+=skillInvoke[AL_HEAL];
        skillInvoke[AL_HEAL]=0;

        skillInvoke[TMW2_HEALING]+=skillInvoke[AB_HIGHNESSHEAL];
        skillInvoke[AB_HIGHNESSHEAL]=0;
    }
    // Misc bugfixes
    // dom nov 22 15:27:47 BRT 2020
    if (UPDATE < 1606069667) {
        UPDATE=1606069667;
        if (RECIPES_EQUIPMENT[0]) {
            Zeny += 15000;
            getitem PrismGift, 1;
            RECIPES_EQUIPMENT[0] = false;
            dispbottom l("Invalid recipe from Nahrec partly reimbursed.");
        }
    }
    */
    // Christmas Warp bug
    // seg dez 28 20:45:55 BRT 2020
    if (UPDATE < 1609199155) {
        UPDATE=1609199155;
        if (BaseLevel < 20) {
            if (getsavepoint(0) != "000-1" &&
                getsavepoint(0) != "003-1" &&
                getsavepoint(0) != "005-1" &&
                getsavepoint(0) != "009-1") {
                // Resave at Candor
                EnterTown("Candor");
                ReturnTown();
            }
        }
        // Assign the initial academic titles
        if (strcharinfo(0) == "Jesus Saves")
            ACADEMIC_RANK=ACADEMIC_GM;
        else if (strcharinfo(0) == "Saulc GM")
            ACADEMIC_RANK=ACADEMIC_GM;
        else if (strcharinfo(0) == "jak2")
            ACADEMIC_RANK=ACADEMIC_GM;
        else if (strcharinfo(0) == "LawnCable")
            ACADEMIC_RANK=ACADEMIC_BACHELOR;
        else if (strcharinfo(0) == "Kolchak")
            ACADEMIC_RANK=ACADEMIC_TECHNIC;
        else if (strcharinfo(0) == "dangerDuck")
            ACADEMIC_RANK=ACADEMIC_TECHNIC;
        else if (strcharinfo(0) == "Livio")
            ACADEMIC_RANK=ACADEMIC_TECHNIC;
        else if (strcharinfo(0) == "Arthur")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Mathias Cronqvist")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Manatauro")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "GoNzO")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "YuckFou")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Xanthem")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Povo")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Esteria")
            ACADEMIC_RANK=ACADEMIC_STUDENT;

        if (ACADEMIC_RANK != ACADEMIC_LAYMAN) {
            // Select a benefactor
            .@benefactor$=rand_sponsor();
            // Inform yourself
            dispbottom l("You received the %s title from %s.",
                         academicrank(), .@benefactor$);
            // Inform everyone
            kamibroadcast(sprintf("%s has been granted the title of %s. Thank %s!",
                          strcharinfo(0), academicrank(), .@benefactor$));
            // Log in a special log file as well
            logmes(sprintf("%s has been granted the title of %s.",
                          strcharinfo(0), academicrank()));
        }

        // Gallery Contest
        .@dg=1;
        showavatar NPC_LOF_RICH;
        mesn ("TMW2 Staff");
        mesc l("Hello, @@! We are proud to announce the @@ RESULTS!", strcharinfo(0) , b(l("2° Screenshooting Contest"))), 3;
        mesc l("Participants: Povo * Manatauro * Woody"), 3;
        next;
        mesc ("Povo Entries: What to do with Presents?"), 3;
        mesc ("Woody Entries: Lava Dungeon"), 3;
        mesc ("Manatauro Entries: Yuck Noob =) ; Povo :) ; Lurking GM and Me"), 3;
        next;
        mesc l("1st Place - Povo (6 likes)");
        mesc l("2nd Place - Manatauro (5 likes)");
        mesc l("3rd Place - Woody (4 likes)");
        mes "";
        next;
        if (strcharinfo(0) == "Povo")
            getitem StrangeCoin, 80;
        else if (strcharinfo(0) == "Manatauro")
            getitem StrangeCoin, 40;
        else if (strcharinfo(0) == "Woody")
            getitem StrangeCoin, 20;
    }
    // Easter Eggs
    // qua jul 29 06:52:00 BRT 2020
    if (UPDATE < 1610083840) {
        UPDATE=1610083840;
        .@q=getq(General_EasterEggs);
        if (.@q) {
            setq General_EasterEggs, 1, .@q, bitmask_count(.@q);
            dispbottom l("Easter Egg quest updated. Total found: %02d/06",
                          bitmask_count(.@q));
        }
    }
    // Change variable scope
    // sáb jan 16 19:21:15 BRT 2021
    if (UPDATE < 1610835675) {
        UPDATE=1610835675;
        #GUILDSHOP=GUILDSHOP;
        GUILDSHOP=0;
    }
    // Post-Fire Titulations
    // ter ago 17 20:02:40 BRT 2021
    if (UPDATE < 1629241360) {
        UPDATE=1629241360;
        // Assign the initial academic titles
        if (strcharinfo(0) == "Jesus Saves")
            ACADEMIC_RANK=ACADEMIC_GM;
        else if (strcharinfo(0) == "Saulc GM")
            ACADEMIC_RANK=ACADEMIC_GM;
        else if (strcharinfo(0) == "jak1")
            ACADEMIC_RANK=ACADEMIC_GM;
        else if (strcharinfo(0) == "dangerDuck")
            ACADEMIC_RANK=ACADEMIC_TECHNIC;
        else if (strcharinfo(0) == "Livio")
            ACADEMIC_RANK=ACADEMIC_TECHNIC;
        else if (strcharinfo(0) == "Xanofire")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Arthur the King")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Mathias Cronqvist")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Mana")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Povo")
            ACADEMIC_RANK=ACADEMIC_STUDENT;
        else if (strcharinfo(0) == "Esteria")
            ACADEMIC_RANK=ACADEMIC_STUDENT;

        //else if (strcharinfo(0) == "LawnCable")
        //    ACADEMIC_RANK=ACADEMIC_BACHELOR;
        //else if (strcharinfo(0) == "Kolchak")
        //    ACADEMIC_RANK=ACADEMIC_TECHNIC;
        //else if (strcharinfo(0) == "GoNzO")
        //    ACADEMIC_RANK=ACADEMIC_STUDENT;
        //else if (strcharinfo(0) == "YuckFou")
        //    ACADEMIC_RANK=ACADEMIC_STUDENT;

        if (ACADEMIC_RANK != ACADEMIC_LAYMAN) {
            // Select a benefactor
            .@benefactor$=rand_sponsor();
            // Inform yourself
            dispbottom l("You received the %s title from %s.",
                         academicrank(), .@benefactor$);
            // Inform everyone
            kamibroadcast(sprintf("%s has been granted the title of %s. Thank %s!",
                          strcharinfo(0), academicrank(), .@benefactor$));
            // Log in a special log file as well
            logmes(sprintf("%s has been granted the title of %s.",
                          strcharinfo(0), academicrank()));
        }
    }
    // Change some quest inner workings
    // qua set 22 12:30:40 BRT 2021
    if (UPDATE < 1632324640) {
        UPDATE=1632324640;
        setq1 HalinarzoQuest_Alvasus, getq(HalinarzoQuest_Alvasus)+1;
    }
    // Christmas 2021
    // ter dez 28 11:57:17 BRT 2021
    if (UPDATE < 1640703437) {
        .@u$ = strtolower(strcharinfo(0));
        setarray .@xmas21$, "jesusalva", "poppet", "jak1", "horak", "hocus pocus fidibus", "statue";
        setarray .@xmas20$, "andulkat", "kolchak", "Pacman_I_I";
        if (array_exists(.@xmas21$, .@u$)) {
                .@dg=1;
                showavatar NPC_LOF_RICH;
                mesn ("TMW2 Staff");
                mesc l("Hello, %s! Congratulations for finishing the %s!", strcharinfo(0), b(l("Christmas 2021 Joint Event"))), 3;
                mesc l("You need to pick your prizes!"), 3;
                inventoryplace NPCEyes, 6, Iten, 5;
                next;
                mesc l("Select one:"), 3;
                menuint
                    l("Elixir of Life"), ElixirOfLife,
                    l("Sacred Immortality Potion"), SacredImmortalityPotion;
                mes "";
                .@it1 = @menuret;
                mesc l("Select one:"), 3;
                menuint
                    l("Short Gunstaff"), PynRevolver,
                    l("Rapid Gunstaff"), PynGatling,
                    l("Explosive Gunstaff"), PynShotgun,
                    l("Powerful Gunstaff"), PynRifle;
                mes "";
                .@it2 = @menuret;
                getitem .@it1, 5;
                getitembound .@it2, 1, 1;
                getitem GoldenBossGift, 1;
                getitem SupremeGift, 1;
                getitem MagicApple, 1;
                getitem Arcanum, 1;
                getitem StrangeCoin, 30;
        } else if (array_exists(.@xmas20$, .@u$)) {
                getitem Arcanum, 1;
                getitem StrangeCoin, 30;
        }
        UPDATE=1640703437;
        // misc fixes
        if (getq(LoFQuest_George) >= 3)
            getexp 45000, 0;
        if (getq(LoFQuest_George) >= 5)
            getexp 135000, 0;
        if (getq2(HalinarzoQuest_LifeDelight) >= 20)
            getitem Coffee, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 30)
            getitem Manapple, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 40)
            getitem LoFWarpCrystal, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 60)
            getitem SacredLifePotion, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 70)
            getitem MercBoxDD, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 80)
            getitem DivineApple, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 90)
            getitem MysteriousFruit, 1;
        if (getq2(HalinarzoQuest_LifeDelight) >= 21)
            Mobpt+=((getq2(HalinarzoQuest_LifeDelight) - 1) * (getq2(HalinarzoQuest_LifeDelight) - 20)); // Will work... Sort of
    }
    // Realm of Drops
    // sab set 24 15:37:15 BRT 2022
    if (UPDATE < 1664044635) {
        UPDATE=1664044635;
        skill TMW2_DROPS, REBIRTH+1, 0;
        if (getskilllv(TMW2_SKILLPERMIT) >= 1)
            getitem ScholarshipBadge, 1;
        if (getskilllv(TMW2_SKILLPERMIT) >= 2)
            getexp 20000, 1000;
        if (getskilllv(TMW2_SKILLPERMIT) >= 3)
            getexp 80000, 0;
        // Actual value has changed, you'll be refunded in EXP
        if (getskilllv(TMW2_SKILLPERMIT) >= 1)
            #ADD_LVL+=80000;
    }
    // Dausen update
    // dom out 22 13:15:32 BRT 2022
    if (UPDATE < 1666541732) {
        UPDATE=1666541732;
        if (getq(TulimsharQuest_MobTutorial) >= 2)
            Zeny+=246;
        if (getq(TulimsharQuest_MobTutorial) >= 4)
            Zeny+=616;
        if (getq(TulimsharQuest_MobTutorial) >= 6)
            Zeny+=1068;
        if (getq(TulimsharQuest_MobTutorial) >= 8)
            Zeny+=2200;
    }
    // Balance update
    // sáb 26 nov 2022 16:44:35 -03
    if (UPDATE < 1669491875) {
        UPDATE=1669491875;
        if (getq(HurnscaldQuest_ForestBow))
            getitem TrainingArrow, 220;
        if (getq3(TulimsharQuest_Swezanne) > 30)
            getitem MercCard_Swezanne, 9 * (getq3(TulimsharQuest_Swezanne)/30);
        if (getq(TulimsharQuest_MobTutorial) >= 4)
            getitem SulfurPowder, 1;
        if (getq(TulimsharQuest_MobTutorial) >= 8)
            getitem SulfurPowder, 3;
        if (TUT_VAR) {
            .@dg = true;
            setpcblock(PCBLOCK_HARD, true);
            // Allow you to choose the starting trait
            // However, we unset #TUTORIAL_DONE so EXP Gain and Knockback are OFF
            // While alts are generally allowed to have these starting traits,
            // there's no way for veterans select this.
            #TUTORIAL_DONE = false;
            do { mesc l("You must choose a trait now, or the opportunity will be forfeit."), 1; next; } while (!ChooseTrait());
            #TUTORIAL_DONE = true;
            setpcblock(PCBLOCK_HARD, false);
        }
    }
    // Char-Server crash
    // sex 09 dez 2022 21:51:40 -03
    if (UPDATE < 1670633500) {
        UPDATE=1670633500;
        setarray .@accid, 2000000, 2000005, 2000008, 2000114, 2000267, 2000474, 2000505, 2000539, 2000777, 2000782, 2000803, 2000816, 2000817, 2000819, 2000820, 2000821, 2000822, 2000823, 2000824, 2000825, 2000826, 2000827;
		if (array_exists(.@accid, getcharid(3)) && #UPDATE < 1670633500) {
            rodex_sendmail(getcharid(0), "TMW Team", "Char-Server Crash", "Due to a disk issue, char server died and quest progress was lost.\nThis is an apology.", 5000, MaggotSlime, 10, BugLeg, 10, Beer, 3, IronOre, 2);
		}
        #UPDATE=1670633500;
    }

    // :// End of Regular Update System
    ////////////////////////////////////
    // Valentine 2020 Record
    if (#VALENTINE20_REWARDS) {
        .@dg=1;
        // Get misc items
        getitem OolongTea, 3;
        getitem SpearmintTea, 5;
        getitem CrazyRum, 1;
        getitem DwarvenSake, 3;
        dispbottom col(l("THANK YOU for participating on cross-server Valentine 2020 Event! We hope you had fun!"), 7);
        #VALENTINE20_REWARDS=false;
    }

    // Permanent Gold Boost
    // #ADD_GP means the user have to right to get some gp
    if (#ADD_GP) {
        Zeny+=#ADD_GP;
        #ADD_GP=0;
    }

    // Permanent Strange Coins Boost
    // #ADD_SC means the user have to right to get some strange coins
    if (#ADD_SC) {
        logmes "[Merger] Strange Coins +"+#ADD_SC, LOGMES_ATCOMMAND;
        getitem StrangeCoin, #ADD_SC;
        #ADD_SC=0;
    }

    // Permanent Monster Points Boost
    // #ADD_MPT means the user have to right to get some Mobpt
    if (#ADD_MPT) {
        logmes "[Merger] Mobpt +"+#ADD_MPT, LOGMES_ATCOMMAND;
        Mobpt+=#ADD_MPT;
        #ADD_MPT=0;
    }

    // Non Permament Level Boost
    if (#ADD_TMP_LVL) {
        // Grant the level
        if (numdate() <= 20200216 && !#SAVED_LVL) {
            #SAVED_LVL=BaseLevel;
            BaseLevel=#ADD_TMP_LVL;
            dispbottom l("Level set from %d to %d", #SAVED_LVL, BaseLevel);

            // Welcome message
            .@dg=true;
            showavatar NPC_LOF_RICH;
            mesn "Moubootaur Legends Server";
            mesc l("First of all: Welcome! Your level was temporaly modified, it'll be reverted once event is over."), 3;
            next;
            mesn "Moubootaur Legends Server";
            mesc l("You will be able to pick basic weapons and skills at the Event Soul Menhir."), 3;
            next;
            mesn "Moubootaur Legends Server";
            mesc l("Be careful during night, use \"@tutorial\" in case of doubt, use \"%s\" to go to the event, and good luck!", b("@toevent")), 3;
            next;
        // Restore the level
        } else if (numdate() > 20200216 && #SAVED_LVL) {
            dispbottom l("Level reset from %d to %d", BaseLevel, #SAVED_LVL);
            // Save
            #DEBUG_LEVEL1=#ADD_TMP_LVL;
            #DEBUG_LEVEL2=BaseLevel;
            #DEBUG_LEVEL3=#DEBUG_LEVEL2-#DEBUG_LEVEL1;
            #DEBUG_EXP=BaseExp;
            // Reset
            //BaseLevel=#SAVED_LVL;
            //#SAVED_LVL=0;
            #ADD_TMP_LVL=0;
        // Player too late for event!
        } else if (numdate() > 20200216) {
            dispbottom l("This event has already ended.");
            #ADD_TMP_LVL=0;
        }
    }

    if (.@dg) {
        next;
        closeclientdialog;
    }
    return;

}

// Just be sure your client version is OK
// NOTE: Current master client version is 26, but M+ 1.9.3.23 is still at 25
function	script	checkclientversion	{
    // Destroy Karma, regardless of version and perpetually
    Karma=0;

    // Minimum version
    if (ClientVersion >= 25)
        return;

    mesn "Narrator";
    mesc l("Warning."), 1;
    mesc l("Warning."), 1;
    mesc l("Warning: You are using an old client."), 1;
    next;
    //mesc l("Please install the new client from [@@https://manaplus.org/|https://manaplus.org/@@]");
    mesc l("Alternatively, download a bleeding edge build at [@@https://manaplus.germantmw.de/|https://manaplus.germantmw.de/@@]");
    mesc l("Or use our awesome [@@https://tmw2.org/manalauncher/InstallManaLauncher.exe|Mana Launcher@@] if you're on Windows or Linux.");
    next;
    if (ClientVersion >= 24) mesc l("Compatibility Support mode enabled. Client may crash AT RANDOM, beware.");
    if (ClientVersion >= 24) mesc l("Crazy stuff can happen in overall. YOU HAVE BEEN WARNED TO UPDATE YOUR CLIENT.");
    if (ClientVersion >= 24) closeclientdialog;
    if (ClientVersion >= 24) return;
    mesc l("You won't be allowed to play this game until you have an updated client.");
    next;
    // Force user to disconnect
    atcommand "@kick "+strcharinfo(0);
    return;
}