Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Save New Duplicate & Edit Just Text Twitter
- 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
- 1220
- 1221
- 1222
- 1223
- 1224
- 1225
- 1226
- 1227
- 1228
- 1229
- 1230
- 1231
- 1232
- 1233
- 1234
- 1235
- 1236
- 1237
- 1238
- 1239
- 1240
- 1241
- 1242
- 1243
- 1244
- 1245
- 1246
- 1247
- 1248
- 1249
- 1250
- 1251
- 1252
- 1253
- 1254
- 1255
- 1256
- 1257
- 1258
- 1259
- 1260
- 1261
- 1262
- 1263
- 1264
- 1265
- 1266
- 1267
- 1268
- 1269
- 1270
- 1271
- 1272
- 1273
- 1274
- 1275
- 1276
- 1277
- 1278
- 1279
- 1280
- 1281
- 1282
- 1283
- 1284
- 1285
- 1286
- 1287
- 1288
- 1289
- 1290
- 1291
- 1292
- 1293
- 1294
- 1295
- 1296
- 1297
- 1298
- 1299
- 1300
- 1301
- 1302
- 1303
- 1304
- 1305
- 1306
- 1307
- 1308
- 1309
- 1310
- 1311
- 1312
- 1313
- 1314
- 1315
- 1316
- 1317
- 1318
- 1319
- 1320
- 1321
- 1322
- 1323
- 1324
- 1325
- 1326
- 1327
- 1328
- 1329
- 1330
- 1331
- 1332
- 1333
- 1334
- 1335
- 1336
- 1337
- 1338
- 1339
- 1340
- 1341
- 1342
- 1343
- 1344
- 1345
- 1346
- 1347
- 1348
- 1349
- 1350
- 1351
- 1352
- 1353
- 1354
- 1355
- 1356
- 1357
- 1358
- 1359
- 1360
- 1361
- 1362
- 1363
- 1364
- 1365
- 1366
- 1367
- 1368
- 1369
- 1370
- 1371
- 1372
- 1373
- 1374
- 1375
- 1376
- 1377
- 1378
- 1379
- 1380
- 1381
- 1382
- 1383
- 1384
- 1385
- 1386
- 1387
- 1388
- 1389
- 1390
- 1391
- 1392
- 1393
- 1394
- 1395
- 1396
- 1397
- 1398
- 1399
- 1400
- 1401
- 1402
- 1403
- 1404
- 1405
- 1406
- 1407
- 1408
- 1409
- 1410
- 1411
- 1412
- 1413
- 1414
- 1415
- 1416
- 1417
- 1418
- 1419
- 1420
- 1421
- 1422
- 1423
- 1424
- 1425
- 1426
- 1427
- 1428
- 1429
- 1430
- 1431
- 1432
- 1433
- 1434
- 1435
- 1436
- 1437
- 1438
- 1439
- 1440
- 1441
- 1442
- 1443
- 1444
- 1445
- 1446
- 1447
- 1448
- 1449
- 1450
- 1451
- 1452
- 1453
- 1454
- 1455
- 1456
- 1457
- 1458
- 1459
- 1460
- 1461
- 1462
- 1463
- 1464
- 1465
- 1466
- 1467
- 1468
- 1469
- 1470
- 1471
- 1472
- 1473
- 1474
- 1475
- 1476
- 1477
- 1478
- 1479
- 1480
- 1481
- 1482
- 1483
- 1484
- 1485
- 1486
- 1487
- 1488
- 1489
- 1490
- 1491
- 1492
- 1493
- 1494
- 1495
- 1496
- 1497
- 1498
- 1499
- 1500
- 1501
- 1502
- 1503
- 1504
- 1505
- 1506
- 1507
- 1508
- 1509
- 1510
- 1511
- 1512
- 1513
- 1514
- 1515
- 1516
- 1517
- 1518
- 1519
- 1520
- 1521
- 1522
- 1523
- 1524
- 1525
- 1526
- 1527
- 1528
- 1529
- 1530
- 1531
- 1532
- 1533
- 1534
- 1535
- 1536
- 1537
- 1538
- 1539
- 1540
- 1541
- 1542
- 1543
- 1544
- 1545
- 1546
- 1547
- 1548
- 1549
- 1550
- 1551
- 1552
- 1553
- 1554
- 1555
- 1556
- 1557
- 1558
- 1559
- 1560
- 1561
- 1562
- 1563
- 1564
- 1565
- 1566
- 1567
- 1568
- 1569
- 1570
- 1571
- 1572
- 1573
- 1574
- 1575
- 1576
- 1577
- 1578
- 1579
- 1580
- 1581
- 1582
- 1583
- 1584
- 1585
- 1586
- 1587
- 1588
- 1589
- 1590
- 1591
- 1592
- 1593
- 1594
- 1595
- 1596
- 1597
- 1598
- 1599
- 1600
- 1601
- 1602
- 1603
- 1604
- 1605
- 1606
- 1607
- 1608
- 1609
- 1610
- 1611
- 1612
- 1613
- 1614
- 1615
- 1616
- 1617
- 1618
- 1619
- 1620
- 1621
- 1622
- 1623
- 1624
- 1625
- 1626
- 1627
- 1628
- 1629
- 1630
- 1631
- 1632
- 1633
- 1634
- 1635
- 1636
- 1637
- 1638
- 1639
- 1640
- 1641
- 1642
- 1643
- 1644
- 1645
- 1646
- 1647
- 1648
- 1649
- 1650
- 1651
- 1652
- 1653
- 1654
- 1655
- 1656
- 1657
- 1658
- 1659
- 1660
- 1661
- 1662
- 1663
- 1664
- 1665
- 1666
- 1667
- 1668
- 1669
- 1670
- 1671
- 1672
- 1673
- 1674
- 1675
- 1676
- 1677
- 1678
- 1679
- 1680
- 1681
- 1682
- 1683
- 1684
- 1685
- 1686
- 1687
- 1688
- 1689
- 1690
- 1691
- 1692
- 1693
- 1694
- 1695
- 1696
- 1697
- 1698
- 1699
- 1700
- 1701
- 1702
- 1703
- 1704
- 1705
- 1706
- 1707
- 1708
- 1709
- 1710
- 1711
- 1712
- 1713
- 1714
- 1715
- 1716
- 1717
- 1718
- 1719
- 1720
- 1721
- 1722
- 1723
- 1724
- 1725
- 1726
- 1727
- 1728
- 1729
- 1730
- 1731
- 1732
- 1733
- 1734
- 1735
- 1736
- 1737
- 1738
- 1739
- 1740
- 1741
- 1742
- 1743
- 1744
- 1745
- 1746
- 1747
- 1748
- 1749
- 1750
- 1751
- 1752
- 1753
- 1754
- 1755
- 1756
- 1757
- 1758
- 1759
- 1760
- 1761
- 1762
- 1763
- 1764
- 1765
- 1766
- 1767
- 1768
- 1769
- 1770
- 1771
- 1772
- 1773
- 1774
- 1775
- 1776
- 1777
- 1778
- 1779
- 1780
- 1781
- 1782
- 1783
- 1784
- 1785
- 1786
- 1787
- 1788
- 1789
- 1790
- 1791
- 1792
- 1793
- 1794
- 1795
- 1796
- 1797
- 1798
- 1799
- 1800
- 1801
- 1802
- 1803
- 1804
- 1805
- 1806
- 1807
- 1808
- 1809
- 1810
- 1811
- 1812
- 1813
- 1814
- 1815
- 1816
- 1817
- 1818
- 1819
- 1820
- 1821
- 1822
- 1823
- 1824
- 1825
- 1826
- 1827
- 1828
- 1829
- 1830
- 1831
- 1832
- 1833
- 1834
- 1835
- 1836
- 1837
- 1838
- 1839
- 1840
- 1841
- 1842
- 1843
- 1844
- 1845
- 1846
- 1847
- 1848
- 1849
- 1850
- 1851
- 1852
- 1853
- 1854
- 1855
- 1856
- 1857
- 1858
- 1859
- 1860
- 1861
- 1862
- 1863
- 1864
- 1865
- 1866
- 1867
- 1868
- 1869
- 1870
- 1871
- 1872
- 1873
- 1874
- 1875
- 1876
- 1877
- 1878
- 1879
- 1880
- 1881
- 1882
- 1883
- 1884
- 1885
- 1886
- 1887
- 1888
- 1889
- 1890
- 1891
- 1892
- 1893
- 1894
- 1895
- 1896
- 1897
- 1898
- 1899
- 1900
- 1901
- 1902
- 1903
- 1904
- 1905
- 1906
- 1907
- 1908
- 1909
- 1910
- 1911
- 1912
- 1913
- 1914
- 1915
- 1916
- 1917
- 1918
- 1919
- 1920
- 1921
- 1922
- 1923
- 1924
- 1925
- 1926
- 1927
- 1928
- 1929
- 1930
- 1931
- 1932
- 1933
- 1934
- 1935
- 1936
- 1937
- 1938
- 1939
- 1940
- 1941
- 1942
- 1943
- 1944
- 1945
- 1946
- 1947
- 1948
- 1949
- 1950
- 1951
- 1952
- 1953
- 1954
- 1955
- 1956
- 1957
- 1958
- 1959
- 1960
- 1961
- 1962
- 1963
- 1964
- 1965
- 1966
- 1967
- 1968
- 1969
- 1970
- 1971
- 1972
- 1973
- 1974
- 1975
- 1976
- 1977
- 1978
- 1979
- 1980
- 1981
- 1982
- 1983
- 1984
- 1985
- 1986
- 1987
- 1988
- 1989
- 1990
- 1991
- 1992
- 1993
- 1994
- 1995
- 1996
- 1997
- 1998
- 1999
- 2000
- 2001
- 2002
- 2003
- 2004
- 2005
- 2006
- 2007
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019
- 2020
- 2021
- 2022
- 2023
- 2024
- 2025
- 2026
- 2027
- 2028
- 2029
- 2030
- 2031
- 2032
- 2033
- 2034
- 2035
- 2036
- 2037
- 2038
- 2039
- 2040
- 2041
- 2042
- 2043
- 2044
- 2045
- 2046
- 2047
- 2048
- 2049
- 2050
- 2051
- 2052
- 2053
- 2054
- 2055
- 2056
- 2057
- 2058
- 2059
- 2060
- 2061
- 2062
- 2063
- 2064
- 2065
- 2066
- 2067
- 2068
- 2069
- 2070
- 2071
- 2072
- 2073
- 2074
- 2075
- 2076
- 2077
- 2078
- 2079
- 2080
- 2081
- 2082
- 2083
- 2084
- 2085
- 2086
- 2087
- 2088
- 2089
- 2090
- 2091
- 2092
- 2093
- 2094
- 2095
- 2096
- 2097
- 2098
- 2099
- 2100
- 2101
- 2102
- 2103
- 2104
- 2105
- 2106
- 2107
- 2108
- 2109
- 2110
- 2111
- 2112
- 2113
- 2114
- 2115
- 2116
- 2117
- 2118
- 2119
- 2120
- 2121
- 2122
- 2123
- 2124
- 2125
- 2126
- 2127
- 2128
- 2129
- 2130
- 2131
- 2132
- 2133
- 2134
- 2135
- 2136
- 2137
- 2138
- 2139
- 2140
- 2141
- 2142
- 2143
- 2144
- 2145
- 2146
- 2147
- 2148
- 2149
- 2150
- 2151
- 2152
- 2153
- 2154
- 2155
- 2156
- 2157
- 2158
- 2159
- 2160
- 2161
- 2162
- 2163
- 2164
- 2165
- 2166
- 2167
- 2168
- 2169
- 2170
- 2171
- 2172
- 2173
- 2174
- 2175
- 2176
- 2177
- 2178
- 2179
- 2180
- 2181
- 2182
- 2183
- 2184
- 2185
- 2186
- 2187
- 2188
- 2189
- 2190
- 2191
- 2192
- 2193
- 2194
- 2195
- 2196
- 2197
- 2198
- 2199
- 2200
- 2201
- 2202
- 2203
- 2204
- 2205
- 2206
- 2207
- 2208
- 2209
- 2210
- 2211
- 2212
- 2213
- 2214
- 2215
- 2216
- 2217
- 2218
- 2219
- 2220
- 2221
- 2222
- 2223
- 2224
- 2225
- 2226
- 2227
- 2228
- 2229
- 2230
- 2231
- 2232
- 2233
- 2234
- 2235
- 2236
- 2237
- 2238
- 2239
- 2240
- 2241
- 2242
- 2243
- 2244
- 2245
- 2246
- 2247
- 2248
- 2249
- 2250
- 2251
- 2252
- 2253
- 2254
- 2255
- 2256
- 2257
- 2258
- 2259
- 2260
- 2261
- 2262
- 2263
- 2264
- 2265
- 2266
- 2267
- 2268
- 2269
- 2270
- 2271
- 2272
- 2273
- 2274
- 2275
- 2276
- 2277
- 2278
- 2279
- 2280
- 2281
- 2282
- 2283
- 2284
- 2285
- 2286
- 2287
- 2288
- 2289
- 2290
- 2291
- 2292
- 2293
- 2294
- 2295
- 2296
- 2297
- 2298
- 2299
- 2300
- 2301
- 2302
- 2303
- 2304
- 2305
- 2306
- 2307
- 2308
- 2309
- 2310
- 2311
- 2312
- 2313
- 2314
- 2315
- 2316
- 2317
- 2318
- 2319
- 2320
- 2321
- 2322
- 2323
- 2324
- 2325
- 2326
- 2327
- 2328
- 2329
- 2330
- 2331
- 2332
- 2333
- 2334
- 2335
- 2336
- 2337
- 2338
- 2339
- 2340
- 2341
- 2342
- 2343
- 2344
- 2345
- 2346
- 2347
- 2348
- 2349
- 2350
- 2351
- 2352
- 2353
- 2354
- 2355
- 2356
- 2357
- 2358
- 2359
- 2360
- 2361
- 2362
- 2363
- 2364
- 2365
- 2366
- 2367
- 2368
- 2369
- 2370
- 2371
- 2372
- 2373
- 2374
- 2375
- 2376
- 2377
- 2378
- 2379
- 2380
- 2381
- 2382
- 2383
- 2384
- 2385
- 2386
- 2387
- 2388
- 2389
- 2390
- 2391
- 2392
- 2393
- 2394
- 2395
- 2396
- 2397
- 2398
- 2399
- 2400
- 2401
- 2402
- 2403
- 2404
- 2405
- 2406
- 2407
- 2408
- 2409
- 2410
- 2411
- 2412
- 2413
- 2414
- 2415
- 2416
- 2417
- 2418
- 2419
- 2420
- 2421
- 2422
- 2423
- 2424
- 2425
- 2426
- 2427
- 2428
- 2429
- 2430
- 2431
- 2432
- 2433
- 2434
- 2435
- 2436
- 2437
- 2438
- 2439
- 2440
- 2441
- 2442
- 2443
- 2444
- 2445
- 2446
- 2447
- 2448
- 2449
- 2450
- 2451
- 2452
- 2453
- 2454
- 2455
- 2456
- 2457
- 2458
- 2459
- 2460
- 2461
- 2462
- 2463
- 2464
- 2465
- 2466
- 2467
- 2468
- 2469
- 2470
- 2471
- 2472
- 2473
- 2474
- 2475
- 2476
- 2477
- 2478
- 2479
- 2480
- 2481
- 2482
- 2483
- 2484
- 2485
- 2486
- 2487
- 2488
- 2489
- 2490
- 2491
- 2492
- 2493
- 2494
- 2495
- 2496
- 2497
- 2498
- 2499
- 2500
- 2501
- 2502
- 2503
- 2504
- 2505
- 2506
- 2507
- 2508
- 2509
- 2510
- 2511
- 2512
- 2513
- 2514
- 2515
- 2516
- 2517
- 2518
- 2519
- 2520
- 2521
- 2522
- 2523
- 2524
- 2525
- 2526
- 2527
- 2528
- 2529
- 2530
- 2531
- 2532
- 2533
- 2534
- 2535
- 2536
- 2537
- 2538
- 2539
- 2540
- 2541
- 2542
- 2543
- 2544
- 2545
- 2546
- 2547
- 2548
- 2549
- 2550
- 2551
- 2552
- 2553
- 2554
- 2555
- 2556
- 2557
- 2558
- 2559
- 2560
- 2561
- 2562
- 2563
- 2564
- 2565
- 2566
- 2567
- 2568
- 2569
- 2570
- 2571
- 2572
- 2573
- 2574
- 2575
- 2576
- 2577
- 2578
- 2579
- 2580
- 2581
- 2582
- 2583
- 2584
- 2585
- 2586
- 2587
- 2588
- 2589
- 2590
- 2591
- 2592
- 2593
- 2594
- 2595
- 2596
- 2597
- 2598
- 2599
- 2600
- 2601
- 2602
- 2603
- 2604
- 2605
- 2606
- 2607
- 2608
- 2609
- 2610
- 2611
- 2612
- 2613
- 2614
- 2615
- 2616
- 2617
- 2618
- 2619
- 2620
- 2621
- 2622
- 2623
- 2624
- 2625
- 2626
- 2627
- 2628
- 2629
- 2630
- 2631
- 2632
- 2633
- 2634
- 2635
- 2636
- 2637
- 2638
- 2639
- 2640
- 2641
- 2642
- 2643
- 2644
- 2645
- 2646
- 2647
- 2648
- 2649
- 2650
- 2651
- 2652
- 2653
- 2654
- 2655
- 2656
- 2657
- 2658
- 2659
- 2660
- 2661
- 2662
- 2663
- 2664
- 2665
- 2666
- 2667
- 2668
- 2669
- 2670
- 2671
- 2672
- 2673
- 2674
- 2675
- 2676
- 2677
- 2678
- 2679
- 2680
- 2681
- 2682
- 2683
- 2684
- 2685
- 2686
- 2687
- 2688
- 2689
- 2690
- 2691
- 2692
- 2693
- 2694
- 2695
- 2696
- 2697
- 2698
- 2699
- 2700
- 2701
- 2702
- 2703
- 2704
- 2705
- 2706
- 2707
- 2708
- 2709
- 2710
- 2711
- 2712
- 2713
- 2714
- 2715
- 2716
- 2717
- 2718
- 2719
- 2720
- 2721
- 2722
- 2723
- 2724
- 2725
- 2726
- 2727
- 2728
- 2729
- 2730
- 2731
- 2732
- 2733
- 2734
- 2735
- 2736
- 2737
- 2738
- 2739
- 2740
- 2741
- 2742
- 2743
- 2744
- 2745
- 2746
- 2747
- 2748
- 2749
- 2750
- 2751
- 2752
- 2753
- 2754
- 2755
- 2756
- 2757
- 2758
- 2759
- 2760
- 2761
- 2762
- 2763
- 2764
- 2765
- 2766
- 2767
- 2768
- 2769
- 2770
- 2771
- 2772
- 2773
- 2774
- 2775
- 2776
- 2777
- 2778
- 2779
- 2780
- 2781
- 2782
- 2783
- 2784
- 2785
- 2786
- 2787
- 2788
- 2789
- 2790
- 2791
- 2792
- 2793
- 2794
- 2795
- 2796
- 2797
- 2798
- 2799
- 2800
- 2801
- 2802
- 2803
- 2804
- 2805
- 2806
- 2807
- 2808
- 2809
- 2810
- 2811
- 2812
- 2813
- 2814
- 2815
- 2816
- 2817
- 2818
- 2819
- 2820
- 2821
- 2822
- 2823
- 2824
- 2825
- 2826
- 2827
- 2828
- 2829
- 2830
- 2831
- 2832
- 2833
- 2834
- 2835
- 2836
- 2837
- 2838
- 2839
- 2840
- 2841
- 2842
- 2843
- 2844
- 2845
- 2846
- 2847
- 2848
- 2849
- 2850
- 2851
- 2852
- 2853
- 2854
- 2855
- 2856
- 2857
- 2858
- 2859
- 2860
- 2861
- 2862
- 2863
- 2864
- 2865
- 2866
- 2867
- 2868
- 2869
- 2870
- 2871
- 2872
- 2873
- 2874
- 2875
- 2876
- 2877
- 2878
- 2879
- 2880
- 2881
- 2882
- 2883
- 2884
- 2885
- 2886
- 2887
- 2888
- 2889
- 2890
- 2891
- 2892
- 2893
- 2894
- 2895
- 2896
- 2897
- 2898
- 2899
- 2900
- 2901
- 2902
- 2903
- 2904
- 2905
- 2906
- 2907
- 2908
- 2909
- 2910
- 2911
- 2912
- 2913
- 2914
- 2915
- 2916
- 2917
- 2918
- 2919
- 2920
- 2921
- 2922
- 2923
- 2924
- 2925
- 2926
- 2927
- 2928
- 2929
- 2930
- 2931
- 2932
- 2933
- 2934
- 2935
- 2936
- 2937
- 2938
- 2939
- 2940
- 2941
- 2942
- 2943
- 2944
- 2945
- 2946
- 2947
- 2948
- 2949
- 2950
- 2951
- 2952
- 2953
- 2954
- 2955
- 2956
- 2957
- 2958
- 2959
- 2960
- 2961
- 2962
- 2963
- 2964
- 2965
- 2966
- 2967
- 2968
- 2969
- 2970
- 2971
- 2972
- 2973
- 2974
- 2975
- 2976
- 2977
- 2978
- 2979
- 2980
- 2981
- 2982
- 2983
- 2984
- 2985
- 2986
- 2987
- 2988
- 2989
- 2990
- 2991
- 2992
- 2993
- 2994
- 2995
- 2996
- 2997
- 2998
- 2999
- 3000
- 3001
- 3002
- 3003
- 3004
- 3005
- 3006
- 3007
- 3008
- 3009
- 3010
- 3011
- 3012
- 3013
- 3014
- 3015
- 3016
- 3017
- 3018
- 3019
- 3020
- 3021
- 3022
- 3023
- 3024
- 3025
- 3026
- 3027
- 3028
- 3029
- 3030
- 3031
- 3032
- 3033
- 3034
- 3035
- 3036
- 3037
- 3038
- 3039
- 3040
- 3041
- 3042
- 3043
- 3044
- 3045
- 3046
- 3047
- 3048
- 3049
- 3050
- 3051
- 3052
- 3053
- 3054
- 3055
- 3056
- 3057
- 3058
- 3059
- 3060
- 3061
- 3062
- 3063
- 3064
- 3065
- 3066
- 3067
- 3068
- 3069
- 3070
- 3071
- 3072
- 3073
- 3074
- 3075
- 3076
- 3077
- 3078
- 3079
- 3080
- 3081
- 3082
- 3083
- 3084
- 3085
- 3086
- 3087
- 3088
- 3089
- 3090
- 3091
- 3092
- 3093
- 3094
- 3095
- 3096
- 3097
- 3098
- 3099
- 3100
- 3101
- 3102
- 3103
- 3104
- 3105
- 3106
- 3107
- 3108
- 3109
- 3110
- 3111
- 3112
- 3113
- 3114
- 3115
- 3116
- 3117
- 3118
- 3119
- 3120
- 3121
- 3122
- 3123
- 3124
- 3125
- 3126
- 3127
- 3128
- 3129
- 3130
- 3131
- 3132
- 3133
- 3134
- 3135
- 3136
- 3137
- 3138
- 3139
- 3140
- 3141
- 3142
- 3143
- 3144
- 3145
- 3146
- 3147
- 3148
- 3149
- 3150
- 3151
- 3152
- 3153
- 3154
- 3155
- 3156
- 3157
- 3158
- 3159
- 3160
- 3161
- 3162
- 3163
- 3164
- 3165
- 3166
- 3167
- 3168
- 3169
- 3170
- 3171
- 3172
- 3173
- 3174
- 3175
- 3176
- 3177
- 3178
- 3179
- 3180
- 3181
- 3182
- 3183
- 3184
- 3185
- 3186
- 3187
- 3188
- 3189
- 3190
- 3191
- 3192
- 3193
- 3194
- 3195
- 3196
- 3197
- 3198
- 3199
- 3200
- 3201
- 3202
- 3203
- 3204
- 3205
- 3206
- 3207
- 3208
- 3209
- 3210
- 3211
- 3212
- 3213
- 3214
- 3215
- 3216
- 3217
- 3218
- 3219
- 3220
- 3221
- 3222
- 3223
- 3224
- 3225
- 3226
- 3227
- 3228
- 3229
- 3230
- 3231
- 3232
- 3233
- 3234
- 3235
- 3236
- 3237
- 3238
- 3239
- 3240
- 3241
- 3242
- 3243
- 3244
- 3245
- 3246
- 3247
- 3248
- 3249
- 3250
- 3251
- 3252
- 3253
- 3254
- 3255
- 3256
- 3257
- 3258
- 3259
- 3260
- 3261
- 3262
- 3263
- 3264
- 3265
- 3266
- 3267
- 3268
- 3269
- 3270
- 3271
- 3272
- 3273
- 3274
- 3275
- 3276
- 3277
- 3278
- 3279
- 3280
- 3281
- 3282
- 3283
- 3284
- 3285
- 3286
- 3287
- 3288
- 3289
- 3290
- 3291
- 3292
- 3293
- 3294
- 3295
- 3296
- 3297
- 3298
- 3299
- 3300
- 3301
- 3302
- 3303
- 3304
- 3305
- 3306
- 3307
- 3308
- 3309
- 3310
- 3311
- 3312
- 3313
- 3314
- 3315
- 3316
- 3317
- 3318
- 3319
- 3320
- 3321
- 3322
- 3323
- 3324
- 3325
- 3326
- 3327
- 3328
- 3329
- 3330
- 3331
- 3332
- 3333
- 3334
- 3335
- 3336
- 3337
- 3338
- 3339
- 3340
- 3341
- 3342
- 3343
- 3344
- 3345
- 3346
- 3347
- 3348
- 3349
- 3350
- 3351
- 3352
- 3353
- 3354
- 3355
- 3356
- 3357
- 3358
- 3359
- 3360
- 3361
- 3362
- 3363
- 3364
- 3365
- 3366
- 3367
- 3368
- 3369
- 3370
- 3371
- 3372
- 3373
- 3374
- 3375
- 3376
- 3377
- 3378
- 3379
- 3380
- 3381
- 3382
- 3383
- 3384
- 3385
- 3386
- 3387
- 3388
- 3389
- 3390
- 3391
- 3392
- 3393
- 3394
- 3395
- 3396
- 3397
- 3398
- 3399
- 3400
- 3401
- 3402
- 3403
- 3404
- 3405
- 3406
- 3407
- 3408
- 3409
- 3410
- 3411
- 3412
- 3413
- 3414
- 3415
- 3416
- 3417
- 3418
- 3419
- 3420
- 3421
- 3422
- 3423
- 3424
- 3425
- 3426
- 3427
- 3428
- 3429
- 3430
- 3431
- 3432
- 3433
- 3434
- 3435
- 3436
- 3437
- 3438
- 3439
- 3440
- 3441
- 3442
- 3443
- 3444
- 3445
- 3446
- 3447
- 3448
- 3449
- 3450
- 3451
- 3452
- 3453
- 3454
- 3455
- 3456
- 3457
- 3458
- 3459
- 3460
- 3461
- 3462
- 3463
- 3464
- 3465
- 3466
- 3467
- 3468
- 3469
- 3470
- 3471
- 3472
- 3473
- 3474
- 3475
- 3476
- 3477
- 3478
- 3479
- 3480
- 3481
- 3482
- 3483
- 3484
- 3485
- 3486
- 3487
- 3488
- 3489
- 3490
- 3491
- 3492
- 3493
- 3494
- 3495
- 3496
- 3497
- 3498
- 3499
- 3500
- 3501
- 3502
- 3503
- 3504
- 3505
- 3506
- 3507
- 3508
- 3509
- 3510
- 3511
- 3512
- 3513
- 3514
- 3515
- 3516
- 3517
- 3518
- 3519
- 3520
- 3521
- 3522
- 3523
- 3524
- 3525
- 3526
- 3527
- 3528
- 3529
- 3530
- 3531
- 3532
- 3533
- 3534
- 3535
- 3536
- 3537
- 3538
- 3539
- 3540
- 3541
- 3542
- 3543
- 3544
- 3545
- 3546
- 3547
- 3548
- 3549
- 3550
- 3551
- 3552
- 3553
- 3554
- 3555
- 3556
- 3557
- 3558
- 3559
- 3560
- 3561
- 3562
- 3563
- 3564
- 3565
- 3566
- 3567
- 3568
- 3569
- 3570
- 3571
- 3572
- 3573
- 3574
- 3575
- 3576
- 3577
- 3578
- 3579
- 3580
- 3581
- 3582
- 3583
- 3584
- 3585
- 3586
- 3587
- 3588
- 3589
- 3590
- 3591
- 3592
- 3593
- 3594
- 3595
- 3596
- 3597
- 3598
- 3599
- 3600
- 3601
- 3602
- 3603
- 3604
- 3605
- 3606
- 3607
- 3608
- 3609
- 3610
- 3611
- 3612
- 3613
- 3614
- 3615
- 3616
- 3617
- 3618
- 3619
- 3620
- 3621
- 3622
- 3623
- 3624
- 3625
- 3626
- 3627
- 3628
- 3629
- 3630
- 3631
- 3632
- 3633
- 3634
- 3635
- 3636
- 3637
- 3638
- 3639
- 3640
- 3641
- 3642
- 3643
- 3644
- 3645
- 3646
- 3647
- 3648
- 3649
- 3650
- 3651
- 3652
- 3653
- 3654
- 3655
- 3656
- 3657
- 3658
- 3659
- 3660
- 3661
- 3662
- 3663
- 3664
- 3665
- 3666
- 3667
- 3668
- 3669
- 3670
- 3671
- 3672
- 3673
- 3674
- 3675
- 3676
- 3677
- 3678
- 3679
- 3680
- 3681
- 3682
- 3683
- 3684
- 3685
- 3686
- 3687
- 3688
- 3689
- 3690
- 3691
- 3692
- 3693
- 3694
- 3695
- 3696
- 3697
- 3698
- 3699
- 3700
- 3701
- 3702
- 3703
- 3704
- 3705
- 3706
- 3707
- 3708
- 3709
- 3710
- 3711
- 3712
- 3713
- 3714
- 3715
- 3716
- 3717
- 3718
- 3719
- 3720
- 3721
- 3722
- 3723
- 3724
- 3725
- 3726
- 3727
- 3728
- 3729
- 3730
- 3731
- 3732
- 3733
- 3734
- 3735
- 3736
- 3737
- 3738
- 3739
- 3740
- 3741
- 3742
- 3743
- 3744
- 3745
- 3746
- 3747
- 3748
- 3749
- 3750
- 3751
- 3752
- 3753
- 3754
- 3755
- 3756
- 3757
- 3758
- 3759
- 3760
- 3761
- 3762
- 3763
- 3764
- 3765
- 3766
- 3767
- 3768
- 3769
- 3770
- 3771
- 3772
- 3773
- 3774
- 3775
- 3776
- 3777
- 3778
- 3779
- 3780
- 3781
- 3782
- 3783
- 3784
- 3785
- 3786
- 3787
- 3788
- 3789
- 3790
- 3791
- 3792
- 3793
- 3794
- 3795
- 3796
- 3797
- 3798
- 3799
- 3800
- 3801
- 3802
- 3803
- 3804
- 3805
- 3806
- 3807
- 3808
- 3809
- 3810
- 3811
- 3812
- 3813
- 3814
- 3815
- 3816
- 3817
- 3818
- 3819
- 3820
- 3821
- 3822
- 3823
- 3824
- 3825
- 3826
- 3827
- 3828
- 3829
- 3830
- 3831
- 3832
- 3833
- 3834
- 3835
- 3836
- 3837
- 3838
- 3839
- 3840
- 3841
- 3842
- 3843
- 3844
- 3845
- 3846
- 3847
- 3848
- 3849
- 3850
- 3851
- 3852
- 3853
- 3854
- 3855
- 3856
- 3857
- 3858
- 3859
- 3860
- 3861
- 3862
- 3863
- 3864
- 3865
- 3866
- 3867
- 3868
- 3869
- 3870
- 3871
- 3872
- 3873
- 3874
- 3875
- 3876
- 3877
- 3878
- 3879
- 3880
- 3881
- 3882
- 3883
- 3884
- 3885
- 3886
- 3887
- 3888
- 3889
- 3890
- 3891
- 3892
- 3893
- 3894
- 3895
- 3896
- 3897
- 3898
- 3899
- 3900
- 3901
- 3902
- 3903
- 3904
- 3905
- 3906
- 3907
- 3908
- 3909
- 3910
- 3911
- 3912
- 3913
- 3914
- 3915
- 3916
- 3917
- 3918
- 3919
- 3920
- 3921
- 3922
- 3923
- 3924
- 3925
- 3926
- 3927
- 3928
- 3929
- 3930
- 3931
- 3932
- 3933
- 3934
- 3935
- 3936
- 3937
- 3938
- 3939
- 3940
- 3941
- 3942
- 3943
- 3944
- 3945
- 3946
- 3947
- 3948
- 3949
- 3950
- 3951
- 3952
- 3953
- 3954
- 3955
- 3956
- 3957
- 3958
- 3959
- 3960
- 3961
- 3962
- 3963
- 3964
- 3965
- 3966
- 3967
- 3968
- 3969
- 3970
- 3971
- 3972
- 3973
- 3974
- 3975
- 3976
- 3977
- 3978
- 3979
- 3980
- 3981
- 3982
- 3983
- 3984
- 3985
- 3986
- 3987
- 3988
- 3989
- 3990
- 3991
- 3992
- 3993
- 3994
- 3995
- 3996
- 3997
- 3998
- 3999
- 4000
- 4001
- 4002
- 4003
- 4004
- 4005
- 4006
- 4007
- 4008
- 4009
- 4010
- 4011
- 4012
- 4013
- 4014
- 4015
- 4016
- 4017
- 4018
- 4019
- 4020
- 4021
- 4022
- 4023
- 4024
- 4025
- 4026
- 4027
- 4028
- 4029
- 4030
- 4031
- 4032
- 4033
- 4034
- 4035
- 4036
- 4037
- 4038
- 4039
- 4040
- 4041
- 4042
- 4043
- 4044
- 4045
- 4046
- 4047
- 4048
- 4049
- 4050
- 4051
- 4052
- 4053
- 4054
- 4055
- 4056
- 4057
- 4058
- 4059
- 4060
- 4061
- 4062
- 4063
- 4064
- 4065
- 4066
- 4067
- 4068
- 4069
- 4070
- 4071
- 4072
- 4073
- 4074
- 4075
- 4076
- 4077
- 4078
- 4079
- 4080
- 4081
- 4082
- 4083
- 4084
- 4085
- 4086
- 4087
- 4088
- 4089
- 4090
- 4091
- 4092
- 4093
- 4094
- 4095
- 4096
- 4097
- 4098
- 4099
- 4100
- 4101
- 4102
- 4103
- 4104
- 4105
- 4106
- 4107
- 4108
- 4109
- 4110
- 4111
- 4112
- 4113
- 4114
- 4115
- 4116
- 4117
- 4118
- 4119
- 4120
- 4121
- 4122
- 4123
- 4124
- 4125
- 4126
- 4127
- 4128
- 4129
- 4130
- 4131
- 4132
- 4133
- 4134
- 4135
- 4136
- 4137
- 4138
- 4139
- 4140
- 4141
- 4142
- 4143
- 4144
- 4145
- 4146
- 4147
- 4148
- 4149
- 4150
- 4151
- 4152
- 4153
- 4154
- 4155
- 4156
- 4157
- 4158
- 4159
- 4160
- 4161
- 4162
- 4163
- 4164
- 4165
- 4166
- 4167
- 4168
- 4169
- 4170
- 4171
- 4172
- 4173
- 4174
- 4175
- 4176
- 4177
- 4178
- 4179
- 4180
- 4181
- 4182
- 4183
- 4184
- 4185
- 4186
- 4187
- 4188
- 4189
- 4190
- 4191
- 4192
- 4193
- 4194
- 4195
- 4196
- 4197
- 4198
- 4199
- 4200
- 4201
- 4202
- 4203
- 4204
- 4205
- 4206
- 4207
- 4208
- 4209
- 4210
- 4211
- 4212
- 4213
- 4214
- 4215
- 4216
- 4217
- 4218
- 4219
- 4220
- 4221
- 4222
- 4223
- 4224
- 4225
- 4226
- 4227
- 4228
- 4229
- 4230
- 4231
- 4232
- 4233
- 4234
- 4235
- 4236
- 4237
- 4238
- 4239
- 4240
- 4241
- 4242
- 4243
- 4244
- 4245
- 4246
- 4247
- 4248
- 4249
- 4250
- 4251
- 4252
- 4253
- 4254
- 4255
- 4256
- 4257
- 4258
- 4259
- 4260
- 4261
- 4262
- 4263
- 4264
- 4265
- 4266
- 4267
- 4268
- 4269
- 4270
- 4271
- 4272
- 4273
- 4274
- 4275
- 4276
- 4277
- 4278
- 4279
- 4280
- 4281
- 4282
- 4283
- 4284
- 4285
- 4286
- 4287
- 4288
- 4289
- 4290
- 4291
- 4292
- 4293
- 4294
- 4295
- 4296
- 4297
- 4298
- 4299
- 4300
- 4301
- 4302
- 4303
- 4304
- 4305
- 4306
- 4307
- 4308
- 4309
- 4310
- 4311
- 4312
- 4313
- 4314
- 4315
- 4316
- 4317
- 4318
- 4319
- 4320
- 4321
- 4322
- 4323
- 4324
- 4325
- 4326
- 4327
- 4328
- 4329
- 4330
- 4331
- 4332
- 4333
- 4334
- 4335
- 4336
- 4337
- 4338
- 4339
- 4340
- 4341
- 4342
- 4343
- 4344
- 4345
- 4346
- 4347
- 4348
- 4349
- 4350
- 4351
- 4352
- 4353
- 4354
- 4355
- 4356
- 4357
- 4358
- 4359
- 4360
- 4361
- 4362
- 4363
- 4364
- 4365
- 4366
- 4367
- 4368
- 4369
- 4370
- 4371
- 4372
- 4373
- 4374
- 4375
- 4376
- 4377
- 4378
- 4379
- 4380
- 4381
- 4382
- 4383
- 4384
- 4385
- 4386
- 4387
- 4388
- 4389
- 4390
- 4391
- 4392
- 4393
- 4394
- 4395
- 4396
- 4397
- 4398
- 4399
- 4400
- 4401
- 4402
- 4403
- 4404
- 4405
- 4406
- 4407
- 4408
- 4409
- 4410
- 4411
- 4412
- 4413
- 4414
- 4415
- 4416
- 4417
- 4418
- 4419
- 4420
- 4421
- 4422
- 4423
- 4424
- 4425
- 4426
- 4427
- 4428
- 4429
- 4430
- 4431
- 4432
- 4433
- 4434
- 4435
- 4436
- 4437
- 4438
- 4439
- 4440
- 4441
- 4442
- 4443
- 4444
- 4445
- 4446
- 4447
- 4448
- 4449
- 4450
- 4451
- 4452
- 4453
- 4454
- 4455
- 4456
- 4457
- 4458
- 4459
- 4460
- 4461
- 4462
- 4463
- 4464
- 4465
- 4466
- 4467
- 4468
- 4469
- 4470
- 4471
- 4472
- 4473
- 4474
- 4475
- 4476
- 4477
- 4478
- 4479
- 4480
- 4481
- 4482
- 4483
- 4484
- 4485
- 4486
- 4487
- 4488
- 4489
- 4490
- 4491
- 4492
- 4493
- 4494
- 4495
- 4496
- 4497
- 4498
- 4499
- 4500
- 4501
- 4502
- 4503
- 4504
- 4505
- 4506
- 4507
- 4508
- 4509
- 4510
- 4511
- 4512
- 4513
- 4514
- 4515
- 4516
- 4517
- 4518
- 4519
- 4520
- 4521
- 4522
- 4523
- 4524
- 4525
- 4526
- 4527
- 4528
- 4529
- 4530
- 4531
- 4532
- 4533
- 4534
- 4535
- 4536
- 4537
- 4538
- 4539
- 4540
- 4541
- 4542
- 4543
- 4544
- 4545
- 4546
- 4547
- 4548
- 4549
- 4550
- 4551
- 4552
- 4553
- 4554
- 4555
- 4556
- 4557
- 4558
- 4559
- 4560
- 4561
- 4562
- 4563
- 4564
- 4565
- 4566
- 4567
- 4568
- 4569
- 4570
- 4571
- 4572
- 4573
- 4574
- 4575
- 4576
- 4577
- 4578
- 4579
- 4580
- 4581
- 4582
- 4583
- 4584
- 4585
- 4586
- 4587
- 4588
- 4589
- 4590
- 4591
- 4592
- 4593
- 4594
- 4595
- 4596
- 4597
- 4598
- 4599
- 4600
- 4601
- 4602
- 4603
- 4604
- 4605
- 4606
- 4607
- 4608
- 4609
- 4610
- 4611
- 4612
- 4613
- 4614
- 4615
- 4616
- 4617
- 4618
- 4619
- 4620
- 4621
- 4622
- 4623
- 4624
- 4625
- 4626
- 4627
- 4628
- 4629
- 4630
- 4631
- 4632
- 4633
- 4634
- 4635
- 4636
- 4637
- 4638
- 4639
- 4640
- 4641
- 4642
- 4643
- 4644
- 4645
- 4646
- 4647
- 4648
- 4649
- 4650
- 4651
- 4652
- 4653
- 4654
- 4655
- 4656
- 4657
- 4658
- 4659
- 4660
- 4661
- 4662
- 4663
- 4664
- 4665
- 4666
- 4667
- 4668
- 4669
- 4670
- 4671
- 4672
- 4673
- 4674
- 4675
- 4676
- 4677
- 4678
- 4679
- 4680
- 4681
- 4682
- 4683
- 4684
- 4685
- 4686
- 4687
- 4688
- 4689
- 4690
- 4691
- 4692
- 4693
- 4694
- 4695
- 4696
- 4697
- 4698
- 4699
- 4700
- 4701
- 4702
- 4703
- 4704
- 4705
- 4706
- 4707
- 4708
- 4709
- 4710
- 4711
- 4712
- 4713
- 4714
- 4715
- 4716
- 4717
- 4718
- 4719
- 4720
- 4721
- 4722
- 4723
- 4724
- 4725
- 4726
- 4727
- 4728
- 4729
- 4730
- 4731
- 4732
- 4733
- 4734
- 4735
- 4736
- 4737
- 4738
- 4739
- 4740
- 4741
- 4742
- 4743
- 4744
- 4745
- 4746
- 4747
- 4748
- 4749
- 4750
- 4751
- 4752
- 4753
- 4754
- 4755
- 4756
- 4757
- 4758
- 4759
- 4760
- 4761
- 4762
- 4763
- 4764
- 4765
- 4766
- 4767
- 4768
- 4769
- 4770
- 4771
- 4772
- 4773
- 4774
- 4775
- 4776
- 4777
- 4778
- 4779
- 4780
- 4781
- 4782
- 4783
- 4784
- 4785
- 4786
- 4787
- 4788
- 4789
- 4790
- 4791
- 4792
- 4793
- 4794
- 4795
- 4796
- 4797
- 4798
- 4799
- 4800
- 4801
- 4802
- 4803
- 4804
- 4805
- 4806
- 4807
- 4808
- 4809
- 4810
- 4811
- 4812
- 4813
- 4814
- 4815
- 4816
- 4817
- 4818
- 4819
- 4820
- 4821
- 4822
- 4823
- 4824
- 4825
- 4826
- 4827
- 4828
- 4829
- 4830
- 4831
- 4832
- 4833
- 4834
- 4835
- 4836
- 4837
- 4838
- 4839
- 4840
- 4841
- 4842
- 4843
- 4844
- 4845
- 4846
- 4847
- 4848
- 4849
- 4850
- 4851
- 4852
- 4853
- 4854
- 4855
- 4856
- 4857
- 4858
- 4859
- 4860
- 4861
- 4862
- 4863
- 4864
- 4865
- 4866
- 4867
- 4868
- 4869
- 4870
- 4871
- 4872
- 4873
- 4874
- 4875
- 4876
- 4877
- 4878
- 4879
- 4880
- 4881
- 4882
- 4883
- 4884
- 4885
- 4886
- 4887
- 4888
- 4889
- 4890
- 4891
- 4892
- 4893
- 4894
- 4895
- 4896
- 4897
- 4898
- 4899
- 4900
- 4901
- 4902
- 4903
- 4904
- 4905
- 4906
- 4907
- 4908
- 4909
- 4910
- 4911
- 4912
- 4913
- 4914
- 4915
- 4916
- 4917
- 4918
- 4919
- 4920
- 4921
- 4922
- 4923
- 4924
- 4925
- 4926
- 4927
- 4928
- 4929
- 4930
- 4931
- 4932
- 4933
- 4934
- 4935
- 4936
- 4937
- 4938
- 4939
- 4940
- 4941
- 4942
- 4943
- 4944
- 4945
- 4946
- 4947
- 4948
- 4949
- 4950
- 4951
- 4952
- 4953
- 4954
- 4955
- 4956
- 4957
- 4958
- 4959
- 4960
- 4961
- 4962
- 4963
- 4964
- 4965
- 4966
- 4967
- 4968
- 4969
- 4970
- 4971
- 4972
- 4973
- 4974
- 4975
- 4976
- 4977
- 4978
- 4979
- 4980
- 4981
- 4982
- 4983
- 4984
- 4985
- 4986
- 4987
- 4988
- 4989
- 4990
- 4991
- 4992
- 4993
- 4994
- 4995
- 4996
- 4997
- 4998
- 4999
- 5000
- 5001
- 5002
- 5003
- 5004
- 5005
- 5006
- 5007
- 5008
- 5009
- 5010
- 5011
- 5012
- 5013
- 5014
- 5015
- 5016
- 5017
- 5018
- 5019
- 5020
- 5021
- 5022
- 5023
- 5024
- 5025
- 5026
- 5027
- 5028
- 5029
- 5030
- 5031
- 5032
- 5033
- 5034
- 5035
- 5036
- 5037
- 5038
- 5039
- 5040
- 5041
- 5042
- 5043
- 5044
- 5045
- 5046
- 5047
- 5048
- 5049
- 5050
- 5051
- 5052
- 5053
- 5054
- 5055
- 5056
- 5057
- 5058
- 5059
- 5060
- 5061
- 5062
- 5063
- 5064
- 5065
- 5066
- 5067
- 5068
- 5069
- 5070
- 5071
- 5072
- 5073
- 5074
- 5075
- 5076
- 5077
- 5078
- 5079
- 5080
- 5081
- 5082
- 5083
- 5084
- 5085
- 5086
- 5087
- 5088
- 5089
- 5090
- 5091
- 5092
- 5093
- 5094
- 5095
- 5096
- 5097
- 5098
- 5099
- 5100
- 5101
- 5102
- 5103
- 5104
- 5105
- 5106
- 5107
- 5108
- 5109
- 5110
- 5111
- 5112
- 5113
- 5114
- 5115
- 5116
- 5117
- 5118
- 5119
- 5120
- 5121
- 5122
- 5123
- 5124
- 5125
- 5126
- 5127
- 5128
- 5129
- 5130
- 5131
- 5132
- 5133
- 5134
- 5135
- 5136
- 5137
- 5138
- 5139
- 5140
- 5141
- 5142
- 5143
- 5144
- 5145
- 5146
- 5147
- 5148
- 5149
- 5150
- 5151
- 5152
- 5153
- 5154
- 5155
- 5156
- 5157
- 5158
- 5159
- 5160
- 5161
- 5162
- 5163
- 5164
- 5165
- 5166
- 5167
- 5168
- 5169
- 5170
- 5171
- 5172
- 5173
- 5174
- 5175
- 5176
- 5177
- 5178
- 5179
- 5180
- 5181
- 5182
- 5183
- 5184
- 5185
- 5186
- 5187
- 5188
- 5189
- 5190
- 5191
- 5192
- 5193
- 5194
- 5195
- 5196
- 5197
- 5198
- 5199
- 5200
- 5201
- 5202
- 5203
- 5204
- 5205
- 5206
- 5207
- 5208
- 5209
- 5210
- 5211
- 5212
- 5213
- 5214
- 5215
- 5216
- 5217
- 5218
- 5219
- 5220
- 5221
- 5222
- 5223
- 5224
- 5225
- 5226
- 5227
- 5228
- 5229
- 5230
- 5231
- 5232
- 5233
- 5234
- 5235
- 5236
- 5237
- 5238
- 5239
- 5240
- 5241
- 5242
- 5243
- 5244
- 5245
- 5246
- 5247
- 5248
- 5249
- 5250
- 5251
- 5252
- 5253
- 5254
- 5255
- 5256
- 5257
- 5258
- 5259
- 5260
- 5261
- 5262
- 5263
- 5264
- 5265
- 5266
- 5267
- 5268
- 5269
- 5270
- 5271
- 5272
- 5273
- 5274
- 5275
- 5276
- 5277
- 5278
- 5279
- 5280
- 5281
- 5282
- 5283
- 5284
- 5285
- 5286
- 5287
- 5288
- 5289
- 5290
- 5291
- 5292
- 5293
- 5294
- 5295
- 5296
- 5297
- 5298
- 5299
- 5300
- 5301
- 5302
- 5303
- 5304
- 5305
- 5306
- 5307
- 5308
- 5309
- 5310
- 5311
- 5312
- 5313
- 5314
- 5315
- 5316
- 5317
- 5318
- 5319
- 5320
- 5321
- 5322
- 5323
- 5324
- 5325
- 5326
- 5327
- 5328
- 5329
- 5330
- 5331
- 5332
- 5333
- 5334
- 5335
- 5336
- 5337
- 5338
- 5339
- 5340
- 5341
- 5342
- 5343
- 5344
- 5345
- 5346
- 5347
- 5348
- 5349
- 5350
- 5351
- 5352
- 5353
- 5354
- 5355
- 5356
- 5357
- 5358
- 5359
- 5360
- 5361
- 5362
- 5363
- 5364
- 5365
- 5366
- 5367
- 5368
- 5369
- 5370
- 5371
- 5372
- 5373
- 5374
- 5375
- 5376
- 5377
- 5378
- 5379
- 5380
- 5381
- 5382
- 5383
- 5384
- 5385
- 5386
- 5387
- 5388
- 5389
- 5390
- 5391
- 5392
- 5393
- 5394
- 5395
- 5396
- 5397
- 5398
- 5399
- 5400
- 5401
- 5402
- 5403
- 5404
- 5405
- 5406
- 5407
- 5408
- 5409
- 5410
- 5411
- 5412
- 5413
- 5414
- 5415
- 5416
- 5417
- 5418
- 5419
- 5420
- 5421
- 5422
- 5423
- 5424
- 5425
- 5426
- 5427
- 5428
- 5429
- 5430
- 5431
- 5432
- 5433
- 5434
- 5435
- 5436
- 5437
- 5438
- 5439
- 5440
- 5441
- 5442
- 5443
- 5444
- 5445
- 5446
- 5447
- 5448
- 5449
- 5450
- 5451
- 5452
- 5453
- 5454
- 5455
- 5456
- 5457
- 5458
- 5459
- 5460
- 5461
- 5462
- 5463
- 5464
- 5465
- 5466
- 5467
- 5468
- 5469
- 5470
- 5471
- 5472
- 5473
- 5474
- 5475
- 5476
- 5477
- 5478
- 5479
- 5480
- 5481
- 5482
- 5483
- 5484
- 5485
- 5486
- 5487
- 5488
- 5489
- 5490
- 5491
- 5492
- 5493
- 5494
- 5495
- 5496
- 5497
- 5498
- 5499
- 5500
- 5501
- 5502
- 5503
- 5504
- 5505
- 5506
- 5507
- 5508
- 5509
- 5510
- 5511
- 5512
- 5513
- 5514
- 5515
- 5516
- 5517
- 5518
- 5519
- 5520
- 5521
- 5522
- 5523
- 5524
- 5525
- 5526
- 5527
- 5528
- 5529
- 5530
- 5531
- 5532
- 5533
- 5534
- 5535
- 5536
- 5537
- 5538
- 5539
- 5540
- 5541
- 5542
- 5543
- 5544
- 5545
- 5546
- 5547
- 5548
- 5549
- 5550
- 5551
- 5552
- 5553
- 5554
- 5555
- 5556
- 5557
- 5558
- 5559
- 5560
- 5561
- 5562
- 5563
- 5564
- 5565
- 5566
- 5567
- 5568
- 5569
- 5570
- 5571
- 5572
- 5573
- 5574
- 5575
- 5576
- 5577
- 5578
- 5579
- 5580
- 5581
- 5582
- 5583
- 5584
- 5585
- 5586
- 5587
- 5588
- 5589
- 5590
- 5591
- 5592
- 5593
- 5594
- 5595
- 5596
- 5597
- 5598
- 5599
- 5600
- 5601
- 5602
- 5603
- 5604
- 5605
- 5606
- 5607
- 5608
- 5609
- 5610
- 5611
- 5612
- 5613
- 5614
- 5615
- 5616
- 5617
- 5618
- 5619
- 5620
- 5621
- 5622
- 5623
- 5624
- 5625
- 5626
- 5627
- 5628
- 5629
- 5630
- 5631
- 5632
- 5633
- 5634
- 5635
- 5636
- 5637
- 5638
- 5639
- 5640
- 5641
- 5642
- 5643
- 5644
- 5645
- 5646
- 5647
- 5648
- 5649
- 5650
- 5651
- 5652
- 5653
- 5654
- 5655
- 5656
- 5657
- 5658
- 5659
- 5660
- 5661
- 5662
- 5663
- 5664
- 5665
- 5666
- 5667
- 5668
- 5669
- 5670
- 5671
- 5672
- 5673
- 5674
- 5675
- 5676
- 5677
- 5678
- 5679
- 5680
- 5681
- 5682
- 5683
- 5684
- 5685
- 5686
- 5687
- 5688
- 5689
- 5690
- 5691
- 5692
- 5693
- 5694
- 5695
- 5696
- 5697
- 5698
- 5699
- 5700
- 5701
- 5702
- 5703
- 5704
- 5705
- 5706
- 5707
- 5708
- 5709
- 5710
- 5711
- 5712
- 5713
- 5714
- 5715
- 5716
- 5717
- 5718
- 5719
- 5720
- 5721
- 5722
- 5723
- 5724
- 5725
- 5726
- 5727
- 5728
- 5729
- 5730
- 5731
- 5732
- 5733
- 5734
- 5735
- 5736
- 5737
- 5738
- 5739
- 5740
- 5741
- 5742
- 5743
- 5744
- 5745
- 5746
- 5747
- 5748
- 5749
- 5750
- 5751
- 5752
- 5753
- 5754
- 5755
- 5756
- 5757
- 5758
- 5759
- 5760
- 5761
- 5762
- 5763
- 5764
- 5765
- 5766
- 5767
- 5768
- 5769
- 5770
- 5771
- 5772
- 5773
- 5774
- 5775
- 5776
- 5777
- 5778
- 5779
- 5780
- 5781
- 5782
- 5783
- 5784
- 5785
- 5786
- 5787
- 5788
- 5789
- 5790
- 5791
- 5792
- 5793
- 5794
- 5795
- 5796
- 5797
- 5798
- 5799
- 5800
- 5801
- 5802
- 5803
- 5804
- 5805
- 5806
- 5807
- 5808
- 5809
- 5810
- 5811
- 5812
- 5813
- 5814
- 5815
- 5816
- 5817
- 5818
- 5819
- 5820
- 5821
- 5822
- 5823
- 5824
- 5825
- 5826
- 5827
- 5828
- 5829
- 5830
- 5831
- 5832
- 5833
- 5834
- 5835
- 5836
- 5837
- 5838
- 5839
- 5840
- 5841
- 5842
- 5843
- 5844
- 5845
- 5846
- 5847
- 5848
- 5849
- 5850
- 5851
- 5852
- 5853
- 5854
- 5855
- 5856
- 5857
- 5858
- 5859
- 5860
- 5861
- 5862
- 5863
- 5864
- 5865
- 5866
- 5867
- 5868
- 5869
- 5870
- 5871
- 5872
- 5873
- 5874
- 5875
- 5876
- 5877
- 5878
- 5879
- 5880
- 5881
- 5882
- 5883
- 5884
- 5885
- 5886
- 5887
- 5888
- 5889
- 5890
- 5891
- 5892
- 5893
- 5894
- 5895
- 5896
- 5897
- 5898
- 5899
- 5900
- 5901
- 5902
- 5903
- 5904
- 5905
- 5906
- 5907
- 5908
- 5909
- 5910
- 5911
- 5912
- 5913
- 5914
- 5915
- 5916
- 5917
- 5918
- 5919
- 5920
- 5921
- 5922
- 5923
- 5924
- 5925
- 5926
- 5927
- 5928
- 5929
- 5930
- 5931
- 5932
- 5933
- 5934
- 5935
- 5936
- 5937
- 5938
- 5939
- 5940
- 5941
- 5942
- 5943
- 5944
- 5945
- 5946
- 5947
- 5948
- 5949
- 5950
- 5951
- 5952
- 5953
- 5954
- 5955
- 5956
- 5957
- 5958
- 5959
- 5960
- 5961
- 5962
- 5963
- 5964
- 5965
- 5966
- 5967
- 5968
- 5969
- 5970
- 5971
- 5972
- 5973
- 5974
- 5975
- 5976
- 5977
- 5978
- 5979
- 5980
- 5981
- 5982
- 5983
- 5984
- 5985
- 5986
- 5987
- 5988
- 5989
- 5990
- 5991
- 5992
- 5993
- 5994
- 5995
- 5996
- 5997
- 5998
- 5999
- 6000
- 6001
- 6002
- 6003
- 6004
- 6005
- 6006
- 6007
- 6008
- 6009
- 6010
- 6011
- 6012
- 6013
- 6014
- 6015
- 6016
- 6017
- 6018
- 6019
- 6020
- 6021
- 6022
- 6023
- 6024
- 6025
- 6026
- 6027
- 6028
- 6029
- 6030
- 6031
- 6032
- 6033
- 6034
- 6035
- 6036
- 6037
- 6038
- 6039
- 6040
- 6041
- 6042
- 6043
- 6044
- 6045
- 6046
- 6047
- 6048
- 6049
- 6050
- 6051
- 6052
- 6053
- 6054
- 6055
- 6056
- 6057
- 6058
- 6059
- 6060
- 6061
- 6062
- 6063
- 6064
- 6065
- 6066
- 6067
- 6068
- 6069
- 6070
- 6071
- 6072
- 6073
- 6074
- 6075
- 6076
- 6077
- 6078
- 6079
- 6080
- 6081
- 6082
- 6083
- 6084
- 6085
- 6086
- 6087
- 6088
- 6089
- 6090
- 6091
- 6092
- 6093
- 6094
- 6095
- 6096
- 6097
- 6098
- 6099
- 6100
- 6101
- 6102
- 6103
- 6104
- 6105
- 6106
- 6107
- 6108
- 6109
- 6110
- 6111
- 6112
- 6113
- 6114
- 6115
- 6116
- 6117
- 6118
- 6119
- 6120
- 6121
- 6122
- 6123
- 6124
- 6125
- 6126
- 6127
- 6128
- 6129
- 6130
- 6131
- 6132
- 6133
- 6134
- 6135
- 6136
- 6137
- 6138
- 6139
- 6140
- 6141
- 6142
- 6143
- 6144
- 6145
- 6146
- 6147
- 6148
- 6149
- 6150
- 6151
- 6152
- 6153
- 6154
- 6155
- 6156
- 6157
- 6158
- 6159
- 6160
- 6161
- 6162
- 6163
- 6164
- 6165
- 6166
- 6167
- 6168
- 6169
- 6170
- 6171
- 6172
- 6173
- 6174
- 6175
- 6176
- 6177
- 6178
- 6179
- 6180
- 6181
- 6182
- 6183
- 6184
- 6185
- 6186
- 6187
- 6188
- 6189
- 6190
- 6191
- 6192
- 6193
- 6194
- 6195
- 6196
- 6197
- 6198
- 6199
- 6200
- 6201
- 6202
- 6203
- 6204
- 6205
- 6206
- 6207
- 6208
- 6209
- 6210
- 6211
- 6212
- 6213
- 6214
- 6215
- 6216
- 6217
- 6218
- 6219
- 6220
- 6221
- 6222
- 6223
- 6224
- 6225
- 6226
- 6227
- 6228
- 6229
- 6230
- 6231
- 6232
- 6233
- 6234
- 6235
- 6236
- 6237
- 6238
- 6239
- 6240
- 6241
- 6242
- 6243
- 6244
- 6245
- 6246
- 6247
- 6248
- 6249
- 6250
- 6251
- 6252
- 6253
- 6254
- 6255
- 6256
- 6257
- 6258
- 6259
- 6260
- 6261
- 6262
- 6263
- 6264
- 6265
- 6266
- 6267
- 6268
- 6269
- 6270
- 6271
- 6272
- 6273
- 6274
- 6275
- 6276
- 6277
- 6278
- 6279
- 6280
- 6281
- 6282
- 6283
- 6284
- 6285
- 6286
- 6287
- 6288
- 6289
- 6290
- 6291
- 6292
- 6293
- 6294
- 6295
- 6296
- 6297
- 6298
- 6299
- 6300
- 6301
- 6302
- 6303
- 6304
- 6305
- 6306
- 6307
- 6308
- 6309
- 6310
- 6311
- 6312
- 6313
- 6314
- 6315
- 6316
- 6317
- 6318
- 6319
- 6320
- 6321
- 6322
- 6323
- 6324
- 6325
- 6326
- 6327
- 6328
- 6329
- 6330
- 6331
- 6332
- 6333
- 6334
- 6335
- 6336
- 6337
- 6338
- 6339
- 6340
- 6341
- 6342
- 6343
- 6344
- 6345
- 6346
- 6347
- 6348
- 6349
- 6350
- 6351
- 6352
- 6353
- 6354
- 6355
- 6356
- 6357
- 6358
- 6359
- 6360
- 6361
- 6362
- 6363
- 6364
- 6365
- 6366
- 6367
- 6368
- 6369
- 6370
- 6371
- 6372
- 6373
- 6374
- 6375
- 6376
- 6377
- 6378
- 6379
- 6380
- 6381
- 6382
- 6383
- 6384
- 6385
- 6386
- 6387
- 6388
- 6389
- 6390
- 6391
- 6392
- 6393
- 6394
- 6395
- 6396
- 6397
- 6398
- 6399
- 6400
- 6401
- 6402
- 6403
- 6404
- 6405
- 6406
- 6407
- 6408
- 6409
- 6410
- 6411
- 6412
- 6413
- 6414
- 6415
- 6416
- 6417
- 6418
- 6419
- 6420
- 6421
- 6422
- 6423
- 6424
- 6425
- 6426
- 6427
- 6428
- 6429
- 6430
- 6431
- 6432
- 6433
- 6434
- 6435
- 6436
- 6437
- 6438
- 6439
- 6440
- 6441
- 6442
- 6443
- 6444
- 6445
- 6446
- 6447
- 6448
- 6449
- 6450
- 6451
- 6452
- 6453
- 6454
- 6455
- 6456
- 6457
- 6458
- 6459
- 6460
- 6461
- 6462
- 6463
- 6464
- 6465
- 6466
- 6467
- 6468
- 6469
- 6470
- 6471
- 6472
- 6473
- 6474
- 6475
- 6476
- 6477
- 6478
- 6479
- 6480
- 6481
- 6482
- 6483
- 6484
- 6485
- 6486
- 6487
- 6488
- 6489
- 6490
- ////////////////////////////////////////////////////////////////////////
- // OpenTibia - an opensource roleplaying game
- ////////////////////////////////////////////////////////////////////////
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- ////////////////////////////////////////////////////////////////////////
- #include "otpch.h"
- #include "game.h"
- #include "configmanager.h"
- #ifdef __LOGIN_SERVER__
- #include "gameservers.h"
- #endif
- #include "server.h"
- #include "chat.h"
- #include "luascript.h"
- #include "creature.h"
- #include "combat.h"
- #include "tile.h"
- #include "database.h"
- #include "iologindata.h"
- #include "ioban.h"
- #include "ioguild.h"
- #include "items.h"
- #include "trashholder.h"
- #include "container.h"
- #include "monsters.h"
- #include "house.h"
- #include "quests.h"
- #include "actions.h"
- #include "globalevent.h"
- #include "movement.h"
- #include "raids.h"
- #include "scriptmanager.h"
- #include "spells.h"
- #include "talkaction.h"
- #include "weapons.h"
- #include "vocation.h"
- #include "group.h"
- #ifdef __EXCEPTION_TRACER__
- #include "exception.h"
- #endif
- extern ConfigManager g_config;
- extern Actions* g_actions;
- extern Monsters g_monsters;
- extern Npcs g_npcs;
- extern Chat g_chat;
- extern TalkActions* g_talkActions;
- extern Spells* g_spells;
- extern MoveEvents* g_moveEvents;
- extern Weapons* g_weapons;
- extern CreatureEvents* g_creatureEvents;
- extern GlobalEvents* g_globalEvents;
- Game::Game()
- {
- gameState = GAMESTATE_NORMAL;
- worldType = WORLDTYPE_OPEN;
- map = NULL;
- playersRecord = lastStageLevel = 0;
- //(1440 minutes/day) * 10 seconds event interval / (3600 seconds/day)
- lightHourDelta = 1440 * 10 / 3600;
- lightHour = SUNRISE + (SUNSET - SUNRISE) / 2;
- lightLevel = LIGHT_LEVEL_DAY;
- lightState = LIGHT_STATE_DAY;
- lastBucket = checkCreatureLastIndex = checkLightEvent = checkCreatureEvent = checkDecayEvent = saveEvent = 0;
- checkWarsEvent = 0;
- }
- Game::~Game()
- {
- delete map;
- }
- void Game::start(ServiceManager* servicer)
- {
- checkDecayEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
- boost::bind(&Game::checkDecay, this)));
- checkCreatureEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL,
- boost::bind(&Game::checkCreatures, this)));
- checkLightEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
- boost::bind(&Game::checkLight, this)));
- checkWarsEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_WARSINTERVAL,
- boost::bind(&Game::checkWars, this)));
- services = servicer;
- if(!g_config.getBool(ConfigManager::GLOBALSAVE_ENABLED))
- return;
- int32_t prepareHour = g_config.getNumber(ConfigManager::GLOBALSAVE_H),
- prepareMinute = g_config.getNumber(ConfigManager::GLOBALSAVE_M);
- if(prepareHour < 0 || prepareHour > 24)
- {
- std::clog << "> WARNING: No valid hour (" << prepareHour << ") for a global save, should be between 0-23. Global save disabled." << std::endl;
- return;
- }
- if(prepareMinute < 0 || prepareMinute > 59)
- {
- std::clog << "> WARNING: No valid minute (" << prepareMinute << ") for a global save, should be between 0-59. Global save disabled." << std::endl;
- return;
- }
- time_t timeNow = time(NULL);
- const tm* theTime = localtime(&timeNow);
- int32_t hour = theTime->tm_hour, minute = theTime->tm_min, second = theTime->tm_sec,
- hoursLeft = 0, minutesLeft = 0, broadcast = 5;
- if(prepareHour == 0)
- prepareHour = 24;
- if(hour != prepareHour)
- {
- if(prepareMinute >= 5)
- prepareMinute -= 5;
- else
- {
- prepareHour--;
- prepareMinute = 55 + prepareMinute;
- }
- if(hour > prepareHour)
- hoursLeft = 24 - (hour - prepareHour);
- else
- hoursLeft = prepareHour - hour;
- if(minute > prepareMinute)
- {
- minutesLeft = 60 - (minute - prepareMinute);
- hoursLeft--;
- }
- else if(minute != prepareMinute)
- minutesLeft = prepareMinute - minute;
- }
- else
- {
- if(minute > prepareMinute)
- {
- minutesLeft = 55 - (minute - prepareMinute);
- hoursLeft = 23;
- }
- else
- {
- minutesLeft = prepareMinute - minute;
- if(minutesLeft >= 5)
- minutesLeft = minutesLeft - 5;
- else if(minutesLeft == 3 || minutesLeft == 1)
- {
- prepareGlobalSave(minutesLeft);
- return;
- }
- else if(minutesLeft > 0)
- {
- broadcast = (minutesLeft == 2 ? 1 : 3);
- minutesLeft = 1;
- }
- }
- }
- uint32_t timeLeft = (hoursLeft * 60 * 60 * 1000) + (minutesLeft * 60 * 1000);
- if(timeLeft > 0)
- {
- timeLeft -= second * 1000;
- saveEvent = Scheduler::getInstance().addEvent(createSchedulerTask(timeLeft,
- boost::bind(&Game::prepareGlobalSave, this, broadcast)));
- }
- }
- void Game::loadGameState()
- {
- ScriptEnviroment::loadGameState();
- loadMotd();
- loadPlayersRecord();
- checkHighscores();
- }
- void Game::setGameState(GameState_t newState)
- {
- if(gameState == GAMESTATE_SHUTDOWN)
- return; //this cannot be stopped
- if(gameState != newState)
- {
- gameState = newState;
- switch(newState)
- {
- case GAMESTATE_INIT:
- {
- Spawns::getInstance()->startup();
- Raids::getInstance()->loadFromXml();
- Raids::getInstance()->startup();
- Quests::getInstance()->loadFromXml();
- loadGameState();
- g_globalEvents->startup();
- IOBan::getInstance()->clearTemporials();
- if(g_config.getBool(ConfigManager::INIT_PREMIUM_UPDATE))
- IOLoginData::getInstance()->updatePremiumDays();
- IOGuild::getInstance()->checkWars();
- break;
- }
- case GAMESTATE_SHUTDOWN:
- {
- g_globalEvents->execute(GLOBALEVENT_SHUTDOWN);
- AutoList<Player>::iterator it = Player::autoList.begin();
- while(it != Player::autoList.end()) //kick all players that are still online
- {
- it->second->kick(true, true);
- it = Player::autoList.begin();
- }
- Houses::getInstance()->payHouses();
- saveGameState(false);
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::shutdown, this)));
- Scheduler::getInstance().stop();
- Dispatcher::getInstance().stop();
- break;
- }
- case GAMESTATE_CLOSED:
- {
- AutoList<Player>::iterator it = Player::autoList.begin();
- while(it != Player::autoList.end()) //kick all players who not allowed to stay
- {
- if(!it->second->hasFlag(PlayerFlag_CanAlwaysLogin))
- {
- it->second->kick(true, true);
- it = Player::autoList.begin();
- }
- else
- ++it;
- }
- saveGameState(false);
- break;
- }
- case GAMESTATE_NORMAL:
- case GAMESTATE_MAINTAIN:
- case GAMESTATE_STARTUP:
- case GAMESTATE_CLOSING:
- default:
- break;
- }
- }
- }
- void Game::saveGameState(bool shallow)
- {
- std::clog << "> Saving server..." << std::endl;
- uint64_t start = OTSYS_TIME();
- if(gameState == GAMESTATE_NORMAL)
- setGameState(GAMESTATE_MAINTAIN);
- IOLoginData* io = IOLoginData::getInstance();
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- it->second->loginPosition = it->second->getPosition();
- io->savePlayer(it->second, false, shallow);
- }
- map->saveMap();
- ScriptEnviroment::saveGameState();
- if(gameState == GAMESTATE_MAINTAIN)
- setGameState(GAMESTATE_NORMAL);
- std::clog << "> SAVE: Complete in " << (OTSYS_TIME() - start) / (1000.) << " seconds using "
- << asLowerCaseString(g_config.getString(ConfigManager::HOUSE_STORAGE))
- << " house storage." << std::endl;
- }
- int32_t Game::loadMap(std::string filename)
- {
- if(!map)
- map = new Map;
- std::string file = getFilePath(FILE_TYPE_CONFIG, "world/" + filename);
- if(!fileExists(file.c_str()))
- file = getFilePath(FILE_TYPE_OTHER, "world/" + filename);
- return map->loadMap(file);
- }
- void Game::cleanMap(uint32_t& count)
- {
- uint64_t start = OTSYS_TIME();
- uint32_t tiles = 0; count = 0;
- int32_t marked = -1;
- if(gameState == GAMESTATE_NORMAL)
- setGameState(GAMESTATE_MAINTAIN);
- Tile* tile = NULL;
- ItemVector::iterator tit;
- if(g_config.getBool(ConfigManager::STORE_TRASH))
- {
- marked = trash.size();
- Trash::iterator it = trash.begin();
- if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES))
- {
- for(; it != trash.end(); ++it)
- {
- if(!(tile = getTile(*it)))
- continue;
- tile->resetFlag(TILESTATE_TRASHED);
- if(tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList())
- continue;
- ++tiles;
- tit = tile->getItemList()->begin();
- while(tile->getItemList() && tit != tile->getItemList()->end())
- {
- if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
- && !(*tit)->isScriptProtected())
- {
- internalRemoveItem(NULL, *tit);
- if(tile->getItemList())
- tit = tile->getItemList()->begin();
- ++count;
- }
- else
- ++tit;
- }
- }
- }
- else
- {
- for(; it != trash.end(); ++it)
- {
- if(!(tile = getTile(*it)))
- continue;
- tile->resetFlag(TILESTATE_TRASHED);
- if(tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList())
- continue;
- ++tiles;
- tit = tile->getItemList()->begin();
- while(tile->getItemList() && tit != tile->getItemList()->end())
- {
- if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
- && !(*tit)->isScriptProtected())
- {
- internalRemoveItem(NULL, *tit);
- if(tile->getItemList())
- tit = tile->getItemList()->begin();
- ++count;
- }
- else
- ++tit;
- }
- }
- }
- trash.clear();
- }
- else if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES))
- {
- for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++)
- {
- for(uint16_t y = 1; y <= map->mapHeight; y++)
- {
- for(uint16_t x = 1; x <= map->mapWidth; x++)
- {
- if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList())
- continue;
- ++tiles;
- tit = tile->getItemList()->begin();
- while(tile->getItemList() && tit != tile->getItemList()->end())
- {
- if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
- && !(*tit)->isScriptProtected())
- {
- internalRemoveItem(NULL, *tit);
- if(tile->getItemList())
- tit = tile->getItemList()->begin();
- ++count;
- }
- else
- ++tit;
- }
- }
- }
- }
- }
- else
- {
- for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++)
- {
- for(uint16_t y = 1; y <= map->mapHeight; y++)
- {
- for(uint16_t x = 1; x <= map->mapWidth; x++)
- {
- if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList())
- continue;
- ++tiles;
- tit = tile->getItemList()->begin();
- while(tile->getItemList() && tit != tile->getItemList()->end())
- {
- if((*tit)->isMovable() && !(*tit)->isLoadedFromMap()
- && !(*tit)->isScriptProtected())
- {
- internalRemoveItem(NULL, *tit);
- if(tile->getItemList())
- tit = tile->getItemList()->begin();
- ++count;
- }
- else
- ++tit;
- }
- }
- }
- }
- }
- if(gameState == GAMESTATE_MAINTAIN)
- setGameState(GAMESTATE_NORMAL);
- std::clog << "> CLEAN: Removed " << count << " item" << (count != 1 ? "s" : "")
- << " from " << tiles << " tile" << (tiles != 1 ? "s" : "");
- if(marked >= 0)
- std::clog << " (" << marked << " were marked)";
- std::clog << " in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
- }
- void Game::proceduralRefresh(RefreshTiles::iterator* it/* = NULL*/)
- {
- if(!it)
- it = new RefreshTiles::iterator(refreshTiles.begin());
- // Refresh 250 tiles each cycle
- refreshMap(it, 250);
- if((*it) != refreshTiles.end())
- {
- delete it;
- return;
- }
- // Refresh some items every 100 ms until all tiles has been checked
- // For 100k tiles, this would take 100000/2500 = 40s = half a minute
- Scheduler::getInstance().addEvent(createSchedulerTask(100,
- boost::bind(&Game::proceduralRefresh, this, it)));
- }
- void Game::refreshMap(RefreshTiles::iterator* it/* = NULL*/, uint32_t limit/* = 0*/)
- {
- RefreshTiles::iterator end = refreshTiles.end();
- if(!it)
- {
- RefreshTiles::iterator begin = refreshTiles.begin();
- it = &begin;
- }
- Tile* tile = NULL;
- TileItemVector* items = NULL;
- Item* item = NULL;
- for(uint32_t cleaned = 0, downItemsSize = 0; (*it) != end &&
- (limit ? (cleaned < limit) : true); ++(*it), ++cleaned)
- {
- if(!(tile = (*it)->first))
- continue;
- if((items = tile->getItemList()))
- {
- downItemsSize = tile->getDownItemCount();
- for(uint32_t i = downItemsSize - 1; i; --i)
- {
- if((item = items->at(i)))
- {
- #ifndef __DEBUG__
- internalRemoveItem(NULL, item);
- #else
- if(internalRemoveItem(NULL, item) != RET_NOERROR)
- {
- std::clog << "> WARNING: Could not refresh item: " << item->getID();
- std::clog << " at position: " << tile->getPosition() << std::endl;
- }
- #endif
- }
- }
- }
- cleanup();
- TileItemVector list = (*it)->second.list;
- for(ItemVector::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
- {
- Item* item = (*it)->clone();
- if(internalAddItem(NULL, tile, item , INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
- {
- if(item->getUniqueId() != 0)
- ScriptEnviroment::addUniqueThing(item);
- startDecay(item);
- }
- else
- {
- std::clog << "> WARNING: Could not refresh item: " << item->getID()
- << " at position: " << tile->getPosition() << std::endl;
- delete item;
- }
- }
- }
- }
- bool Game::isSwimmingPool(Item* item, const Tile* tile, bool checkProtection) const
- {
- if(!tile)
- return false;
- TrashHolder* trashHolder = NULL;
- if(!item)
- trashHolder = tile->getTrashHolder();
- else
- trashHolder = item->getTrashHolder();
- return trashHolder && trashHolder->getEffect() == MAGIC_EFFECT_LOSE_ENERGY && (!checkProtection
- || tile->getZone() == ZONE_PROTECTION || tile->getZone() == ZONE_OPTIONAL);
- }
- Cylinder* Game::internalGetCylinder(Player* player, const Position& pos)
- {
- if(pos.x != 0xFFFF)
- return getTile(pos);
- //container
- if(pos.y & 0x40)
- return player->getContainer((uint8_t)(pos.y & 0x0F));
- return player;
- }
- Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index,
- uint32_t spriteId/* = 0*/, stackposType_t type/* = STACKPOS_NORMAL*/)
- {
- if(pos.x != 0xFFFF)
- {
- Tile* tile = getTile(pos);
- if(!tile)
- return NULL;
- if(type == STACKPOS_LOOK)
- return tile->getTopVisibleThing(player);
- Thing* thing = NULL;
- switch(type)
- {
- case STACKPOS_MOVE:
- {
- Item* item = tile->getTopDownItem();
- if(item && item->isMovable())
- thing = item;
- else
- thing = tile->getTopVisibleCreature(player);
- break;
- }
- case STACKPOS_USE:
- {
- thing = tile->getTopDownItem();
- break;
- }
- case STACKPOS_USEITEM:
- {
- Item* downItem = tile->getTopDownItem();
- Item* item = tile->getItemByTopOrder(2);
- if(item && g_actions->hasAction(item))
- {
- const ItemType& it = Item::items[item->getID()];
- if(!downItem || (!it.hasHeight && !it.allowPickupable))
- thing = item;
- }
- if(!thing)
- thing = downItem;
- if(!thing)
- thing = tile->getTopTopItem();
- if(!thing)
- thing = tile->ground;
- break;
- }
- default:
- thing = tile->__getThing(index);
- break;
- }
- if(player && thing && thing->getItem())
- {
- if(tile->hasProperty(ISVERTICAL))
- {
- if(player->getPosition().x + 1 == tile->getPosition().x)
- thing = NULL;
- }
- else if(tile->hasProperty(ISHORIZONTAL) && player->getPosition().y + 1 == tile->getPosition().y)
- thing = NULL;
- }
- return thing;
- }
- else if(pos.y & 0x40)
- {
- uint8_t fromCid = pos.y & 0x0F, slot = pos.z;
- if(Container* parentcontainer = player->getContainer(fromCid))
- return parentcontainer->getItem(slot);
- }
- else if(!pos.y && !pos.z)
- {
- const ItemType& it = Item::items.getItemIdByClientId(spriteId);
- if(!it.id)
- return NULL;
- int32_t subType = -1;
- if(it.isFluidContainer() && index < int32_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
- subType = reverseFluidMap[index];
- return findItemOfType(player, it.id, true, subType);
- }
- return player->getInventoryItem((slots_t)static_cast<uint8_t>(pos.y));
- }
- void Game::internalGetPosition(Item* item, Position& pos, int16_t& stackpos)
- {
- pos.x = pos.y = pos.z = stackpos = 0;
- if(Cylinder* topParent = item->getTopParent())
- {
- if(Player* player = dynamic_cast<Player*>(topParent))
- {
- pos.x = 0xFFFF;
- Container* container = dynamic_cast<Container*>(item->getParent());
- if(container)
- {
- pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) );
- pos.z = container->__getIndexOfThing(item);
- stackpos = pos.z;
- }
- else
- {
- pos.y = player->__getIndexOfThing(item);
- stackpos = pos.y;
- }
- }
- else if(Tile* tile = topParent->getTile())
- {
- pos = tile->getPosition();
- stackpos = tile->__getIndexOfThing(item);
- }
- }
- }
- Creature* Game::getCreatureByID(uint32_t id)
- {
- if(!id)
- return NULL;
- AutoList<Creature>::iterator it = autoList.find(id);
- if(it != autoList.end() && !it->second->isRemoved())
- return it->second;
- return NULL; //just in case the player doesnt exist
- }
- Player* Game::getPlayerByID(uint32_t id)
- {
- if(!id)
- return NULL;
- AutoList<Player>::iterator it = Player::autoList.find(id);
- if(it != Player::autoList.end() && !it->second->isRemoved())
- return it->second;
- return NULL; //just in case the player doesnt exist
- }
- Creature* Game::getCreatureByName(std::string s)
- {
- if(s.empty())
- return NULL;
- toLowerCaseString(s);
- for(AutoList<Creature>::iterator it = autoList.begin(); it != autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
- return it->second;
- }
- return NULL; //just in case the creature doesnt exist
- }
- Player* Game::getPlayerByName(std::string s)
- {
- if(s.empty())
- return NULL;
- toLowerCaseString(s);
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
- return it->second;
- }
- return NULL;
- }
- Player* Game::getPlayerByNameEx(const std::string& s)
- {
- Player* player = getPlayerByName(s);
- if(player)
- return player;
- std::string name = s;
- if(!IOLoginData::getInstance()->playerExists(name))
- return NULL;
- player = new Player(name, NULL);
- if(IOLoginData::getInstance()->loadPlayer(player, name))
- return player;
- #ifdef __DEBUG__
- std::clog << "[Failure - Game::getPlayerByNameEx] Cannot load player: " << name << std::endl;
- #endif
- delete player;
- return NULL;
- }
- Player* Game::getPlayerByGuid(uint32_t guid)
- {
- if(!guid)
- return NULL;
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && it->second->getGUID() == guid)
- return it->second;
- }
- return NULL;
- }
- Player* Game::getPlayerByGuidEx(uint32_t guid)
- {
- Player* player = getPlayerByGuid(guid);
- if(player)
- return player;
- std::string name;
- if(!IOLoginData::getInstance()->getNameByGuid(guid, name))
- return NULL;
- player = new Player(name, NULL);
- if(IOLoginData::getInstance()->loadPlayer(player, name))
- return player;
- #ifdef __DEBUG__
- std::clog << "[Failure - Game::getPlayerByGuidEx] Cannot load player: " << name << std::endl;
- #endif
- delete player;
- return NULL;
- }
- ReturnValue Game::getPlayerByNameWildcard(std::string s, Player*& player)
- {
- player = NULL;
- if(s.empty())
- return RET_PLAYERWITHTHISNAMEISNOTONLINE;
- char tmp = *s.rbegin();
- if(tmp != '~' && tmp != '*')
- {
- player = getPlayerByName(s);
- if(!player)
- return RET_PLAYERWITHTHISNAMEISNOTONLINE;
- return RET_NOERROR;
- }
- Player* last = NULL;
- s = s.substr(0, s.length() - 1);
- toLowerCaseString(s);
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(it->second->isRemoved())
- continue;
- std::string name = asLowerCaseString(it->second->getName());
- if(name.substr(0, s.length()) != s)
- continue;
- if(last)
- return RET_NAMEISTOOAMBIGUOUS;
- last = it->second;
- }
- if(!last)
- return RET_PLAYERWITHTHISNAMEISNOTONLINE;
- player = last;
- return RET_NOERROR;
- }
- Player* Game::getPlayerByAccount(uint32_t acc)
- {
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && it->second->getAccount() == acc)
- return it->second;
- }
- return NULL;
- }
- PlayerVector Game::getPlayersByName(std::string s)
- {
- toLowerCaseString(s);
- PlayerVector players;
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
- players.push_back(it->second);
- }
- return players;
- }
- PlayerVector Game::getPlayersByAccount(uint32_t acc)
- {
- PlayerVector players;
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && it->second->getAccount() == acc)
- players.push_back(it->second);
- }
- return players;
- }
- PlayerVector Game::getPlayersByIP(uint32_t ip, uint32_t mask)
- {
- PlayerVector players;
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->isRemoved() && (it->second->getIP() & mask) == (ip & mask))
- players.push_back(it->second);
- }
- return players;
- }
- bool Game::internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/)
- {
- if(creature->getParent())
- return false;
- if(!map->placeCreature(pos, creature, extendedPos, forced))
- return false;
- creature->addRef();
- creature->setID();
- autoList[creature->getID()] = creature;
- creature->addList();
- return true;
- }
- bool Game::placeCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/)
- {
- if(!internalPlaceCreature(creature, pos, extendedPos, forced))
- return false;
- Player* tmpPlayer = NULL;
- if((tmpPlayer = creature->getPlayer()) && !tmpPlayer->storedConditionList.empty())
- {
- for(ConditionList::iterator it = tmpPlayer->storedConditionList.begin(); it != tmpPlayer->storedConditionList.end(); ++it)
- {
- if((*it)->getType() == CONDITION_MUTED && (*it)->getTicks() != -1 &&
- (*it)->getTicks() - ((time(NULL) - tmpPlayer->getLastLogout()) * 1000) <= 0)
- continue;
- tmpPlayer->addCondition(*it);
- }
- tmpPlayer->storedConditionList.clear();
- }
- SpectatorVec::iterator it;
- SpectatorVec list;
- getSpectators(list, creature->getPosition(), false, true);
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureAppear(creature);
- }
- for(it = list.begin(); it != list.end(); ++it)
- (*it)->onCreatureAppear(creature);
- creature->setLastPosition(pos);
- creature->getParent()->postAddNotification(NULL, creature, NULL, creature->getParent()->__getIndexOfThing(creature));
- addCreatureCheck(creature);
- creature->onPlacedCreature();
- return true;
- }
- ReturnValue Game::placeSummon(Creature* creature, const std::string& name)
- {
- Monster* monster = Monster::createMonster(name);
- if(!monster)
- return RET_NOTPOSSIBLE;
- // Place the monster
- creature->addSummon(monster);
- if(placeCreature(monster, creature->getPosition(), true))
- {
- addMagicEffect(monster->getPosition(), MAGIC_EFFECT_TELEPORT);
- return RET_NOERROR;
- }
- creature->removeSummon(monster);
- return RET_NOTENOUGHROOM;
- }
- bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
- {
- if(creature->isRemoved())
- return false;
- Tile* tile = creature->getTile();
- SpectatorVec list;
- getSpectators(list, tile->getPosition(), false, true);
- SpectatorVec::iterator it;
- for(it = list.begin(); it != list.end(); ++it)
- (*it)->onCreatureDisappear(creature, isLogout);
- if(tile != creature->getTile())
- {
- list.clear();
- tile = creature->getTile();
- getSpectators(list, tile->getPosition(), false, true);
- }
- Player* player = NULL;
- std::vector<uint32_t> oldStackPosVector;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((player = (*it)->getPlayer()) && player->canSeeCreature(creature))
- oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature));
- }
- int32_t oldIndex = tile->__getIndexOfThing(creature);
- if(!map->removeCreature(creature))
- return false;
- //send to client
- uint32_t i = 0;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if(creature != (*it))
- (*it)->updateTileCache(tile);
- if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature))
- continue;
- player->setWalkthrough(creature, false);
- player->sendCreatureDisappear(creature, oldStackPosVector[i]);
- ++i;
- }
- creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true);
- creature->onRemovedCreature();
- autoList.erase(creature->getID());
- freeThing(creature);
- removeCreatureCheck(creature);
- for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it)
- removeCreature(*it);
- return true;
- }
- bool Game::playerMoveThing(uint32_t playerId, const Position& fromPos,
- uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- uint8_t fromIndex = 0;
- if(fromPos.x == 0xFFFF)
- {
- if(fromPos.y & 0x40)
- fromIndex = static_cast<uint8_t>(fromPos.z);
- else
- fromIndex = static_cast<uint8_t>(fromPos.y);
- }
- else
- fromIndex = fromStackpos;
- Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
- Cylinder* toCylinder = internalGetCylinder(player, toPos);
- if(!thing || !toCylinder)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(Creature* movingCreature = thing->getCreature())
- playerMoveCreature(playerId, movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition(), true);
- else if(thing->getItem())
- playerMoveItem(playerId, fromPos, spriteId, fromStackpos, toPos, count);
- return true;
- }
- bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
- const Position& movingCreaturePos, const Position& toPos, bool delay)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveCreatures))
- return false;
- if(!player->canDoAction())
- {
- uint32_t delay = player->getNextActionTime();
- SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature,
- this, playerId, movingCreatureId, movingCreaturePos, toPos, true));
- player->setNextActionTask(task);
- return false;
- }
- Creature* movingCreature = getCreatureByID(movingCreatureId);
- if(!movingCreature || movingCreature->isRemoved() || !player->canSeeCreature(movingCreature))
- return false;
- player->setNextActionTask(NULL);
- if(!Position::areInRange<1,1,0>(movingCreaturePos, player->getPosition()) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
- {
- //need to walk to the creature first before moving it
- std::list<Direction> listDir;
- if(getPathToEx(player, movingCreaturePos, listDir, 0, 1, true, true))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(std::max((int32_t)SCHEDULER_MINTICKS, player->getStepDuration()),
- boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos, false));
- player->setNextWalkActionTask(task);
- return true;
- }
- player->sendCancelMessage(RET_THEREISNOWAY);
- return false;
- }
- else if(delay)
- {
- uint32_t delayTime = g_config.getNumber(ConfigManager::PUSH_CREATURE_DELAY);
- if(delayTime > 0)
- {
- SchedulerTask* task = createSchedulerTask(delayTime,
- boost::bind(&Game::playerMoveCreature, this, playerId, movingCreatureId, movingCreaturePos, toPos, false));
- player->setNextActionTask(task);
- return true;
- }
- }
- Tile* toTile = map->getTile(toPos);
- if(!toTile)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(!player->hasFlag(PlayerFlag_CanPushAllCreatures))
- {
- if(!movingCreature->isPushable())
- {
- player->sendCancelMessage(RET_NOTMOVABLE);
- return false;
- }
- if(movingCreature->getNoMove())
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(toTile->hasProperty(BLOCKPATH))
- {
- player->sendCancelMessage(RET_NOTENOUGHROOM);
- return false;
- }
- }
- //check throw distance
- const Position& pos = movingCreature->getPosition();
- if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere) && ((std::abs(pos.x - toPos.x) > movingCreature->getThrowRange()) ||
- (std::abs(pos.y - toPos.y) > movingCreature->getThrowRange()) || (std::abs(pos.z - toPos.z) * 4 > movingCreature->getThrowRange())))
- {
- player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
- return false;
- }
- if(player != movingCreature)
- {
- if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone) && (movingCreature->getZone() == ZONE_PROTECTION
- || movingCreature->getZone() == ZONE_OPTIONAL) && !toTile->hasFlag(TILESTATE_OPTIONALZONE)
- && !toTile->hasFlag(TILESTATE_PROTECTIONZONE))
- {
- player->sendCancelMessage(RET_ACTIONNOTPERMITTEDINANOPVPZONE);
- return false;
- }
- if(!player->hasFlag(PlayerFlag_CanPushAllCreatures))
- {
- if(toTile->getCreatureCount() && !Item::items[
- movingCreature->getTile()->ground->getID()].walkStack)
- {
- player->sendCancelMessage(RET_NOTENOUGHROOM);
- return false;
- }
- if(MagicField* field = toTile->getFieldItem())
- {
- if(field->isUnstepable() || field->isBlocking(movingCreature)
- || !movingCreature->isImmune(field->getCombatType()))
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- }
- uint32_t protectionLevel = g_config.getNumber(ConfigManager::PROTECTION_LEVEL);
- if(player->getLevel() < protectionLevel && player->getVocation()->isAttackable())
- {
- Player* movingPlayer = movingCreature->getPlayer();
- if(movingPlayer && movingPlayer->getLevel() >= protectionLevel
- && movingPlayer->getVocation()->isAttackable())
- {
- player->sendCancelMessage(RET_NOTMOVABLE);
- return false;
- }
- }
- }
- }
- bool deny = false;
- CreatureEventList pushEvents = player->getCreatureEvents(CREATURE_EVENT_PUSH);
- for(CreatureEventList::iterator it = pushEvents.begin(); it != pushEvents.end(); ++it)
- {
- if(!(*it)->executePush(player, movingCreature) && !deny)
- deny = true;
- }
- if(deny)
- return false;
- ReturnValue ret = internalMoveCreature(player, movingCreature, movingCreature->getTile(), toTile);
- if(ret != RET_NOERROR)
- {
- if(!player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
- {
- player->sendCancelMessage(ret);
- return false;
- }
- if(!toTile->ground)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- internalTeleport(movingCreature, toTile->getPosition(), false);
- }
- else if(Player* movingPlayer = movingCreature->getPlayer())
- {
- uint64_t delay = OTSYS_TIME() + movingPlayer->getStepDuration();
- if(delay > movingPlayer->getNextActionTime())
- movingPlayer->setNextAction(delay);
- }
- return true;
- }
- ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction, uint32_t flags/* = 0*/)
- {
- const Position& currentPos = creature->getPosition();
- Cylinder* fromTile = creature->getTile();
- Cylinder* toTile = NULL;
- Position destPos = getNextPosition(direction, currentPos);
- if(direction < SOUTHWEST && creature->getPlayer())
- {
- Tile* tmpTile = NULL;
- if(currentPos.z != 8 && creature->getTile()->hasHeight(3)) //try go up
- {
- if((!(tmpTile = map->getTile(Position(currentPos.x, currentPos.y, currentPos.z - 1)))
- || (!tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))) &&
- (tmpTile = map->getTile(Position(destPos.x, destPos.y, destPos.z - 1)))
- && tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID) && !tmpTile->hasProperty(FLOORCHANGEDOWN))
- {
- flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
- destPos.z--;
- }
- }
- else if(currentPos.z != 7 && (!(tmpTile = map->getTile(destPos)) || (!tmpTile->ground &&
- !tmpTile->hasProperty(BLOCKSOLID))) && (tmpTile = map->getTile(Position(
- destPos.x, destPos.y, destPos.z + 1))) && tmpTile->hasHeight(3)) //try go down
- {
- flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
- destPos.z++;
- }
- }
- ReturnValue ret = RET_NOTPOSSIBLE;
- if((toTile = map->getTile(destPos)))
- ret = internalMoveCreature(NULL, creature, fromTile, toTile, flags);
- if(ret == RET_NOERROR)
- return RET_NOERROR;
- Player* player = creature->getPlayer();
- if(!player)
- return ret;
- player->sendCancelMessage(ret);
- player->sendCancelWalk();
- return ret;
- }
- ReturnValue Game::internalMoveCreature(Creature* actor, Creature* creature, Cylinder* fromCylinder,
- Cylinder* toCylinder, uint32_t flags/* = 0*/, bool forceTeleport/* = false*/)
- {
- //check if we can move the creature to the destination
- ReturnValue ret = toCylinder->__queryAdd(0, creature, 1, flags, actor);
- if(ret != RET_NOERROR)
- return ret;
- fromCylinder->getTile()->moveCreature(actor, creature, toCylinder, forceTeleport);
- if(creature->getParent() != toCylinder)
- return RET_NOERROR;
- Item* toItem = NULL;
- Cylinder* subCylinder = NULL;
- int32_t n = 0, tmp = 0;
- while((subCylinder = toCylinder->__queryDestination(tmp, creature, &toItem, flags)) != toCylinder)
- {
- toCylinder->getTile()->moveCreature(actor, creature, subCylinder);
- if(creature->getParent() != subCylinder) //could happen if a script move the creature
- break;
- toCylinder = subCylinder;
- flags = 0;
- if(++n >= MAP_MAX_LAYERS) //to prevent infinite loop
- break;
- }
- return RET_NOERROR;
- }
- bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
- uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveItems))
- return false;
- if(!player->canDoAction())
- {
- uint32_t delay = player->getNextActionTime();
- SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveItem, this,
- playerId, fromPos, spriteId, fromStackpos, toPos, count));
- player->setNextActionTask(task);
- return false;
- }
- player->setNextActionTask(NULL);
- Cylinder* fromCylinder = internalGetCylinder(player, fromPos);
- uint8_t fromIndex = 0;
- if(fromPos.x == 0xFFFF)
- {
- if(fromPos.y & 0x40)
- fromIndex = static_cast<uint8_t>(fromPos.z);
- else
- fromIndex = static_cast<uint8_t>(fromPos.y);
- }
- else
- fromIndex = fromStackpos;
- Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
- if(!thing || !thing->getItem())
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Item* item = thing->getItem();
- Cylinder* toCylinder = internalGetCylinder(player, toPos);
- uint8_t toIndex = 0;
- if(toPos.x == 0xFFFF)
- {
- if(toPos.y & 0x40)
- toIndex = static_cast<uint8_t>(toPos.z);
- else
- toIndex = static_cast<uint8_t>(toPos.y);
- }
- if(!fromCylinder || !toCylinder || !item || item->getClientID() != spriteId)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(!player->hasCustomFlag(PlayerCustomFlag_CanPushAllItems) && (!item->isPushable() || (item->isLoadedFromMap() &&
- (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer())))))
- {
- player->sendCancelMessage(RET_NOTMOVABLE);
- return false;
- }
- const Position &mapToPos = toCylinder->getTile()->getPosition(), &playerPos = player->getPosition(),
- &mapFromPos = fromCylinder->getTile()->getPosition();
- if(playerPos.z > mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
- {
- player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
- return false;
- }
- if(playerPos.z < mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
- {
- player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
- return false;
- }
- if(!Position::areInRange<1,1,0>(playerPos, mapFromPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
- {
- //need to walk to the item first before using it
- std::list<Direction> listDir;
- if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(std::max((int32_t)SCHEDULER_MINTICKS, player->getStepDuration()),
- boost::bind(&Game::playerMoveItem, this, playerId, fromPos, spriteId, fromStackpos, toPos, count));
- player->setNextWalkActionTask(task);
- return true;
- }
- player->sendCancelMessage(RET_THEREISNOWAY);
- return false;
- }
- //hangable item specific code
- if(item->isHangable() && toCylinder->getTile()->hasProperty(SUPPORTHANGABLE))
- {
- //destination supports hangable objects so need to move there first
- if(toCylinder->getTile()->hasProperty(ISVERTICAL))
- {
- if(player->getPosition().x + 1 == mapToPos.x)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- }
- else if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
- {
- if(player->getPosition().y + 1 == mapToPos.y)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- }
- if(!Position::areInRange<1,1,0>(playerPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
- {
- Position walkPos = mapToPos;
- if(toCylinder->getTile()->hasProperty(ISVERTICAL))
- walkPos.x -= -1;
- if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
- walkPos.y -= -1;
- Position itemPos = fromPos;
- int16_t itemStackpos = fromStackpos;
- if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition())
- && !Position::areInRange<1,1,0>(mapFromPos, walkPos))
- {
- //need to pickup the item first
- Item* moveItem = NULL;
- ReturnValue ret = internalMoveItem(player, fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem);
- if(ret != RET_NOERROR)
- {
- player->sendCancelMessage(ret);
- return false;
- }
- //changing the position since its now in the inventory of the player
- internalGetPosition(moveItem, itemPos, itemStackpos);
- }
- std::list<Direction> listDir;
- if(map->getPathTo(player, walkPos, listDir))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(std::max((int32_t)SCHEDULER_MINTICKS, player->getStepDuration()),
- boost::bind(&Game::playerMoveItem, this, playerId, itemPos, spriteId, itemStackpos, toPos, count));
- player->setNextWalkActionTask(task);
- return true;
- }
- player->sendCancelMessage(RET_THEREISNOWAY);
- return false;
- }
- }
- if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
- {
- if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) ||
- (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) ||
- (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange()))
- {
- player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
- return false;
- }
- }
- if(!canThrowObjectTo(mapFromPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
- {
- player->sendCancelMessage(RET_CANNOTTHROW);
- return false;
- }
- bool success = true;
- CreatureEventList moveitemEvents = player->getCreatureEvents(CREATURE_EVENT_MOVEITEM);
- for(CreatureEventList::iterator it = moveitemEvents.begin(); it != moveitemEvents.end(); ++it)
- {
- Item* toContainer = toCylinder->getItem();
- Item* fromContainer = fromCylinder->getItem();
- if(!(*it)->executeMoveItem(player, item, count, fromPos, toPos, (toContainer ? toContainer : 0), (fromContainer ? fromContainer : 0), fromStackpos) && success)
- success = false;
- }
- if(!success)
- return false;
- ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL);
- if(ret == RET_NOERROR)
- return true;
- player->setNextAction(OTSYS_TIME() + g_config.getNumber(ConfigManager::ACTIONS_DELAY_INTERVAL) - 2000);
- player->sendCancelMessage(ret);
- return false;
- }
- ReturnValue Game::internalMoveItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder,
- int32_t index, Item* item, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/)
- {
- if(!toCylinder)
- return RET_NOTPOSSIBLE;
- if(!item->getParent())
- {
- assert(fromCylinder == item->getParent());
- return internalAddItem(actor, toCylinder, item, INDEX_WHEREEVER, FLAG_NOLIMIT);
- }
- Item* toItem = NULL;
- Cylinder* subCylinder = NULL;
- int32_t floor = 0;
- while((subCylinder = toCylinder->__queryDestination(index, item, &toItem, flags)) != toCylinder)
- {
- flags = 0;
- toCylinder = subCylinder;
- //to prevent infinite loop
- if(++floor >= MAP_MAX_LAYERS)
- break;
- }
- //destination is the same as the source?
- if(item == toItem)
- return RET_NOERROR; //silently ignore move
- //check if we can add this item
- ReturnValue ret = toCylinder->__queryAdd(index, item, count, flags, actor);
- if(ret == RET_NEEDEXCHANGE)
- {
- //check if we can add it to source cylinder
- int32_t fromIndex = fromCylinder->__getIndexOfThing(item);
- if((ret = fromCylinder->__queryAdd(fromIndex, toItem, toItem->getItemCount(), 0, actor)) == RET_NOERROR)
- {
- //check how much we can move
- uint32_t maxExchangeQueryCount = 0;
- ReturnValue retExchangeMaxCount = fromCylinder->__queryMaxCount(-1, toItem, toItem->getItemCount(), maxExchangeQueryCount, 0);
- if(retExchangeMaxCount != RET_NOERROR && maxExchangeQueryCount == 0)
- return retExchangeMaxCount;
- if((toCylinder->__queryRemove(toItem, toItem->getItemCount(), flags, actor) == RET_NOERROR) && ret == RET_NOERROR)
- {
- int32_t oldToItemIndex = toCylinder->__getIndexOfThing(toItem);
- toCylinder->__removeThing(toItem, toItem->getItemCount());
- fromCylinder->__addThing(actor, toItem);
- if(oldToItemIndex != -1)
- toCylinder->postRemoveNotification(actor, toItem, fromCylinder, oldToItemIndex, true);
- int32_t newToItemIndex = fromCylinder->__getIndexOfThing(toItem);
- if(newToItemIndex != -1)
- fromCylinder->postAddNotification(actor, toItem, toCylinder, newToItemIndex);
- ret = toCylinder->__queryAdd(index, item, count, flags, actor);
- toItem = NULL;
- }
- }
- }
- if(ret != RET_NOERROR)
- return ret;
- //check how much we can move
- uint32_t maxQueryCount = 0;
- ReturnValue retMaxCount = toCylinder->__queryMaxCount(index, item, count, maxQueryCount, flags);
- if(retMaxCount != RET_NOERROR && !maxQueryCount)
- return retMaxCount;
- uint32_t m = maxQueryCount;
- if(item->isStackable())
- m = std::min((uint32_t)count, m);
- Item* moveItem = item;
- //check if we can remove this item
- if((fromCylinder->__queryRemove(item, m, flags, actor)) != RET_NOERROR)
- return ret;
- //remove the item
- int32_t itemIndex = fromCylinder->__getIndexOfThing(item);
- fromCylinder->__removeThing(item, m);
- bool isCompleteRemoval = item->isRemoved();
- Item* updateItem = NULL;
- if(item->isStackable())
- {
- uint8_t n = 0;
- if(toItem && toItem->getID() == item->getID())
- {
- n = std::min((uint32_t)100 - toItem->getItemCount(), m);
- toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
- updateItem = toItem;
- }
- if(m - n > 0)
- moveItem = Item::CreateItem(item->getID(), m - n);
- else
- moveItem = NULL;
- if(item->isRemoved())
- freeThing(item);
- }
- if(moveItem)
- toCylinder->__addThing(actor, index, moveItem);
- if(itemIndex != -1)
- fromCylinder->postRemoveNotification(actor, item, toCylinder, itemIndex, isCompleteRemoval);
- if(moveItem)
- {
- int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem);
- if(moveItemIndex != -1)
- toCylinder->postAddNotification(actor, moveItem, fromCylinder, moveItemIndex);
- }
- if(updateItem)
- {
- int32_t updateItemIndex = toCylinder->__getIndexOfThing(updateItem);
- if(updateItemIndex != -1)
- toCylinder->postAddNotification(actor, updateItem, fromCylinder, updateItemIndex);
- }
- if(_moveItem)
- {
- if(moveItem)
- *_moveItem = moveItem;
- else
- *_moveItem = item;
- }
- //we could not move all, inform the player
- if(item->isStackable() && maxQueryCount < count)
- return retMaxCount;
- return ret;
- }
- ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
- uint32_t flags/* = 0*/, bool test/* = false*/)
- {
- uint32_t remainderCount = 0;
- return internalAddItem(actor, toCylinder, item, index, flags, test, remainderCount);
- }
- ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index,
- uint32_t flags, bool test, uint32_t& remainderCount)
- {
- Item* stackItem = NULL;
- return internalAddItem(actor, toCylinder, item, index, flags, test, remainderCount, &stackItem);
- }
- ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index,
- uint32_t flags, bool test, uint32_t& remainderCount, Item** stackItem)
- {
- *stackItem = NULL;
- remainderCount = 0;
- if(!toCylinder || !item)
- return RET_NOTPOSSIBLE;
- Cylinder* destCylinder = toCylinder;
- toCylinder = toCylinder->__queryDestination(index, item, stackItem, flags);
- //check if we can add this item
- ReturnValue ret = toCylinder->__queryAdd(index, item, item->getItemCount(), flags, actor);
- if(ret != RET_NOERROR)
- return ret;
- uint32_t maxQueryCount = 0;
- ret = destCylinder->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), maxQueryCount, flags);
- if(ret != RET_NOERROR)
- return ret;
- if(test)
- return RET_NOERROR;
- Item* toItem = *stackItem;
- if(item->isStackable() && toItem)
- {
- uint32_t m = std::min((uint32_t)item->getItemCount(), maxQueryCount), n = 0;
- if(toItem->getID() == item->getID())
- {
- n = std::min((uint32_t)100 - toItem->getItemCount(), m);
- toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
- }
- uint32_t count = m - n;
- if(count > 0)
- {
- if(item->getItemCount() != count)
- {
- Item* remainderItem = Item::CreateItem(item->getID(), count);
- if((ret = internalAddItem(NULL, toCylinder, remainderItem, INDEX_WHEREEVER, flags, false)) == RET_NOERROR)
- {
- if(item->getParent() != VirtualCylinder::virtualCylinder)
- {
- item->onRemoved();
- freeThing(item);
- }
- return RET_NOERROR;
- }
- delete remainderItem;
- remainderCount = count;
- return ret;
- }
- }
- else
- {
- if(item->getParent() != VirtualCylinder::virtualCylinder)
- {
- item->onRemoved();
- freeThing(item);
- }
- return RET_NOERROR;
- }
- }
- toCylinder->__addThing(NULL, index, item);
- int32_t itemIndex = toCylinder->__getIndexOfThing(item);
- if(itemIndex != -1)
- toCylinder->postAddNotification(actor, item, NULL, itemIndex);
- return RET_NOERROR;
- }
- ReturnValue Game::internalRemoveItem(Creature* actor, Item* item, int32_t count /*= -1*/, bool test /*= false*/, uint32_t flags /*= 0*/)
- {
- Cylinder* cylinder = item->getParent();
- if(!cylinder)
- return RET_NOTPOSSIBLE;
- if(count == -1)
- count = item->getItemCount();
- //check if we can remove this item
- ReturnValue ret = cylinder->__queryRemove(item, count, flags | FLAG_IGNORENOTMOVABLE, actor);
- if(ret != RET_NOERROR)
- return ret;
- if(!item->canRemove())
- return RET_NOTPOSSIBLE;
- if(!test)
- {
- //remove the item
- int32_t index = cylinder->__getIndexOfThing(item);
- cylinder->__removeThing(item, count);
- bool isCompleteRemoval = false;
- if(item->isRemoved())
- {
- isCompleteRemoval = true;
- freeThing(item);
- }
- cylinder->postRemoveNotification(actor, item, NULL, index, isCompleteRemoval);
- }
- item->onRemoved();
- return RET_NOERROR;
- }
- ReturnValue Game::internalPlayerAddItem(Creature* actor, Player* player, Item* item,
- bool dropOnMap/* = true*/, slots_t slot/* = SLOT_WHEREEVER*/)
- {
- Item* toItem = NULL;
- uint32_t remainderCount = 0, count = item->getItemCount();
- ReturnValue ret = internalAddItem(actor, player, item, (int32_t)slot, 0, false, remainderCount, &toItem);
- if(ret == RET_NOERROR)
- return RET_NOERROR;
- if(dropOnMap)
- {
- if(!remainderCount)
- return internalAddItem(actor, player->getTile(), item, (int32_t)slot, FLAG_NOLIMIT);
- Item* remainderItem = Item::CreateItem(item->getID(), remainderCount);
- ReturnValue remainderRet = internalAddItem(actor, player->getTile(), remainderItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
- if(remainderRet == RET_NOERROR)
- return RET_NOERROR;
- delete remainderItem;
- }
- if(remainderCount && toItem)
- transformItem(toItem, toItem->getID(), (toItem->getItemCount() - (count - remainderCount)));
- return ret;
- }
- Item* Game::findItemOfType(Cylinder* cylinder, uint16_t itemId,
- bool depthSearch /*= true*/, int32_t subType /*= -1*/)
- {
- if(!cylinder)
- return NULL;
- std::list<Container*> listContainer;
- Container* tmpContainer = NULL;
- Thing* thing = NULL;
- Item* item = NULL;
- for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex();)
- {
- if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
- {
- if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
- return item;
- else
- {
- ++i;
- if(depthSearch && (tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- }
- }
- else
- ++i;
- }
- while(listContainer.size() > 0)
- {
- Container* container = listContainer.front();
- listContainer.pop_front();
- for(int32_t i = 0; i < (int32_t)container->size();)
- {
- Item* item = container->getItem(i);
- if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
- return item;
- else
- {
- ++i;
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- }
- }
- }
- return NULL;
- }
- bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType /*= -1*/)
- {
- if(!cylinder || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count))
- return false;
- if(count <= 0)
- return true;
- std::list<Container*> listContainer;
- Container* tmpContainer = NULL;
- Item* item = NULL;
- Thing* thing = NULL;
- for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0;)
- {
- if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
- {
- if(item->getID() == itemId)
- {
- if(item->isStackable())
- {
- if(item->getItemCount() > count)
- {
- internalRemoveItem(NULL, item, count);
- count = 0;
- }
- else
- {
- count -= item->getItemCount();
- internalRemoveItem(NULL, item);
- }
- }
- else if(subType == -1 || subType == item->getSubType())
- {
- --count;
- internalRemoveItem(NULL, item);
- }
- else
- ++i;
- }
- else
- {
- ++i;
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- }
- }
- else
- ++i;
- }
- while(listContainer.size() > 0 && count > 0)
- {
- Container* container = listContainer.front();
- listContainer.pop_front();
- for(int32_t i = 0; i < (int32_t)container->size() && count > 0;)
- {
- Item* item = container->getItem(i);
- if(item->getID() == itemId)
- {
- if(item->isStackable())
- {
- if(item->getItemCount() > count)
- {
- internalRemoveItem(NULL, item, count);
- count = 0;
- }
- else
- {
- count-= item->getItemCount();
- internalRemoveItem(NULL, item);
- }
- }
- else if(subType == -1 || subType == item->getSubType())
- {
- --count;
- internalRemoveItem(NULL, item);
- }
- else
- ++i;
- }
- else
- {
- ++i;
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- }
- }
- }
- return (count == 0);
- }
- uint64_t Game::getMoney(const Cylinder* cylinder)
- {
- if(!cylinder)
- return 0;
- std::list<Container*> listContainer;
- Container* tmpContainer = NULL;
- Item* item = NULL;
- Thing* thing = NULL;
- uint64_t moneyCount = 0;
- for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i)
- {
- if(!(thing = cylinder->__getThing(i)) || !(item = thing->getItem()))
- continue;
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- else if(item->getWorth() != 0)
- moneyCount += item->getWorth();
- }
- while(listContainer.size() > 0)
- {
- Container* container = listContainer.front();
- listContainer.pop_front();
- for(ItemList::const_iterator it = container->getItems(); it != container->getEnd(); ++it)
- {
- item = *it;
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- else if(item->getWorth() != 0)
- moneyCount += item->getWorth();
- }
- }
- return moneyCount;
- }
- bool Game::removeMoney(Cylinder* cylinder, int64_t money, uint32_t flags /*= 0*/)
- {
- if(!cylinder)
- return false;
- if(money <= 0)
- return true;
- typedef std::multimap<int32_t, Item*, std::less<int32_t> > MoneyMultiMap;
- MoneyMultiMap moneyMap;
- std::list<Container*> listContainer;
- Container* tmpContainer = NULL;
- Thing* thing = NULL;
- Item* item = NULL;
- int64_t moneyCount = 0;
- for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && money > 0; ++i)
- {
- if(!(thing = cylinder->__getThing(i)) || !(item = thing->getItem()))
- continue;
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- else if(item->getWorth() != 0)
- {
- moneyCount += item->getWorth();
- moneyMap.insert(std::make_pair(item->getWorth(), item));
- }
- }
- while(listContainer.size() > 0 && money > 0)
- {
- Container* container = listContainer.front();
- listContainer.pop_front();
- for(int32_t i = 0; i < (int32_t)container->size() && money > 0; i++)
- {
- Item* item = container->getItem(i);
- if((tmpContainer = item->getContainer()))
- listContainer.push_back(tmpContainer);
- else if(item->getWorth() != 0)
- {
- moneyCount += item->getWorth();
- moneyMap.insert(std::make_pair(item->getWorth(), item));
- }
- }
- }
- // Not enough money
- if(moneyCount < money)
- return false;
- for(MoneyMultiMap::iterator mit = moneyMap.begin(); mit != moneyMap.end() && money > 0; ++mit)
- {
- Item* item = mit->second;
- if(!item)
- continue;
- internalRemoveItem(NULL, item);
- if(mit->first > money)
- {
- // Remove a monetary value from an item
- addMoney(cylinder, (int64_t)(item->getWorth() - money), flags);
- money = 0;
- }
- else
- money -= mit->first;
- mit->second = NULL;
- }
- moneyMap.clear();
- return money == 0;
- }
- void Game::addMoney(Cylinder* cylinder, int64_t money, uint32_t flags /*= 0*/)
- {
- IntegerMap moneyMap = Item::items.getMoneyMap();
- for(IntegerMap::reverse_iterator it = moneyMap.rbegin(); it != moneyMap.rend(); ++it)
- {
- int64_t tmp = money / it->first;
- money -= tmp * it->first;
- if(!tmp)
- continue;
- do
- {
- uint32_t remainderCount = 0;
- Item* item = Item::CreateItem(it->second, std::min((int64_t)100, tmp));
- if(internalAddItem(NULL, cylinder, item, INDEX_WHEREEVER, flags, false, remainderCount) != RET_NOERROR)
- {
- if(remainderCount)
- {
- delete item;
- item = Item::CreateItem(it->second, remainderCount);
- }
- if(internalAddItem(NULL, cylinder->getTile(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
- delete item;
- }
- tmp -= std::min((int64_t)100, tmp);
- }
- while(tmp > 0);
- }
- }
- Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount /*= -1*/)
- {
- if(item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount != 0)))
- return item;
- Cylinder* cylinder = item->getParent();
- if(!cylinder)
- return NULL;
- int32_t itemIndex = cylinder->__getIndexOfThing(item);
- if(itemIndex == -1)
- {
- #ifdef __DEBUG__
- std::clog << "Error: transformItem, itemIndex == -1" << std::endl;
- #endif
- return item;
- }
- if(!item->canTransform())
- return item;
- const ItemType& curType = Item::items[item->getID()];
- const ItemType& newType = Item::items[newId];
- if(curType.alwaysOnTop != newType.alwaysOnTop)
- {
- //This only occurs when you transform items on tiles from a downItem to a topItem (or vice versa)
- //Remove the old, and add the new
- ReturnValue ret = internalRemoveItem(NULL, item);
- if(ret != RET_NOERROR)
- return item;
- Item* newItem = NULL;
- if(newCount == -1)
- newItem = Item::CreateItem(newId);
- else
- newItem = Item::CreateItem(newId, newCount);
- if(!newItem)
- return NULL;
- newItem->copyAttributes(item);
- if(internalAddItem(NULL, cylinder, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
- return newItem;
- delete newItem;
- return NULL;
- }
- if(curType.type == newType.type)
- {
- //Both items has the same type so we can safely change id/subtype
- if(!newCount && (item->isStackable() || item->hasCharges()))
- {
- if(!item->isStackable() && (!item->getDefaultDuration() || item->getDuration() <= 0))
- {
- int32_t tmpId = newId;
- if(curType.id == newType.id)
- tmpId = curType.decayTo;
- if(tmpId != -1)
- {
- item = transformItem(item, tmpId);
- return item;
- }
- }
- internalRemoveItem(NULL, item);
- return NULL;
- }
- uint16_t itemId = item->getID();
- int32_t count = item->getSubType();
- cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, false);
- if(curType.id != newType.id)
- {
- itemId = newId;
- if(newType.group != curType.group)
- item->setDefaultSubtype();
- }
- if(newCount != -1 && newType.hasSubType())
- count = newCount;
- cylinder->__updateThing(item, itemId, count);
- cylinder->postAddNotification(NULL, item, cylinder, itemIndex);
- return item;
- }
- //Replacing the the old item with the new while maintaining the old position
- Item* newItem = NULL;
- if(newCount == -1)
- newItem = Item::CreateItem(newId);
- else
- newItem = Item::CreateItem(newId, newCount);
- if(!newItem)
- {
- #ifdef __DEBUG__
- std::clog << "Error: [Game::transformItem] Item of type " << item->getID() << " transforming into invalid type " << newId << std::endl;
- #endif
- return NULL;
- }
- cylinder->__replaceThing(itemIndex, newItem);
- cylinder->postAddNotification(NULL, newItem, cylinder, itemIndex);
- item->setParent(NULL);
- cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, true);
- freeThing(item);
- return newItem;
- }
- ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool forceTeleport, uint32_t flags/* = 0*/, bool fullTeleport/* = true*/)
- {
- if(newPos == thing->getPosition())
- return RET_NOERROR;
- if(thing->isRemoved())
- return RET_NOTPOSSIBLE;
- if(Tile* toTile = map->getTile(newPos))
- {
- if(Creature* creature = thing->getCreature())
- {
- if(fullTeleport)
- return internalMoveCreature(NULL, creature, creature->getParent(), toTile, flags, forceTeleport);
- creature->getTile()->moveCreature(NULL, creature, toTile, forceTeleport);
- return RET_NOERROR;
- }
- if(Item* item = thing->getItem())
- return internalMoveItem(NULL, item->getParent(), toTile, INDEX_WHEREEVER, item, item->getItemCount(), NULL, flags);
- }
- return RET_NOTPOSSIBLE;
- }
- bool Game::playerMove(uint32_t playerId, Direction dir)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->setIdleTime(0);
- if(player->getNoMove())
- {
- player->sendCancelWalk();
- return false;
- }
- std::list<Direction> dirs;
- dirs.push_back(dir);
- return player->startAutoWalk(dirs);
- }
- bool Game::playerBroadcastMessage(Player* player, SpeakClasses type, const std::string& text)
- {
- if(!player->hasFlag(PlayerFlag_CanBroadcast) || type < SPEAK_CLASS_FIRST || type > SPEAK_CLASS_LAST)
- return false;
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- it->second->sendCreatureSay(player, type, text);
- //TODO: event handling - onCreatureSay
- std::clog << "> " << player->getName() << " broadcasted: \"" << text << "\"." << std::endl;
- return true;
- }
- bool Game::playerCreatePrivateChannel(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || !player->isPremium())
- return false;
- ChatChannel* channel = g_chat.createChannel(player, 0xFFFF);
- if(!channel || !channel->addUser(player))
- return false;
- player->sendCreatePrivateChannel(channel->getId(), channel->getName());
- return true;
- }
- bool Game::playerChannelInvite(uint32_t playerId, const std::string& name)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
- if(!channel)
- return false;
- Player* invitePlayer = getPlayerByName(name);
- if(!invitePlayer)
- return false;
- channel->invitePlayer(player, invitePlayer);
- return true;
- }
- bool Game::playerChannelExclude(uint32_t playerId, const std::string& name)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
- if(!channel)
- return false;
- Player* excludePlayer = getPlayerByName(name);
- if(!excludePlayer)
- return false;
- channel->excludePlayer(player, excludePlayer);
- return true;
- }
- bool Game::playerRequestChannels(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->sendChannelsDialog();
- return true;
- }
- bool Game::playerOpenChannel(uint32_t playerId, uint16_t channelId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- ChatChannel* channel = g_chat.addUserToChannel(player, channelId);
- if(!channel)
- {
- #ifdef __DEBUG_CHAT__
- std::clog << "Game::playerOpenChannel - failed adding user to channel." << std::endl;
- #endif
- return false;
- }
- if(channel->getId() != CHANNEL_RVR)
- player->sendChannel(channel->getId(), channel->getName());
- else
- player->sendRuleViolationsChannel(channel->getId());
- return true;
- }
- bool Game::playerCloseChannel(uint32_t playerId, uint16_t channelId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- g_chat.removeUserFromChannel(player, channelId);
- return true;
- }
- bool Game::playerOpenPrivateChannel(uint32_t playerId, std::string& receiver)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(IOLoginData::getInstance()->playerExists(receiver))
- player->sendOpenPrivateChannel(receiver);
- else
- player->sendCancel("A player with this name does not exist.");
- return true;
- }
- bool Game::playerProcessRuleViolation(uint32_t playerId, const std::string& name)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(!player->hasFlag(PlayerFlag_CanAnswerRuleViolations))
- return false;
- Player* reporter = getPlayerByName(name);
- if(!reporter)
- return false;
- RuleViolationsMap::iterator it = ruleViolations.find(reporter->getID());
- if(it == ruleViolations.end())
- return false;
- RuleViolation& rvr = *it->second;
- if(!rvr.isOpen)
- return false;
- rvr.isOpen = false;
- rvr.gamemaster = player;
- if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
- {
- UsersMap tmpMap = channel->getUsers();
- for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
- tit->second->sendRemoveReport(reporter->getName());
- }
- return true;
- }
- bool Game::playerCloseRuleViolation(uint32_t playerId, const std::string& name)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Player* reporter = getPlayerByName(name);
- if(!reporter)
- return false;
- return closeRuleViolation(reporter);
- }
- bool Game::playerCancelRuleViolation(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- return cancelRuleViolation(player);
- }
- bool Game::playerCloseNpcChannel(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- SpectatorVec list;
- SpectatorVec::iterator it;
- getSpectators(list, player->getPosition());
- Npc* npc = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((npc = (*it)->getNpc()))
- npc->onPlayerCloseChannel(player);
- }
- return true;
- }
- bool Game::playerReceivePing(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->receivePing();
- return true;
- }
- bool Game::playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->setIdleTime(0);
- if(player->getNoMove())
- {
- player->sendCancelWalk();
- return false;
- }
- if(player->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_TELEPORT))
- {
- Position pos = player->getPosition();
- for(std::list<Direction>::iterator it = listDir.begin(); it != listDir.end(); ++it)
- pos = getNextPosition((*it), pos);
- pos = getClosestFreeTile(player, pos, true, false);
- if(!pos.x || !pos.y)
- {
- player->sendCancelWalk();
- return false;
- }
- internalCreatureTurn(player, getDirectionTo(player->getPosition(), pos, false));
- internalTeleport(player, pos, true);
- return true;
- }
- player->setNextWalkTask(NULL);
- return player->startAutoWalk(listDir);
- }
- bool Game::playerStopAutoWalk(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->stopWalk();
- return true;
- }
- bool Game::playerUseItemEx(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint16_t fromSpriteId,
- const Position& toPos, int16_t toStackpos, uint16_t toSpriteId, bool isHotkey)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED))
- return false;
- Thing* thing = internalGetThing(player, fromPos, fromStackpos, fromSpriteId, STACKPOS_USEITEM);
- if(!thing)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Item* item = thing->getItem();
- if(!item || !item->isUsable())
- {
- player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
- return false;
- }
- Position walkToPos = fromPos;
- ReturnValue ret = g_actions->canUse(player, fromPos);
- if(ret == RET_NOERROR)
- {
- ret = g_actions->canUse(player, toPos, item);
- if(ret == RET_TOOFARAWAY)
- walkToPos = toPos;
- }
- if(ret != RET_NOERROR)
- {
- if(ret == RET_TOOFARAWAY)
- {
- Position itemPos = fromPos;
- int16_t itemStackpos = fromStackpos;
- if(fromPos.x != 0xFFFF && toPos.x != 0xFFFF && Position::areInRange<1,1,0>(fromPos,
- player->getPosition()) && !Position::areInRange<1,1,0>(fromPos, toPos))
- {
- Item* moveItem = NULL;
- ReturnValue retTmp = internalMoveItem(player, item->getParent(), player,
- INDEX_WHEREEVER, item, item->getItemCount(), &moveItem);
- if(retTmp != RET_NOERROR)
- {
- player->sendCancelMessage(retTmp);
- return false;
- }
- //changing the position since its now in the inventory of the player
- internalGetPosition(moveItem, itemPos, itemStackpos);
- }
- std::list<Direction> listDir;
- if(getPathToEx(player, walkToPos, listDir, 0, 1, true, true, 10))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItemEx, this,
- playerId, itemPos, itemStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey));
- player->setNextWalkActionTask(task);
- return true;
- }
- ret = RET_THEREISNOWAY;
- }
- player->sendCancelMessage(ret);
- return false;
- }
- if(isHotkey)
- showHotkeyUseMessage(player, item);
- if(!player->canDoAction())
- {
- uint32_t delay = player->getNextActionTime();
- SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItemEx, this,
- playerId, fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey));
- player->setNextActionTask(task);
- return false;
- }
- player->setNextActionTask(NULL);
- return g_actions->useItemEx(player, fromPos, toPos, toStackpos, item, isHotkey);
- }
- bool Game::playerUseItem(uint32_t playerId, const Position& pos, int16_t stackpos,
- uint8_t index, uint16_t spriteId, bool isHotkey)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED))
- return false;
- Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USEITEM);
- if(!thing)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Item* item = thing->getItem();
- if(!item || item->isUsable())
- {
- player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
- return false;
- }
- ReturnValue ret = g_actions->canUse(player, pos);
- if(ret != RET_NOERROR)
- {
- if(ret == RET_TOOFARAWAY)
- {
- std::list<Direction> listDir;
- if(getPathToEx(player, pos, listDir, 0, 1, true, true))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItem, this,
- playerId, pos, stackpos, index, spriteId, isHotkey));
- player->setNextWalkActionTask(task);
- return true;
- }
- ret = RET_THEREISNOWAY;
- }
- player->sendCancelMessage(ret);
- return false;
- }
- if(isHotkey)
- showHotkeyUseMessage(player, item);
- if(!player->canDoAction())
- {
- uint32_t delay = player->getNextActionTime();
- SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItem, this,
- playerId, pos, stackpos, index, spriteId, isHotkey));
- player->setNextActionTask(task);
- return false;
- }
- player->setNextActionTask(NULL);
- return g_actions->useItem(player, pos, index, item);
- }
- bool Game::playerUseBattleWindow(uint32_t playerId, const Position& fromPos, int16_t fromStackpos,
- uint32_t creatureId, uint16_t spriteId, bool isHotkey)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Creature* creature = getCreatureByID(creatureId);
- if(!creature)
- return false;
- if(!Position::areInRange<7,5,0>(creature->getPosition(), player->getPosition()))
- return false;
- if(!g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED) && (creature->getPlayer() || isHotkey))
- {
- player->sendCancelMessage(RET_DIRECTPLAYERSHOOT);
- return false;
- }
- Thing* thing = internalGetThing(player, fromPos, fromStackpos, spriteId, STACKPOS_USE);
- if(!thing)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Item* item = thing->getItem();
- if(!item || item->getClientID() != spriteId)
- {
- player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
- return false;
- }
- ReturnValue ret = g_actions->canUse(player, fromPos);
- if(ret != RET_NOERROR)
- {
- if(ret == RET_TOOFARAWAY)
- {
- std::list<Direction> listDir;
- if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseBattleWindow, this,
- playerId, fromPos, fromStackpos, creatureId, spriteId, isHotkey));
- player->setNextWalkActionTask(task);
- return true;
- }
- ret = RET_THEREISNOWAY;
- }
- player->sendCancelMessage(ret);
- return false;
- }
- if(isHotkey)
- showHotkeyUseMessage(player, item);
- if(!player->canDoAction())
- {
- uint32_t delay = player->getNextActionTime();
- SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseBattleWindow, this,
- playerId, fromPos, fromStackpos, creatureId, spriteId, isHotkey));
- player->setNextActionTask(task);
- return false;
- }
- player->setNextActionTask(NULL);
- return g_actions->useItemEx(player, fromPos, creature->getPosition(),
- creature->getParent()->__getIndexOfThing(creature), item, isHotkey, creatureId);
- }
- bool Game::playerCloseContainer(uint32_t playerId, uint8_t cid)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->closeContainer(cid);
- player->sendCloseContainer(cid);
- return true;
- }
- bool Game::playerMoveUpContainer(uint32_t playerId, uint8_t cid)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Container* container = player->getContainer(cid);
- if(!container)
- return false;
- Container* parentContainer = dynamic_cast<Container*>(container->getParent());
- if(!parentContainer)
- return false;
- player->addContainer(cid, parentContainer);
- player->sendContainer(cid, parentContainer, (dynamic_cast<const Container*>(parentContainer->getParent()) != NULL));
- return true;
- }
- bool Game::playerUpdateTile(uint32_t playerId, const Position& pos)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(!player->canSee(pos))
- return false;
- if(Tile* tile = getTile(pos))
- player->sendUpdateTile(tile, pos);
- return true;
- }
- bool Game::playerUpdateContainer(uint32_t playerId, uint8_t cid)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Container* container = player->getContainer(cid);
- if(!container)
- return false;
- player->sendContainer(cid, container, (dynamic_cast<const Container*>(container->getParent()) != NULL));
- return true;
- }
- bool Game::playerRotateItem(uint32_t playerId, const Position& pos, int16_t stackpos, const uint16_t spriteId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Thing* thing = internalGetThing(player, pos, stackpos);
- if(!thing)
- return false;
- Item* item = thing->getItem();
- if(!item || item->getClientID() != spriteId || !item->isRoteable() || (item->isLoadedFromMap() &&
- (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer()))))
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(pos.x != 0xFFFF && !Position::areInRange<1,1,0>(pos, player->getPosition()))
- {
- std::list<Direction> listDir;
- if(getPathToEx(player, pos, listDir, 0, 1, true, true))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRotateItem, this,
- playerId, pos, stackpos, spriteId));
- player->setNextWalkActionTask(task);
- return true;
- }
- player->sendCancelMessage(RET_THEREISNOWAY);
- return false;
- }
- uint16_t newId = Item::items[item->getID()].rotateTo;
- if(newId != 0)
- transformItem(item, newId);
- return true;
- }
- bool Game::playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- uint16_t maxTextLength = 0;
- uint32_t internalWindowTextId = 0;
- Item* writeItem = player->getWriteItem(internalWindowTextId, maxTextLength);
- if(text.length() > maxTextLength || windowTextId != internalWindowTextId)
- return false;
- if(!writeItem || writeItem->isRemoved())
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Cylinder* topParent = writeItem->getTopParent();
- Player* owner = dynamic_cast<Player*>(topParent);
- if(owner && owner != player)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(!Position::areInRange<1,1,0>(writeItem->getPosition(), player->getPosition()))
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- bool deny = false;
- CreatureEventList textEditEvents = player->getCreatureEvents(CREATURE_EVENT_TEXTEDIT);
- for(CreatureEventList::iterator it = textEditEvents.begin(); it != textEditEvents.end(); ++it)
- {
- if(!(*it)->executeTextEdit(player, writeItem, text))
- deny = true;
- }
- if(deny)
- return false;
- if(!text.empty())
- {
- if(writeItem->getText() != text)
- {
- writeItem->setText(text);
- writeItem->setWriter(player->getName());
- writeItem->setDate(std::time(NULL));
- }
- }
- else
- {
- writeItem->resetText();
- writeItem->resetWriter();
- writeItem->resetDate();
- }
- uint16_t newId = Item::items[writeItem->getID()].writeOnceItemId;
- if(newId != 0)
- transformItem(writeItem, newId);
- player->setWriteItem(NULL);
- return true;
- }
- bool Game::playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- uint32_t internalWindowTextId = 0;
- uint32_t internalListId = 0;
- House* house = player->getEditHouse(internalWindowTextId, internalListId);
- if(house && internalWindowTextId == windowTextId && listId == 0)
- {
- house->setAccessList(internalListId, text);
- player->setEditHouse(NULL);
- }
- return true;
- }
- bool Game::playerRequestTrade(uint32_t playerId, const Position& pos, int16_t stackpos,
- uint32_t tradePlayerId, uint16_t spriteId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 8))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditiontrade = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 300, 0, false, 8))
- player->addCondition(conditiontrade);
- Player* tradePartner = getPlayerByID(tradePlayerId);
- if(!tradePartner || tradePartner == player)
- {
- player->sendTextMessage(MSG_INFO_DESCR, "Sorry, not possible.");
- return false;
- }
- if(!Position::areInRange<2,2,0>(tradePartner->getPosition(), player->getPosition()))
- {
- std::stringstream ss;
- ss << tradePartner->getName() << " tells you to move closer.";
- player->sendTextMessage(MSG_INFO_DESCR, ss.str());
- return false;
- }
- if(!canThrowObjectTo(tradePartner->getPosition(), player->getPosition())
- && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
- {
- player->sendCancelMessage(RET_CREATUREISNOTREACHABLE);
- return false;
- }
- Item* tradeItem = dynamic_cast<Item*>(internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USE));
- if(!tradeItem || tradeItem->getClientID() != spriteId || !tradeItem->isPickupable() || (tradeItem->isLoadedFromMap() &&
- (tradeItem->getUniqueId() != 0 || (tradeItem->getActionId() != 0 && tradeItem->getContainer()))))
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- if(player->getPosition().z > tradeItem->getPosition().z)
- {
- player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
- return false;
- }
- if(player->getPosition().z < tradeItem->getPosition().z)
- {
- player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
- return false;
- }
- if(!Position::areInRange<1,1,0>(tradeItem->getPosition(), player->getPosition()))
- {
- std::list<Direction> listDir;
- if(getPathToEx(player, pos, listDir, 0, 1, true, true))
- {
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
- this, player->getID(), listDir)));
- SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRequestTrade, this,
- playerId, pos, stackpos, tradePlayerId, spriteId));
- player->setNextWalkActionTask(task);
- return true;
- }
- player->sendCancelMessage(RET_THEREISNOWAY);
- return false;
- }
- const Container* container = NULL;
- for(std::map<Item*, uint32_t>::const_iterator it = tradeItems.begin(); it != tradeItems.end(); it++)
- {
- if(tradeItem == it->first ||
- ((container = dynamic_cast<const Container*>(tradeItem)) && container->isHoldingItem(it->first)) ||
- ((container = dynamic_cast<const Container*>(it->first)) && container->isHoldingItem(tradeItem)))
- {
- player->sendTextMessage(MSG_INFO_DESCR, "This item is already being traded.");
- return false;
- }
- }
- Container* tradeContainer = tradeItem->getContainer();
- if(tradeContainer && tradeContainer->getItemHoldingCount() + 1 > (uint32_t)g_config.getNumber(ConfigManager::TRADE_LIMIT))
- {
- player->sendTextMessage(MSG_INFO_DESCR, "You cannot trade more than 100 items.");
- return false;
- }
- bool deny = false;
- CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_REQUEST);
- for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it)
- {
- if(!(*it)->executeTradeRequest(player, tradePartner, tradeItem))
- deny = true;
- }
- if(deny)
- return false;
- return internalStartTrade(player, tradePartner, tradeItem);
- }
- bool Game::internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem)
- {
- if(player->tradeState != TRADE_NONE && !(player->tradeState == TRADE_ACKNOWLEDGE && player->tradePartner == tradePartner))
- {
- player->sendCancelMessage(RET_YOUAREALREADYTRADING);
- return false;
- }
- else if(tradePartner->tradeState != TRADE_NONE && tradePartner->tradePartner != player)
- {
- player->sendCancelMessage(RET_THISPLAYERISALREADYTRADING);
- return false;
- }
- player->tradePartner = tradePartner;
- player->tradeItem = tradeItem;
- player->tradeState = TRADE_INITIATED;
- tradeItem->addRef();
- tradeItems[tradeItem] = player->getID();
- player->sendTradeItemRequest(player, tradeItem, true);
- if(tradePartner->tradeState == TRADE_NONE)
- {
- char buffer[100];
- sprintf(buffer, "%s wants to trade with you", player->getName().c_str());
- tradePartner->sendTextMessage(MSG_INFO_DESCR, buffer);
- tradePartner->tradeState = TRADE_ACKNOWLEDGE;
- tradePartner->tradePartner = player;
- }
- else
- {
- Item* counterItem = tradePartner->tradeItem;
- player->sendTradeItemRequest(tradePartner, counterItem, false);
- tradePartner->sendTradeItemRequest(player, tradeItem, false);
- }
- return true;
- }
- bool Game::playerAcceptTrade(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || (player->getTradeState() != TRADE_ACKNOWLEDGE
- && player->getTradeState() != TRADE_INITIATED))
- return false;
- Player* tradePartner = player->tradePartner;
- if(!tradePartner)
- return false;
- if(!canThrowObjectTo(tradePartner->getPosition(), player->getPosition())
- && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
- {
- player->sendCancelMessage(RET_CREATUREISNOTREACHABLE);
- return false;
- }
- player->setTradeState(TRADE_ACCEPT);
- if(tradePartner->getTradeState() != TRADE_ACCEPT)
- return false;
- Item* tradeItem1 = player->tradeItem;
- Item* tradeItem2 = tradePartner->tradeItem;
- bool deny = false;
- CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_ACCEPT);
- for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it)
- {
- if(!(*it)->executeTradeAccept(player, tradePartner, tradeItem1, tradeItem2))
- deny = true;
- }
- if(deny)
- return false;
- player->setTradeState(TRADE_TRANSFER);
- tradePartner->setTradeState(TRADE_TRANSFER);
- std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradeItem1);
- if(it != tradeItems.end())
- {
- freeThing(it->first);
- tradeItems.erase(it);
- }
- it = tradeItems.find(tradeItem2);
- if(it != tradeItems.end())
- {
- freeThing(it->first);
- tradeItems.erase(it);
- }
- ReturnValue ret1 = internalAddItem(player, tradePartner, tradeItem1, INDEX_WHEREEVER, 0, true);
- ReturnValue ret2 = internalAddItem(tradePartner, player, tradeItem2, INDEX_WHEREEVER, 0, true);
- bool success = false;
- if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
- {
- ret1 = internalRemoveItem(tradePartner, tradeItem1, tradeItem1->getItemCount(), true);
- ret2 = internalRemoveItem(player, tradeItem2, tradeItem2->getItemCount(), true);
- if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
- {
- Cylinder *cylinder1 = tradeItem1->getParent(), *cylinder2 = tradeItem2->getParent();
- internalMoveItem(player, cylinder1, tradePartner, INDEX_WHEREEVER, tradeItem1, tradeItem1->getItemCount(), NULL);
- internalMoveItem(tradePartner, cylinder2, player, INDEX_WHEREEVER, tradeItem2, tradeItem2->getItemCount(), NULL);
- tradeItem1->onTradeEvent(ON_TRADE_TRANSFER, tradePartner, player);
- tradeItem2->onTradeEvent(ON_TRADE_TRANSFER, player, tradePartner);
- success = true;
- }
- }
- if(!success)
- {
- std::string error;
- if(tradeItem2)
- {
- error = getTradeErrorDescription(ret1, tradeItem1);
- tradePartner->sendTextMessage(MSG_INFO_DESCR, error);
- tradeItem2->onTradeEvent(ON_TRADE_CANCEL, tradePartner, NULL);
- }
- if(tradeItem1)
- {
- error = getTradeErrorDescription(ret2, tradeItem2);
- player->sendTextMessage(MSG_INFO_DESCR, error);
- tradeItem1->onTradeEvent(ON_TRADE_CANCEL, player, NULL);
- }
- }
- player->setTradeState(TRADE_NONE);
- player->tradeItem = NULL;
- player->tradePartner = NULL;
- tradePartner->setTradeState(TRADE_NONE);
- tradePartner->tradeItem = NULL;
- tradePartner->tradePartner = NULL;
- player->sendTradeClose();
- tradePartner->sendTradeClose();
- return success;
- }
- std::string Game::getTradeErrorDescription(ReturnValue ret, Item* item)
- {
- if(!item)
- return std::string();
- std::stringstream ss;
- if(ret == RET_NOTENOUGHCAPACITY)
- {
- ss << "You do not have enough capacity to carry";
- if(item->isStackable() && item->getItemCount() > 1)
- ss << " these objects.";
- else
- ss << " this object." ;
- ss << std::endl << " " << item->getWeightDescription();
- }
- else if(ret == RET_NOTENOUGHROOM || ret == RET_CONTAINERNOTENOUGHROOM)
- {
- ss << "You do not have enough room to carry";
- if(item->isStackable() && item->getItemCount() > 1)
- ss << " these objects.";
- else
- ss << " this object.";
- }
- else
- ss << "Trade could not be completed.";
- return ss.str().c_str();
- }
- bool Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int32_t index)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Player* tradePartner = player->tradePartner;
- if(!tradePartner)
- return false;
- Item* tradeItem = NULL;
- if(lookAtCounterOffer)
- tradeItem = tradePartner->getTradeItem();
- else
- tradeItem = player->getTradeItem();
- if(!tradeItem)
- return false;
- std::stringstream ss;
- ss << "You see ";
- int32_t lookDistance = std::max(std::abs(player->getPosition().x - tradeItem->getPosition().x),
- std::abs(player->getPosition().y - tradeItem->getPosition().y));
- if(!index)
- {
- ss << tradeItem->getDescription(lookDistance);
- if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
- {
- ss << std::endl << "ItemID: [" << tradeItem->getID() << "]";
- if(tradeItem->getActionId() > 0)
- ss << ", ActionID: [" << tradeItem->getActionId() << "]";
- if(tradeItem->getUniqueId() > 0)
- ss << ", UniqueID: [" << tradeItem->getUniqueId() << "]";
- ss << ".";
- const ItemType& it = Item::items[tradeItem->getID()];
- if(it.transformEquipTo)
- ss << std::endl << "TransformTo (onEquip): [" << it.transformEquipTo << "]";
- else if(it.transformDeEquipTo)
- ss << std::endl << "TransformTo (onDeEquip): [" << it.transformDeEquipTo << "]";
- else if(it.decayTo != -1)
- ss << std::endl << "DecayTo: [" << it.decayTo << "]";
- }
- player->sendTextMessage(MSG_INFO_DESCR, ss.str());
- return false;
- }
- Container* tradeContainer = tradeItem->getContainer();
- if(!tradeContainer || index > (int32_t)tradeContainer->getItemHoldingCount())
- return false;
- std::list<const Container*> listContainer;
- listContainer.push_back(tradeContainer);
- ItemList::const_iterator it;
- Container* tmpContainer = NULL;
- while(listContainer.size() > 0)
- {
- const Container* container = listContainer.front();
- listContainer.pop_front();
- for(it = container->getItems(); it != container->getEnd(); ++it)
- {
- if((tmpContainer = (*it)->getContainer()))
- listContainer.push_back(tmpContainer);
- --index;
- if(index != 0)
- continue;
- ss << (*it)->getDescription(lookDistance);
- if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
- {
- ss << std::endl << "ItemID: [" << (*it)->getID() << "]";
- if((*it)->getActionId() > 0)
- ss << ", ActionID: [" << (*it)->getActionId() << "]";
- if((*it)->getUniqueId() > 0)
- ss << ", UniqueID: [" << (*it)->getUniqueId() << "]";
- ss << ".";
- const ItemType& iit = Item::items[(*it)->getID()];
- if(iit.transformEquipTo)
- ss << std::endl << "TransformTo: [" << iit.transformEquipTo << "] (onEquip).";
- else if(iit.transformDeEquipTo)
- ss << std::endl << "TransformTo: [" << iit.transformDeEquipTo << "] (onDeEquip).";
- else if(iit.decayTo != -1)
- ss << std::endl << "DecayTo: [" << iit.decayTo << "].";
- }
- player->sendTextMessage(MSG_INFO_DESCR, ss.str());
- return true;
- }
- }
- return false;
- }
- bool Game::playerCloseTrade(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- return internalCloseTrade(player);
- }
- bool Game::internalCloseTrade(Player* player)
- {
- Player* tradePartner = player->tradePartner;
- if((tradePartner && tradePartner->getTradeState() == TRADE_TRANSFER) || player->getTradeState() == TRADE_TRANSFER)
- {
- std::clog << "[Warning - Game::internalCloseTrade] TradeState == TRADE_TRANSFER, " <<
- player->getName() << " " << player->getTradeState() << ", " <<
- tradePartner->getName() << " " << tradePartner->getTradeState() << std::endl;
- return true;
- }
- std::vector<Item*>::iterator it;
- if(player->getTradeItem())
- {
- std::map<Item*, uint32_t>::iterator it = tradeItems.find(player->getTradeItem());
- if(it != tradeItems.end())
- {
- freeThing(it->first);
- tradeItems.erase(it);
- }
- player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player, NULL);
- player->tradeItem = NULL;
- }
- player->setTradeState(TRADE_NONE);
- player->tradePartner = NULL;
- player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
- player->sendTradeClose();
- if(tradePartner)
- {
- if(tradePartner->getTradeItem())
- {
- std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradePartner->getTradeItem());
- if(it != tradeItems.end())
- {
- freeThing(it->first);
- tradeItems.erase(it);
- }
- tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner, NULL);
- tradePartner->tradeItem = NULL;
- }
- tradePartner->setTradeState(TRADE_NONE);
- tradePartner->tradePartner = NULL;
- tradePartner->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
- tradePartner->sendTradeClose();
- }
- return true;
- }
- bool Game::playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
- bool ignoreCap/* = false*/, bool inBackpacks/* = false*/)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- int32_t onBuy, onSell;
- Npc* merchant = player->getShopOwner(onBuy, onSell);
- if(!merchant)
- return false;
- const ItemType& it = Item::items.getItemIdByClientId(spriteId);
- if(!it.id)
- return false;
- uint8_t subType = count;
- if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
- subType = reverseFluidMap[count];
- if(!player->canShopItem(it.id, subType, SHOPEVENT_BUY))
- return false;
- merchant->onPlayerTrade(player, SHOPEVENT_BUY, onBuy, it.id, subType, amount, ignoreCap, inBackpacks);
- return true;
- }
- bool Game::playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- int32_t onBuy, onSell;
- Npc* merchant = player->getShopOwner(onBuy, onSell);
- if(!merchant)
- return false;
- const ItemType& it = Item::items.getItemIdByClientId(spriteId);
- if(!it.id)
- return false;
- uint8_t subType = count;
- if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
- subType = reverseFluidMap[count];
- if(!player->canShopItem(it.id, subType, SHOPEVENT_SELL))
- return false;
- merchant->onPlayerTrade(player, SHOPEVENT_SELL, onSell, it.id, subType, amount);
- return true;
- }
- bool Game::playerCloseShop(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(player == NULL || player->isRemoved())
- return false;
- player->closeShopWindow();
- return true;
- }
- bool Game::playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count)
- {
- Player* player = getPlayerByID(playerId);
- if(player == NULL || player->isRemoved())
- return false;
- const ItemType& it = Item::items.getItemIdByClientId(spriteId);
- if(it.id == 0)
- return false;
- int32_t subType = count;
- if(it.isFluidContainer())
- {
- if(subType == 3) // FIXME: hack
- subType = 11;
- else if(count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
- subType = reverseFluidMap[count];
- }
- std::stringstream ss;
- ss << "You see " << Item::getDescription(it, 1, NULL, subType);
- if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
- ss << std::endl << "ItemID: [" << it.id << "].";
- player->sendTextMessage(MSG_INFO_DESCR, ss.str());
- return true;
- }
- bool Game::playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, int16_t stackpos)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 7))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionlook = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 300, 0, false, 7))
- player->addCondition(conditionlook);
- Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_LOOK);
- if(!thing)
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Position thingPos = pos;
- if(pos.x == 0xFFFF)
- thingPos = thing->getPosition();
- if(!player->canSee(thingPos))
- {
- player->sendCancelMessage(RET_NOTPOSSIBLE);
- return false;
- }
- Position playerPos = player->getPosition();
- int32_t lookDistance = -1;
- if(thing != player)
- {
- lookDistance = std::max(std::abs(playerPos.x - thingPos.x), std::abs(playerPos.y - thingPos.y));
- if(playerPos.z != thingPos.z)
- lookDistance = lookDistance + 9 + 6;
- }
- bool deny = false;
- CreatureEventList lookEvents = player->getCreatureEvents(CREATURE_EVENT_LOOK);
- for(CreatureEventList::iterator it = lookEvents.begin(); it != lookEvents.end(); ++it)
- {
- if(!(*it)->executeLook(player, thing, thingPos, stackpos, lookDistance))
- deny = true;
- }
- if(deny)
- return false;
- std::stringstream ss;
- ss << "You see " << thing->getDescription(lookDistance);
- if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
- {
- if(Item* item = thing->getItem())
- {
- ss << std::endl << "ItemID: [" << item->getID() << "]";
- if(item->getActionId() > 0)
- ss << ", ActionID: [" << item->getActionId() << "]";
- if(item->getUniqueId() > 0)
- ss << ", UniqueID: [" << item->getUniqueId() << "]";
- ss << ".";
- const ItemType& it = Item::items[item->getID()];
- if(it.transformEquipTo)
- ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
- else if(it.transformDeEquipTo)
- ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
- else if(it.decayTo != -1)
- ss << std::endl << "DecayTo: [" << it.decayTo << "].";
- }
- }
- if(player->hasCustomFlag(PlayerCustomFlag_CanSeeCreatureDetails))
- {
- if(const Creature* creature = thing->getCreature())
- {
- ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]";
- if(creature->getMaxMana() > 0)
- ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]";
- ss << ".";
- if(const Player* destPlayer = creature->getPlayer())
- {
- ss << std::endl << "IP: " << convertIPAddress(destPlayer->getIP()) << ", Client: " << destPlayer->getClientVersion() << ".";
- if(destPlayer->isGhost())
- ss << std::endl << "* Ghost mode *";
- }
- }
- }
- if(player->hasCustomFlag(PlayerCustomFlag_CanSeePosition))
- ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.z << "].";
- player->sendTextMessage(MSG_INFO_DESCR, ss.str());
- return true;
- }
- bool Game::playerQuests(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->sendQuests();
- return true;
- }
- bool Game::playerQuestInfo(uint32_t playerId, uint16_t questId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Quest* quest = Quests::getInstance()->getQuestById(questId);
- if(!quest)
- return false;
- player->sendQuestInfo(quest);
- return true;
- }
- bool Game::playerCancelAttackAndFollow(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- playerSetAttackedCreature(playerId, 0);
- playerFollowCreature(playerId, 0);
- player->stopWalk();
- return true;
- }
- bool Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->getAttackedCreature() && !creatureId)
- {
- player->setAttackedCreature(NULL);
- player->sendCancelTarget();
- return true;
- }
- Creature* attackCreature = getCreatureByID(creatureId);
- if(!attackCreature)
- {
- player->setAttackedCreature(NULL);
- player->sendCancelTarget();
- return false;
- }
- ReturnValue ret = Combat::canTargetCreature(player, attackCreature);
- if(ret != RET_NOERROR)
- {
- player->sendCancelMessage(ret);
- player->sendCancelTarget();
- player->setAttackedCreature(NULL);
- return false;
- }
- player->setAttackedCreature(attackCreature);
- Dispatcher::getInstance().addTask(createTask(boost::bind(
- &Game::updateCreatureWalk, this, player->getID())));
- return true;
- }
- bool Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Creature* followCreature = NULL;
- if(creatureId)
- followCreature = getCreatureByID(creatureId);
- player->setAttackedCreature(NULL);
- Dispatcher::getInstance().addTask(createTask(boost::bind(
- &Game::updateCreatureWalk, this, player->getID())));
- return player->setFollowCreature(followCreature);
- }
- bool Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- player->setFightMode(fightMode);
- player->setChaseMode(chaseMode);
- player->setSecureMode(secureMode);
- return true;
- }
- bool Game::playerRequestAddVip(uint32_t playerId, const std::string& vipName)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- uint32_t guid;
- bool specialVip;
- std::string name = vipName;
- if(!IOLoginData::getInstance()->getGuidByNameEx(guid, specialVip, name))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "A player with that name does not exist.");
- return false;
- }
- if(specialVip && !player->hasFlag(PlayerFlag_SpecialVIP))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You cannot add this player.");
- return false;
- }
- if(player->hasCondition(CONDITION_EXHAUST, 1))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "Please wait few seconds before adding new player to your vip list.");
- return false;
- }
- bool online = false;
- if(Player* target = getPlayerByName(name))
- online = player->canSeeCreature(target);
- if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 3000, 0, false, 1))
- player->addCondition(condition);
- return player->addVIP(guid, name, online);
- }
- bool Game::playerRequestRemoveVip(uint32_t playerId, uint32_t guid)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 1))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "Please wait few seconds before deleting next player from your vip list.");
- return false;
- }
- if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 3000, 0, false, 1))
- player->addCondition(condition);
- player->removeVIP(guid);
- return true;
- }
- bool Game::playerTurn(uint32_t playerId, Direction dir)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(internalCreatureTurn(player, dir))
- {
- player->setIdleTime(0);
- return true;
- }
- if(player->getDirection() != dir || !player->hasCustomFlag(PlayerCustomFlag_CanTurnhop))
- return false;
- Position pos = getNextPosition(dir, player->getPosition());
- Tile* tile = map->getTile(pos);
- if(!tile || !tile->ground)
- return false;
- player->setIdleTime(0);
- ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM);
- if(ret != RET_NOTENOUGHROOM && (ret != RET_NOTPOSSIBLE || player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
- && (ret != RET_PLAYERISNOTINVITED || player->hasFlag(PlayerFlag_CanEditHouses)))
- return internalTeleport(player, pos, false, FLAG_NOLIMIT, false);
- player->sendCancelMessage(ret);
- return false;
- }
- bool Game::playerRequestOutfit(uint32_t playerId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 4))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionoutfit = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 300, 0, false, 4))
- player->addCondition(conditionoutfit);
- player->sendOutfitWindow();
- return true;
- }
- bool Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 4))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionoutfit = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, 4))
- player->addCondition(conditionoutfit);
- if(!player->changeOutfit(outfit, true))
- return false;
- player->setIdleTime(0);
- if(!player->hasCondition(CONDITION_OUTFIT, -1))
- internalCreatureChangeOutfit(player, outfit);
- return true;
- }
- bool Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type, const std::string& receiver, const std::string& text)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- int32_t muted = 0;
- bool mute = player->isMuted(channelId, type, muted);
- if(muted && mute)
- {
- if(muted > 0)
- {
- char buffer[75];
- sprintf(buffer, "You are still muted for %d seconds.", muted);
- player->sendTextMessage(MSG_STATUS_SMALL, buffer);
- }
- else
- player->sendTextMessage(MSG_STATUS_SMALL, "You are muted permanently.");
- return false;
- }
- if(player->isAccountManager())
- {
- if(mute)
- player->removeMessageBuffer();
- return internalCreatureSay(player, SPEAK_SAY, text, false);
- }
- if(g_talkActions->onPlayerSay(player, type == SPEAK_SAY ? (unsigned)CHANNEL_DEFAULT : channelId, text, false))
- return true;
- ReturnValue ret = RET_NOERROR;
- if(!muted)
- {
- ret = g_spells->onPlayerSay(player, text);
- if(ret == RET_NOERROR || (ret == RET_NEEDEXCHANGE && !g_config.getBool(ConfigManager::BUFFER_SPELL_FAILURE)))
- return true;
- }
- if(mute)
- player->removeMessageBuffer();
- if(ret == RET_NEEDEXCHANGE)
- return true;
- switch(type)
- {
- case SPEAK_SAY:
- return internalCreatureSay(player, SPEAK_SAY, text, false);
- case SPEAK_WHISPER:
- return playerWhisper(player, text);
- case SPEAK_YELL:
- return playerYell(player, text);
- case SPEAK_PRIVATE:
- case SPEAK_PRIVATE_RED:
- case SPEAK_RVR_ANSWER:
- return playerSpeakTo(player, type, receiver, text);
- case SPEAK_CHANNEL_O:
- case SPEAK_CHANNEL_Y:
- case SPEAK_CHANNEL_RN:
- case SPEAK_CHANNEL_RA:
- case SPEAK_CHANNEL_W:
- {
- if(playerTalkToChannel(player, type, text, channelId))
- return true;
- return playerSay(playerId, 0, SPEAK_SAY, receiver, text);
- }
- case SPEAK_PRIVATE_PN:
- return playerSpeakToNpc(player, text);
- case SPEAK_BROADCAST:
- return playerBroadcastMessage(player, SPEAK_BROADCAST, text);
- case SPEAK_RVR_CHANNEL:
- return playerReportRuleViolation(player, text);
- case SPEAK_RVR_CONTINUE:
- return playerContinueReport(player, text);
- default:
- break;
- }
- return false;
- }
- bool Game::playerWhisper(Player* player, const std::string& text)
- {
- SpectatorVec list;
- SpectatorVec::const_iterator it;
- getSpectators(list, player->getPosition(), false, false, 1, 1);
- //send to client
- Player* tmpPlayer = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureSay(player, SPEAK_WHISPER, text);
- }
- //event method
- for(it = list.begin(); it != list.end(); ++it)
- (*it)->onCreatureSay(player, SPEAK_WHISPER, text);
- return true;
- }
- bool Game::playerYell(Player* player, const std::string& text)
- {
- if(player->getLevel() <= 1 && !player->hasFlag(PlayerFlag_CannotBeMuted))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You may not yell as long as you are on level 1.");
- return true;
- }
- if(player->hasCondition(CONDITION_MUTED, 1))
- {
- player->sendCancelMessage(RET_YOUAREEXHAUSTED);
- return true;
- }
- if(!player->hasFlag(PlayerFlag_CannotBeMuted))
- {
- if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_MUTED, 30000, 0, false, 1))
- player->addCondition(condition);
- }
- internalCreatureSay(player, SPEAK_YELL, asUpperCaseString(text), false);
- return true;
- }
- bool Game::playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver,
- const std::string& text)
- {
- Player* toPlayer = getPlayerByName(receiver);
- if(!toPlayer || toPlayer->isRemoved())
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
- return false;
- }
- bool canSee = player->canSeeCreature(toPlayer);
- if(toPlayer->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_IGNORE)
- && !player->hasFlag(PlayerFlag_CannotBeMuted))
- {
- char buffer[70];
- if(!canSee)
- sprintf(buffer, "A player with this name is not online.");
- else
- sprintf(buffer, "Sorry, %s is currently ignoring private messages.", toPlayer->getName().c_str());
- player->sendTextMessage(MSG_STATUS_SMALL, buffer);
- return false;
- }
- if(type == SPEAK_PRIVATE_RED && !player->hasFlag(PlayerFlag_CanTalkRedPrivate))
- type = SPEAK_PRIVATE;
- toPlayer->sendCreatureSay(player, type, text);
- toPlayer->onCreatureSay(player, type, text);
- if(!canSee)
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
- return false;
- }
- char buffer[80];
- sprintf(buffer, "Message sent to %s.", toPlayer->getName().c_str());
- player->sendTextMessage(MSG_STATUS_SMALL, buffer);
- return true;
- }
- bool Game::playerTalkToChannel(Player* player, SpeakClasses type, const std::string& text, uint16_t channelId)
- {
- if(player->hasCondition(CONDITION_EXHAUST, 6))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionchannel = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 300, 0, false, 6))
- player->addCondition(conditionchannel);
- switch(type)
- {
- case SPEAK_CHANNEL_Y:
- {
- if(channelId == CHANNEL_HELP && player->hasFlag(PlayerFlag_TalkOrangeHelpChannel))
- type = SPEAK_CHANNEL_O;
- break;
- }
- case SPEAK_CHANNEL_O:
- {
- if(channelId != CHANNEL_HELP || !player->hasFlag(PlayerFlag_TalkOrangeHelpChannel))
- type = SPEAK_CHANNEL_Y;
- break;
- }
- case SPEAK_CHANNEL_RN:
- {
- if(!player->hasFlag(PlayerFlag_CanTalkRedChannel))
- type = SPEAK_CHANNEL_Y;
- break;
- }
- case SPEAK_CHANNEL_RA:
- {
- if(!player->hasFlag(PlayerFlag_CanTalkRedChannelAnonymous))
- type = SPEAK_CHANNEL_Y;
- break;
- }
- default:
- break;
- }
- if(text.length() > 250)
- player->sendCancel("Chat message is too long");
- else
- return g_chat.talkToChannel(player, type, text, channelId);
- return false;
- }
- bool Game::playerSpeakToNpc(Player* player, const std::string& text)
- {
- SpectatorVec list;
- SpectatorVec::iterator it;
- getSpectators(list, player->getPosition());
- if(player->hasCondition(CONDITION_EXHAUST, 2))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionnpc = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 300, 0, false, 2))
- player->addCondition(conditionnpc);
- //send to npcs only
- Npc* tmpNpc = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((tmpNpc = (*it)->getNpc()))
- (*it)->onCreatureSay(player, SPEAK_PRIVATE_PN, text);
- }
- return true;
- }
- bool Game::playerReportRuleViolation(Player* player, const std::string& text)
- {
- //Do not allow reports on multiclones worlds since reports are name-based
- if(g_config.getNumber(ConfigManager::ALLOW_CLONES))
- {
- player->sendTextMessage(MSG_INFO_DESCR, "Rule violation reports are disabled.");
- return false;
- }
- cancelRuleViolation(player);
- boost::shared_ptr<RuleViolation> rvr(new RuleViolation(player, text, time(NULL)));
- ruleViolations[player->getID()] = rvr;
- ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR);
- if(!channel)
- return false;
- for(UsersMap::const_iterator it = channel->getUsers().begin(); it != channel->getUsers().end(); ++it)
- it->second->sendToChannel(player, SPEAK_RVR_CHANNEL, text, CHANNEL_RVR, rvr->time);
- return true;
- }
- bool Game::playerContinueReport(Player* player, const std::string& text)
- {
- RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
- if(it == ruleViolations.end())
- return false;
- RuleViolation& rvr = *it->second;
- Player* toPlayer = rvr.gamemaster;
- if(!toPlayer)
- return false;
- toPlayer->sendCreatureSay(player, SPEAK_RVR_CONTINUE, text);
- player->sendTextMessage(MSG_STATUS_SMALL, "Message sent to Gamemaster.");
- return true;
- }
- bool Game::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/,
- int32_t rangex/* = Map::maxClientViewportX*/, int32_t rangey/* = Map::maxClientViewportY*/)
- {
- return map->canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey);
- }
- bool Game::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck)
- {
- return map->isSightClear(fromPos, toPos, floorCheck);
- }
- bool Game::internalCreatureTurn(Creature* creature, Direction dir)
- {
- bool deny = false;
- CreatureEventList directionEvents = creature->getCreatureEvents(CREATURE_EVENT_DIRECTION);
- for(CreatureEventList::iterator it = directionEvents.begin(); it != directionEvents.end(); ++it)
- {
- if(!(*it)->executeDirection(creature, creature->getDirection(), dir) && !deny)
- deny = true;
- }
- if(deny || creature->getDirection() == dir)
- return false;
- creature->setDirection(dir);
- const SpectatorVec& list = getSpectators(creature->getPosition());
- SpectatorVec::const_iterator it;
- //send to client
- Player* tmpPlayer = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureTurn(creature);
- }
- //event method
- for(it = list.begin(); it != list.end(); ++it)
- (*it)->onCreatureTurn(creature);
- return true;
- }
- bool Game::internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
- bool ghostMode, SpectatorVec* spectators/* = NULL*/, Position* pos/* = NULL*/)
- {
- Player* player = creature->getPlayer();
- if(player && player->isAccountManager())
- {
- player->manageAccount(text);
- return true;
- }
- Position destPos = creature->getPosition();
- if(pos)
- destPos = (*pos);
- SpectatorVec list;
- SpectatorVec::const_iterator it;
- if(!spectators || !spectators->size())
- {
- // This somewhat complex construct ensures that the cached SpectatorVec
- // is used if available and if it can be used, else a local vector is
- // used (hopefully the compiler will optimize away the construction of
- // the temporary when it's not used).
- if(type != SPEAK_YELL && type != SPEAK_MONSTER_YELL)
- getSpectators(list, destPos, false, false,
- Map::maxClientViewportX, Map::maxClientViewportX,
- Map::maxClientViewportY, Map::maxClientViewportY);
- else
- getSpectators(list, destPos, false, true, 18, 18, 14, 14);
- }
- else
- list = (*spectators);
- //send to client
- Player* tmpPlayer = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if(!(tmpPlayer = (*it)->getPlayer()))
- continue;
- if(!ghostMode || tmpPlayer->canSeeCreature(creature))
- tmpPlayer->sendCreatureSay(creature, type, text, &destPos);
- }
- //event method
- for(it = list.begin(); it != list.end(); ++it)
- (*it)->onCreatureSay(creature, type, text, &destPos);
- return true;
- }
- bool Game::getPathTo(const Creature* creature, const Position& destPos,
- std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/)
- {
- return map->getPathTo(creature, destPos, listDir, maxSearchDist);
- }
- bool Game::getPathToEx(const Creature* creature, const Position& targetPos,
- std::list<Direction>& dirList, const FindPathParams& fpp)
- {
- return map->getPathMatching(creature, dirList, FrozenPathingConditionCall(targetPos), fpp);
- }
- bool Game::getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList,
- uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch/* = true*/,
- bool clearSight/* = true*/, int32_t maxSearchDist/* = -1*/)
- {
- FindPathParams fpp;
- fpp.fullPathSearch = fullPathSearch;
- fpp.maxSearchDist = maxSearchDist;
- fpp.clearSight = clearSight;
- fpp.minTargetDist = minTargetDist;
- fpp.maxTargetDist = maxTargetDist;
- return getPathToEx(creature, targetPos, dirList, fpp);
- }
- bool Game::steerCreature(Creature* creature, const Position& position)
- {
- FindPathParams fpp;
- fpp.fullPathSearch = true;
- fpp.maxSearchDist = -1;
- fpp.clearSight = true;
- fpp.minTargetDist = 0;
- fpp.maxTargetDist = 1;
- std::list<Direction> dirList;
- if(!getPathToEx(creature, position, dirList, fpp))
- return false;
- if(!Position::areInRange<1,1,0>(creature->getPosition(), position))
- {
- SchedulerTask* task = createSchedulerTask(std::max((int32_t)SCHEDULER_MINTICKS,
- creature->getStepDuration()), boost::bind(&Game::steerCreature, this, creature, position));
- if(Player* player = creature->getPlayer())
- player->setNextWalkActionTask(task);
- }
- creature->startAutoWalk(dirList);
- return true;
- }
- void Game::checkCreatureWalk(uint32_t creatureId)
- {
- Creature* creature = getCreatureByID(creatureId);
- if(!creature || creature->getHealth() < 1)
- return;
- creature->onWalk();
- cleanup();
- }
- void Game::updateCreatureWalk(uint32_t creatureId)
- {
- Creature* creature = getCreatureByID(creatureId);
- if(creature && creature->getHealth() > 0)
- creature->goToFollowCreature();
- }
- void Game::checkCreatureAttack(uint32_t creatureId)
- {
- Creature* creature = getCreatureByID(creatureId);
- if(creature && creature->getHealth() > 0)
- creature->onAttacking(0);
- }
- void Game::addCreatureCheck(Creature* creature)
- {
- if(creature->isRemoved())
- return;
- creature->checked = true;
- if(creature->checkVector >= 0) //already in a vector, or about to be added
- return;
- toAddCheckCreatureVector.push_back(creature);
- creature->checkVector = random_range(0, EVENT_CREATURECOUNT - 1);
- creature->addRef();
- }
- void Game::removeCreatureCheck(Creature* creature)
- {
- if(creature->checkVector == -1) //not in any vector
- return;
- creature->checked = false;
- }
- void Game::checkCreatures()
- {
- checkCreatureEvent = Scheduler::getInstance().addEvent(createSchedulerTask(
- EVENT_CHECK_CREATURE_INTERVAL, boost::bind(&Game::checkCreatures, this)));
- checkCreatureLastIndex++;
- if(checkCreatureLastIndex == EVENT_CREATURECOUNT)
- checkCreatureLastIndex = 0;
- std::vector<Creature*>::iterator it;
- for(it = toAddCheckCreatureVector.begin(); it != toAddCheckCreatureVector.end(); ++it)
- checkCreatureVectors[(*it)->checkVector].push_back(*it);
- toAddCheckCreatureVector.clear();
- std::vector<Creature*>& checkCreatureVector = checkCreatureVectors[checkCreatureLastIndex];
- for(it = checkCreatureVector.begin(); it != checkCreatureVector.end();)
- {
- if((*it)->checked)
- {
- if((*it)->getHealth() > 0 || !(*it)->onDeath())
- (*it)->onThink(EVENT_CREATURE_THINK_INTERVAL);
- ++it;
- }
- else
- {
- (*it)->checkVector = -1;
- freeThing(*it);
- it = checkCreatureVector.erase(it);
- }
- }
- cleanup();
- }
- void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
- {
- if(!creature)
- return;
- int32_t varSpeed = creature->getSpeed() - creature->getBaseSpeed();
- varSpeed += varSpeedDelta;
- creature->setSpeed(varSpeed);
- const SpectatorVec& list = getSpectators(creature->getPosition());
- SpectatorVec::const_iterator it;
- //send to client
- Player* tmpPlayer = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((*it) && (tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendChangeSpeed(creature, creature->getStepSpeed());
- }
- }
- void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit, bool forced/* = false*/)
- {
- if(!forced)
- {
- bool deny = false;
- CreatureEventList outfitEvents = creature->getCreatureEvents(CREATURE_EVENT_OUTFIT);
- for(CreatureEventList::iterator it = outfitEvents.begin(); it != outfitEvents.end(); ++it)
- {
- if(!(*it)->executeOutfit(creature, creature->getCurrentOutfit(), outfit) && !deny)
- deny = true;
- }
- if(deny || creature->getCurrentOutfit() == outfit)
- return;
- }
- creature->setCurrentOutfit(outfit);
- const SpectatorVec& list = getSpectators(creature->getPosition());
- SpectatorVec::const_iterator it;
- //send to client
- Player* tmpPlayer = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((*it) && (tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureChangeOutfit(creature, outfit);
- }
- //event method
- for(it = list.begin(); it != list.end(); ++it)
- if((*it)) (*it)->onCreatureChangeOutfit(creature, outfit);
- }
- void Game::internalCreatureChangeVisible(Creature* creature, Visible_t visible)
- {
- const SpectatorVec& list = getSpectators(creature->getPosition());
- SpectatorVec::const_iterator it;
- //send to client
- Player* tmpPlayer = NULL;
- for(it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureChangeVisible(creature, visible);
- }
- //event method
- for(it = list.begin(); it != list.end(); ++it)
- (*it)->onCreatureChangeVisible(creature, visible);
- }
- void Game::changeLight(const Creature* creature)
- {
- const SpectatorVec& list = getSpectators(creature->getPosition());
- //send to client
- Player* tmpPlayer = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()) && !tmpPlayer->hasCustomFlag(PlayerCustomFlag_HasFullLight))
- tmpPlayer->sendCreatureLight(creature);
- }
- }
- bool Game::combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target,
- int32_t& healthChange, bool checkDefense, bool checkArmor, bool field/* = false*/)
- {
- if(healthChange > 0)
- return false;
- const Position& targetPos = target->getPosition();
- const SpectatorVec& list = getSpectators(targetPos);
- if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
- {
- addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF, target->isGhost());
- return true;
- }
- int32_t damage = -healthChange;
- BlockType_t blockType = target->blockHit(attacker, combatType,
- damage, checkDefense, checkArmor, !field, field);
- healthChange = -damage;
- if(blockType == BLOCK_DEFENSE)
- {
- addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
- return true;
- }
- else if(blockType == BLOCK_ARMOR)
- {
- addMagicEffect(list, targetPos, MAGIC_EFFECT_BLOCKHIT);
- return true;
- }
- else if(blockType != BLOCK_IMMUNITY)
- return false;
- MagicEffect_t effect = MAGIC_EFFECT_NONE;
- switch(combatType)
- {
- case COMBAT_UNDEFINEDDAMAGE:
- break;
- case COMBAT_ENERGYDAMAGE:
- case COMBAT_FIREDAMAGE:
- case COMBAT_PHYSICALDAMAGE:
- case COMBAT_ICEDAMAGE:
- case COMBAT_DEATHDAMAGE:
- case COMBAT_EARTHDAMAGE:
- case COMBAT_HOLYDAMAGE:
- {
- effect = MAGIC_EFFECT_BLOCKHIT;
- break;
- }
- default:
- {
- effect = MAGIC_EFFECT_POFF;
- break;
- }
- }
- addMagicEffect(list, targetPos, effect);
- return true;
- }
- bool Game::combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange,
- MagicEffect_t hitEffect/* = MAGIC_EFFECT_UNKNOWN*/, Color_t hitColor/* = COLOR_UNKNOWN*/, bool force/* = false*/)
- {
- const Position& targetPos = target->getPosition();
- if(healthChange > 0)
- {
- if(!force && target->getHealth() <= 0)
- return false;
- bool deny = false;
- CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
- for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
- {
- if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHGAIN, combatType, healthChange))
- deny = true;
- }
- if(deny)
- return false;
- target->gainHealth(attacker, healthChange);
- if(g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE) && !target->isGhost() &&
- (g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE_MONSTER) || !target->getMonster()))
- {
- char buffer[20];
- sprintf(buffer, "+%d", healthChange);
- const SpectatorVec& list = getSpectators(targetPos);
- if(combatType != COMBAT_HEALING)
- addMagicEffect(list, targetPos, MAGIC_EFFECT_WRAPS_BLUE);
- addAnimatedText(list, targetPos, COLOR_MAYABLUE, buffer);
- }
- }
- else
- {
- const SpectatorVec& list = getSpectators(targetPos);
- if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
- {
- addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
- return true;
- }
- int32_t damage = -healthChange;
- if(damage != 0)
- {
- if(target->hasCondition(CONDITION_MANASHIELD) && combatType != COMBAT_UNDEFINEDDAMAGE)
- {
- int32_t manaDamage = std::min(target->getMana(), damage);
- damage = std::max((int32_t)0, damage - manaDamage);
- if(manaDamage != 0)
- {
- bool deny = false;
- CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
- for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
- {
- if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, combatType, manaDamage))
- deny = true;
- }
- if(deny)
- return false;
- target->drainMana(attacker, combatType, manaDamage);
- char buffer[20];
- sprintf(buffer, "%d", manaDamage);
- addMagicEffect(list, targetPos, MAGIC_EFFECT_LOSE_ENERGY);
- addAnimatedText(list, targetPos, COLOR_BLUE, buffer);
- }
- }
- damage = std::min(target->getHealth(), damage);
- if(damage > 0)
- {
- bool deny = false;
- CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
- for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
- {
- if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHLOSS, combatType, damage))
- deny = true;
- }
- if(deny)
- return false;
- target->drainHealth(attacker, combatType, damage);
- addCreatureHealth(list, target);
- Color_t textColor = COLOR_NONE;
- MagicEffect_t magicEffect = MAGIC_EFFECT_NONE;
- switch(combatType)
- {
- case COMBAT_PHYSICALDAMAGE:
- {
- Item* splash = NULL;
- switch(target->getRace())
- {
- case RACE_VENOM:
- textColor = COLOR_LIGHTGREEN;
- magicEffect = MAGIC_EFFECT_POISON;
- splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_GREEN);
- break;
- case RACE_BLOOD:
- textColor = COLOR_RED;
- magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
- splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_BLOOD);
- break;
- case RACE_UNDEAD:
- textColor = COLOR_GREY;
- magicEffect = MAGIC_EFFECT_HIT_AREA;
- break;
- case RACE_FIRE:
- textColor = COLOR_ORANGE;
- magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
- break;
- case RACE_ENERGY:
- textColor = COLOR_LIGHTBLUE;
- magicEffect = MAGIC_EFFECT_PURPLEENERGY;
- break;
- default:
- break;
- }
- if(splash)
- {
- internalAddItem(NULL, target->getTile(), splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
- startDecay(splash);
- }
- break;
- }
- case COMBAT_ENERGYDAMAGE:
- {
- textColor = COLOR_LIGHTBLUE;
- magicEffect = MAGIC_EFFECT_ENERGY_DAMAGE;
- break;
- }
- case COMBAT_EARTHDAMAGE:
- {
- textColor = COLOR_LIGHTGREEN;
- magicEffect = MAGIC_EFFECT_POISON_RINGS;
- break;
- }
- case COMBAT_DROWNDAMAGE:
- {
- textColor = COLOR_LIGHTBLUE;
- magicEffect = MAGIC_EFFECT_LOSE_ENERGY;
- break;
- }
- case COMBAT_FIREDAMAGE:
- {
- textColor = COLOR_ORANGE;
- magicEffect = MAGIC_EFFECT_HITBY_FIRE;
- break;
- }
- case COMBAT_ICEDAMAGE:
- {
- textColor = COLOR_TEAL;
- magicEffect = MAGIC_EFFECT_ICEATTACK;
- break;
- }
- case COMBAT_HOLYDAMAGE:
- {
- textColor = COLOR_YELLOW;
- magicEffect = MAGIC_EFFECT_HOLYDAMAGE;
- break;
- }
- case COMBAT_DEATHDAMAGE:
- {
- textColor = COLOR_DARKRED;
- magicEffect = MAGIC_EFFECT_SMALLCLOUDS;
- break;
- }
- case COMBAT_LIFEDRAIN:
- {
- textColor = COLOR_RED;
- magicEffect = MAGIC_EFFECT_WRAPS_RED;
- break;
- }
- default:
- break;
- }
- if(hitEffect != MAGIC_EFFECT_UNKNOWN)
- magicEffect = hitEffect;
- if(hitColor != COLOR_UNKNOWN)
- textColor = hitColor;
- if(textColor < COLOR_NONE && magicEffect < MAGIC_EFFECT_NONE)
- {
- char buffer[20];
- sprintf(buffer, "%d", damage);
- addMagicEffect(list, targetPos, magicEffect);
- addAnimatedText(list, targetPos, textColor, buffer);
- }
- }
- }
- }
- return true;
- }
- bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange)
- {
- const Position& targetPos = target->getPosition();
- if(manaChange > 0)
- {
- bool deny = false;
- CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
- for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
- {
- if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANAGAIN, COMBAT_HEALING, manaChange))
- deny = true;
- }
- if(deny)
- return false;
- target->changeMana(manaChange);
- if(g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE) && !target->isGhost() &&
- (g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE_MONSTER) || !target->getMonster()))
- {
- char buffer[20];
- sprintf(buffer, "+%d", manaChange);
- const SpectatorVec& list = getSpectators(targetPos);
- addAnimatedText(list, targetPos, COLOR_DARKPURPLE, buffer);
- }
- }
- else
- {
- const SpectatorVec& list = getSpectators(targetPos);
- if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
- {
- addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
- return false;
- }
- int32_t manaLoss = std::min(target->getMana(), -manaChange);
- BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
- if(blockType != BLOCK_NONE)
- {
- addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
- return false;
- }
- if(manaLoss > 0)
- {
- bool deny = false;
- CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
- for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
- {
- if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, COMBAT_UNDEFINEDDAMAGE, manaChange))
- deny = true;
- }
- if(deny)
- return false;
- target->drainMana(attacker, COMBAT_MANADRAIN, manaLoss);
- char buffer[20];
- sprintf(buffer, "%d", manaLoss);
- addAnimatedText(list, targetPos, COLOR_BLUE, buffer);
- }
- }
- return true;
- }
- void Game::addCreatureHealth(const Creature* target)
- {
- const SpectatorVec& list = getSpectators(target->getPosition());
- addCreatureHealth(list, target);
- }
- void Game::addCreatureHealth(const SpectatorVec& list, const Creature* target)
- {
- Player* player = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((player = (*it)->getPlayer()))
- player->sendCreatureHealth(target);
- }
- }
- void Game::addCreatureSquare(const Creature* target, uint8_t squareColor)
- {
- const SpectatorVec& list = getSpectators(target->getPosition());
- addCreatureSquare(list, target, squareColor);
- }
- void Game::addCreatureSquare(const SpectatorVec& list, const Creature* target, uint8_t squareColor)
- {
- Player* player = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((player = (*it)->getPlayer()))
- player->sendCreatureSquare(target, squareColor);
- }
- }
- void Game::addAnimatedText(const Position& pos, uint8_t textColor, const std::string& text)
- {
- const SpectatorVec& list = getSpectators(pos);
- addAnimatedText(list, pos, textColor, text);
- }
- void Game::addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t textColor,
- const std::string& text)
- {
- Player* player = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((player = (*it)->getPlayer()))
- player->sendAnimatedText(pos, textColor, text);
- }
- }
- void Game::addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode/* = false*/)
- {
- if(ghostMode)
- return;
- const SpectatorVec& list = getSpectators(pos);
- addMagicEffect(list, pos, effect);
- }
- void Game::addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect,
- bool ghostMode/* = false*/)
- {
- if(ghostMode)
- return;
- Player* player = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((player = (*it)->getPlayer()))
- player->sendMagicEffect(pos, effect);
- }
- }
- void Game::addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect)
- {
- SpectatorVec list;
- getSpectators(list, fromPos, false);
- getSpectators(list, toPos, true);
- addDistanceEffect(list, fromPos, toPos, effect);
- }
- void Game::addDistanceEffect(const SpectatorVec& list, const Position& fromPos,
- const Position& toPos, uint8_t effect)
- {
- Player* player = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((player = (*it)->getPlayer()))
- player->sendDistanceShoot(fromPos, toPos, effect);
- }
- }
- void Game::startDecay(Item* item)
- {
- if(!item || !item->canDecay() || item->getDecaying() == DECAYING_TRUE)
- return;
- if(item->getDuration() > 0)
- {
- item->addRef();
- item->setDecaying(DECAYING_TRUE);
- toDecayItems.push_back(item);
- }
- else
- internalDecayItem(item);
- }
- void Game::internalDecayItem(Item* item)
- {
- const ItemType& it = Item::items.getItemType(item->getID());
- if(it.decayTo)
- {
- Item* newItem = transformItem(item, it.decayTo);
- startDecay(newItem);
- }
- else
- {
- ReturnValue ret = internalRemoveItem(NULL, item);
- if(ret != RET_NOERROR)
- std::clog << "> DEBUG: internalDecayItem failed, error code: " << (int32_t)ret << ", item id: " << item->getID() << std::endl;
- }
- }
- void Game::checkDecay()
- {
- checkDecayEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
- boost::bind(&Game::checkDecay, this)));
- size_t bucket = (lastBucket + 1) % EVENT_DECAYBUCKETS;
- for(DecayList::iterator it = decayItems[bucket].begin(); it != decayItems[bucket].end();)
- {
- Item* item = *it;
- int32_t decreaseTime = EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS;
- if(item->getDuration() - decreaseTime < 0)
- decreaseTime = item->getDuration();
- item->decreaseDuration(decreaseTime);
- if(!item->canDecay())
- {
- item->setDecaying(DECAYING_FALSE);
- freeThing(item);
- it = decayItems[bucket].erase(it);
- continue;
- }
- int32_t dur = item->getDuration();
- if(dur <= 0)
- {
- it = decayItems[bucket].erase(it);
- internalDecayItem(item);
- freeThing(item);
- }
- else if(dur < EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS)
- {
- it = decayItems[bucket].erase(it);
- size_t newBucket = (bucket + ((dur + EVENT_DECAYINTERVAL / 2) / 1000)) % EVENT_DECAYBUCKETS;
- if(newBucket == bucket)
- {
- internalDecayItem(item);
- freeThing(item);
- }
- else
- decayItems[newBucket].push_back(item);
- }
- else
- ++it;
- }
- lastBucket = bucket;
- cleanup();
- }
- void Game::checkLight()
- {
- checkLightEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
- boost::bind(&Game::checkLight, this)));
- lightHour = lightHour + lightHourDelta;
- if(lightHour > 1440)
- lightHour = lightHour - 1440;
- if(std::abs(lightHour - SUNRISE) < 2 * lightHourDelta)
- lightState = LIGHT_STATE_SUNRISE;
- else if(std::abs(lightHour - SUNSET) < 2 * lightHourDelta)
- lightState = LIGHT_STATE_SUNSET;
- int32_t newLightLevel = lightLevel;
- bool lightChange = false;
- switch(lightState)
- {
- case LIGHT_STATE_SUNRISE:
- {
- newLightLevel += (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
- lightChange = true;
- break;
- }
- case LIGHT_STATE_SUNSET:
- {
- newLightLevel -= (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
- lightChange = true;
- break;
- }
- default:
- break;
- }
- if(newLightLevel <= LIGHT_LEVEL_NIGHT)
- {
- lightLevel = LIGHT_LEVEL_NIGHT;
- lightState = LIGHT_STATE_NIGHT;
- }
- else if(newLightLevel >= LIGHT_LEVEL_DAY)
- {
- lightLevel = LIGHT_LEVEL_DAY;
- lightState = LIGHT_STATE_DAY;
- }
- else
- lightLevel = newLightLevel;
- if(lightChange)
- {
- LightInfo lightInfo;
- getWorldLightInfo(lightInfo);
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- {
- if(!it->second->hasCustomFlag(PlayerCustomFlag_HasFullLight))
- it->second->sendWorldLight(lightInfo);
- }
- }
- }
- void Game::checkWars()
- {
- IOGuild::getInstance()->checkWars();
- checkWarsEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_WARSINTERVAL,
- boost::bind(&Game::checkWars, this)));
- }
- void Game::getWorldLightInfo(LightInfo& lightInfo)
- {
- lightInfo.level = lightLevel;
- lightInfo.color = 0xD7;
- }
- bool Game::cancelRuleViolation(Player* player)
- {
- RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
- if(it == ruleViolations.end())
- return false;
- Player* gamemaster = it->second->gamemaster;
- if(!it->second->isOpen && gamemaster) //Send to the responser
- gamemaster->sendRuleViolationCancel(player->getName());
- else if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
- {
- UsersMap tmpMap = channel->getUsers();
- for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
- tit->second->sendRemoveReport(player->getName());
- }
- //Now erase it
- ruleViolations.erase(it);
- return true;
- }
- bool Game::closeRuleViolation(Player* player)
- {
- RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
- if(it == ruleViolations.end())
- return false;
- ruleViolations.erase(it);
- player->sendLockRuleViolation();
- if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
- {
- UsersMap tmpMap = channel->getUsers();
- for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
- tit->second->sendRemoveReport(player->getName());
- }
- return true;
- }
- void Game::updateCreatureSkull(Creature* creature)
- {
- const SpectatorVec& list = getSpectators(creature->getPosition());
- //send to client
- Player* tmpPlayer = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureSkull(creature);
- }
- }
- void Game::updateCreatureShield(Creature* creature)
- {
- const SpectatorVec& list = getSpectators(creature->getPosition());
- //send to client
- Player* tmpPlayer = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureShield(creature);
- }
- }
- void Game::updateCreatureEmblem(Creature* creature)
- {
- const SpectatorVec& list = getSpectators(creature->getPosition());
- //send to client
- Player* tmpPlayer = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureEmblem(creature);
- }
- }
- void Game::updateCreatureWalkthrough(Creature* creature)
- {
- const SpectatorVec& list = getSpectators(creature->getPosition());
- //send to client
- Player* tmpPlayer = NULL;
- for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
- {
- if((tmpPlayer = (*it)->getPlayer()))
- tmpPlayer->sendCreatureWalkthrough(creature, (*it)->canWalkthrough(creature));
- }
- }
- bool Game::playerInviteToParty(uint32_t playerId, uint32_t invitedId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 5))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionparty = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, 5))
- player->addCondition(conditionparty);
- Player* invitedPlayer = getPlayerByID(invitedId);
- if(!invitedPlayer || invitedPlayer->isRemoved() || invitedPlayer->isInviting(player))
- return false;
- if(invitedPlayer->getParty())
- {
- char buffer[90];
- sprintf(buffer, "%s is already in a party.", invitedPlayer->getName().c_str());
- player->sendTextMessage(MSG_INFO_DESCR, buffer);
- return false;
- }
- Party* party = player->getParty();
- if(!party)
- party = new Party(player);
- else if(party->getLeader() != player)
- return false;
- return party->invitePlayer(invitedPlayer);
- }
- bool Game::playerJoinParty(uint32_t playerId, uint32_t leaderId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 5))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionparty = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, 5))
- player->addCondition(conditionparty);
- Player* leader = getPlayerByID(leaderId);
- if(!leader || leader->isRemoved() || !leader->isInviting(player))
- return false;
- if(!player->getParty())
- return leader->getParty()->join(player);
- player->sendTextMessage(MSG_INFO_DESCR, "You are already in a party.");
- return false;
- }
- bool Game::playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player)
- return false;
- Player* invitedPlayer = getPlayerByID(invitedId);
- if(!invitedPlayer || invitedPlayer->isRemoved() || !player->isInviting(invitedPlayer))
- return false;
- player->getParty()->revokeInvitation(invitedPlayer);
- return true;
- }
- bool Game::playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player)
- return false;
- if(player->hasCondition(CONDITION_EXHAUST, 5))
- {
- player->sendTextMessage(MSG_STATUS_SMALL, "You have to wait a while.");
- return false;
- }
- if(Condition* conditionparty = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, 1000, 0, false, 5))
- player->addCondition(conditionparty);
- Player* newLeader = getPlayerByID(newLeaderId);
- if(!newLeader || newLeader->isRemoved() || !newLeader->getParty() || newLeader->getParty() != player->getParty())
- return false;
- return player->getParty()->passLeadership(newLeader);
- }
- bool Game::playerLeaveParty(uint32_t playerId, bool forced/* = false*/)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved() || !player->getParty() || (player->hasCondition(CONDITION_INFIGHT) && !forced))
- return false;
- return player->getParty()->leave(player);
- }
- bool Game::playerSharePartyExperience(uint32_t playerId, bool activate, uint8_t)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(!player->getParty() || (!player->hasFlag(PlayerFlag_NotGainInFight)
- && player->hasCondition(CONDITION_INFIGHT)))
- return false;
- return player->getParty()->setSharedExperience(player, activate);
- }
- bool Game::playerReportBug(uint32_t playerId, std::string comment)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- if(!player->hasFlag(PlayerFlag_CanReportBugs))
- return false;
- CreatureEventList reportBugEvents = player->getCreatureEvents(CREATURE_EVENT_REPORTBUG);
- for(CreatureEventList::iterator it = reportBugEvents.begin(); it != reportBugEvents.end(); ++it)
- (*it)->executeReportBug(player, comment);
- return true;
- }
- bool Game::playerViolationWindow(uint32_t playerId, std::string name, uint8_t reason, ViolationAction_t action,
- std::string comment, std::string statement, uint32_t statementId, bool ipBanishment)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return false;
- Group* group = player->getGroup();
- if(!group)
- return false;
- std::string::size_type start = comment.find("{"), end = std::string::npos;
- if(start != std::string::npos)
- end = comment.find("}", start + 1);
- time_t length[3] = {0, 0, 0};
- if(end != std::string::npos)
- {
- int32_t i = 0;
- StringVec vec = explodeString(comment.substr(start + 1, end - 1), ",");
- for(StringVec::iterator it = vec.begin(); it != vec.end() && i < 4; ++it, ++i)
- {
- if((*it) == "delete")
- {
- i--;
- action = ACTION_DELETION;
- continue;
- }
- time_t banTime = time(NULL);
- StringVec tec = explodeString((*it), "+");
- for(StringVec::iterator tit = tec.begin(); tit != tec.end(); ++tit)
- {
- std::string tmp = (*tit);
- if(tmp[0] != 's' && tmp[0] != 'm' && tmp[0] != 'h' && tmp[0] != 'd'
- && tmp[0] != 'w' && tmp[0] != 'o' && tmp[0] != 'y')
- continue;
- uint32_t count = 1;
- if(tmp.size() > 1)
- {
- count = atoi(tmp.substr(1).c_str());
- if(!count)
- count = 1;
- }
- if(tmp[0] == 's')
- banTime += count;
- if(tmp[0] == 'm')
- banTime += count * 60;
- if(tmp[0] == 'h')
- banTime += count * 3600;
- if(tmp[0] == 'd')
- banTime += count * 86400;
- if(tmp[0] == 'w')
- banTime += count * 604800;
- if(tmp[0] == 'o')
- banTime += count * 2592000;
- if(tmp[0] == 'y')
- banTime += count * 31536000;
- length[i] = banTime;
- }
- }
- comment = comment.substr(end + 1);
- }
- int16_t nameFlags = group->getNameViolationFlags(), statementFlags = group->getStatementViolationFlags();
- if((ipBanishment && ((nameFlags & IPBAN_FLAG) != IPBAN_FLAG || (statementFlags & IPBAN_FLAG) != IPBAN_FLAG)) ||
- !(nameFlags & (1 << action) || statementFlags & (1 << action)) || reason > group->getViolationReasons())
- {
- player->sendCancel("You do not have authorization for this action.");
- return false;
- }
- uint32_t commentSize = g_config.getNumber(ConfigManager::MAX_VIOLATIONCOMMENT_SIZE);
- if(comment.size() > commentSize)
- {
- char buffer[90];
- sprintf(buffer, "The comment may not exceed limit of %d characters.", commentSize);
- player->sendCancel(buffer);
- return false;
- }
- toLowerCaseString(name);
- Player* target = getPlayerByNameEx(name);
- if(!target || name == "account manager")
- {
- player->sendCancel("A player with this name does not exist.");
- return false;
- }
- if(target->hasFlag(PlayerFlag_CannotBeBanned))
- {
- player->sendCancel("You do not have authorization for this action.");
- return false;
- }
- Account account = IOLoginData::getInstance()->loadAccount(target->getAccount(), true);
- enum KickAction {
- NONE = 1,
- KICK = 2,
- FULL_KICK = 3,
- } kickAction = FULL_KICK;
- switch(action)
- {
- case ACTION_STATEMENT:
- {
- StatementMap::iterator it = g_chat.statementMap.find(statementId);
- if(it == g_chat.statementMap.end())
- {
- player->sendCancel("Statement has been already reported.");
- return false;
- }
- IOBan::getInstance()->addStatement(target->getGUID(), reason, comment,
- player->getGUID(), -1, statement);
- g_chat.statementMap.erase(it);
- kickAction = NONE;
- break;
- }
- case ACTION_NAMEREPORT:
- {
- int64_t banTime = -1;
- PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE);
- if(tmp == PLAYERBAN_BANISHMENT)
- {
- if(!length[0])
- banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
- else
- banTime = length[0];
- }
- if(!IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action,
- comment, player->getGUID(), tmp))
- {
- player->sendCancel("Player has been already reported.");
- return false;
- }
- else if(tmp == PLAYERBAN_BANISHMENT)
- account.warnings++;
- kickAction = (KickAction)tmp;
- break;
- }
- case ACTION_NOTATION:
- case ACTION_BANISHMENT:
- case ACTION_BANREPORT:
- {
- if(action == ACTION_NOTATION)
- {
- if(!IOBan::getInstance()->addNotation(account.number, reason,
- comment, player->getGUID(), target->getGUID()))
- {
- player->sendCancel("Unable to perform action.");
- return false;
- }
- if(IOBan::getInstance()->getNotationsCount(account.number) < (uint32_t)
- g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN))
- {
- kickAction = NONE;
- break;
- }
- action = ACTION_BANISHMENT;
- }
- bool deny = action != ACTION_BANREPORT;
- int64_t banTime = -1;
- account.warnings++;
- if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
- action = ACTION_DELETION;
- else if(length[0])
- banTime = length[0];
- else if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN))
- banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
- else
- banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
- if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action,
- comment, player->getGUID(), target->getGUID()))
- {
- account.warnings--;
- player->sendCancel("Account is already banned.");
- return false;
- }
- if(deny)
- break;
- banTime = -1;
- PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE);
- if(tmp == PLAYERBAN_BANISHMENT)
- {
- if(!length[1])
- banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
- else
- banTime = length[1];
- }
- IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action, comment,
- player->getGUID(), tmp);
- break;
- }
- case ACTION_BANFINAL:
- case ACTION_BANREPORTFINAL:
- {
- bool allow = action == ACTION_BANREPORTFINAL;
- int64_t banTime = -1;
- account.warnings++;
- if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
- action = ACTION_DELETION;
- else if(length[0])
- banTime = length[0];
- else
- banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
- if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action,
- comment, player->getGUID(), target->getGUID()))
- {
- account.warnings--;
- player->sendCancel("Account is already banned.");
- return false;
- }
- if(action != ACTION_DELETION)
- account.warnings += (g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN) - 1);
- if(allow)
- IOBan::getInstance()->addPlayerBanishment(target->getGUID(), -1, reason, action, comment,
- player->getGUID(), (PlayerBan_t)g_config.getNumber(
- ConfigManager::NAME_REPORT_TYPE));
- break;
- }
- case ACTION_DELETION:
- {
- //completely internal
- account.warnings++;
- if(!IOBan::getInstance()->addAccountBanishment(account.number, -1, reason, ACTION_DELETION,
- comment, player->getGUID(), target->getGUID()))
- {
- account.warnings--;
- player->sendCancel("Account is currently banned or already deleted.");
- return false;
- }
- break;
- }
- default:
- // these just shouldn't occur in rvw
- return false;
- }
- if(ipBanishment && target->getIP())
- {
- if(!length[2])
- length[2] = time(NULL) + g_config.getNumber(ConfigManager::IPBANISHMENT_LENGTH);
- IOBan::getInstance()->addIpBanishment(target->getIP(), length[2], reason, comment, player->getGUID(), 0xFFFFFFFF);
- }
- if(kickAction == FULL_KICK)
- IOBan::getInstance()->removeNotations(account.number);
- std::stringstream ss;
- if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS))
- ss << player->getName() << " has";
- else
- ss << "You have";
- ss << " taken the action \"" << getAction(action, ipBanishment) << "\"";
- switch(action)
- {
- case ACTION_NOTATION:
- {
- ss << " (" << (g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN) - IOBan::getInstance()->getNotationsCount(
- account.number)) << " left to banishment)";
- break;
- }
- case ACTION_STATEMENT:
- {
- ss << " for the statement: \"" << statement << "\"";
- break;
- }
- default:
- break;
- }
- ss << " against: " << name << " (Warnings: " << account.warnings << "), with reason: \"" << getReason(
- reason) << "\", and comment: \"" << comment << "\".";
- if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS))
- broadcastMessage(ss.str(), MSG_STATUS_WARNING);
- else
- player->sendTextMessage(MSG_STATUS_CONSOLE_RED, ss.str());
- if(target->isVirtual())
- {
- delete target;
- target = NULL;
- }
- else if(kickAction > NONE)
- {
- char buffer[30];
- sprintf(buffer, "You have been %s.", (kickAction > KICK ? "banished" : "namelocked"));
- target->sendTextMessage(MSG_INFO_DESCR, buffer);
- addMagicEffect(target->getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
- Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(
- &Game::kickPlayer, this, target->getID(), false)));
- }
- IOLoginData::getInstance()->saveAccount(account);
- return true;
- }
- void Game::kickPlayer(uint32_t playerId, bool displayEffect)
- {
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return;
- player->kick(displayEffect, true);
- }
- bool Game::broadcastMessage(const std::string& text, MessageClasses type)
- {
- if(type < MSG_CLASS_FIRST || type > MSG_CLASS_LAST)
- return false;
- std::clog << "> Broadcasted message: \"" << text << "\"." << std::endl;
- for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
- it->second->sendTextMessage(type, text);
- return true;
- }
- Position Game::getClosestFreeTile(Creature* creature, Position pos, bool extended/* = false*/, bool ignoreHouse/* = true*/)
- {
- PairVector relList;
- relList.push_back(PositionPair(0, 0));
- relList.push_back(PositionPair(-1, -1));
- relList.push_back(PositionPair(-1, 0));
- relList.push_back(PositionPair(-1, 1));
- relList.push_back(PositionPair(0, -1));
- relList.push_back(PositionPair(0, 1));
- relList.push_back(PositionPair(1, -1));
- relList.push_back(PositionPair(1, 0));
- relList.push_back(PositionPair(1, 1));
- if(extended)
- {
- relList.push_back(PositionPair(-2, 0));
- relList.push_back(PositionPair(0, -2));
- relList.push_back(PositionPair(0, 2));
- relList.push_back(PositionPair(2, 0));
- }
- std::random_shuffle(relList.begin() + 1, relList.end());
- if(Player* player = creature->getPlayer())
- {
- for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it)
- {
- Tile* tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z));
- if(!tile || !tile->ground)
- continue;
- ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM);
- if(ret == RET_NOTENOUGHROOM || (ret == RET_NOTPOSSIBLE && !player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
- || (ret == RET_PLAYERISNOTINVITED && !ignoreHouse && !player->hasFlag(PlayerFlag_CanEditHouses)))
- continue;
- return tile->getPosition();
- }
- }
- else
- {
- for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it)
- {
- Tile* tile = NULL;
- if((tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z)))
- && tile->__queryAdd(0, creature, 1, FLAG_IGNOREBLOCKITEM) == RET_NOERROR)
- return tile->getPosition();
- }
- }
- return Position(0, 0, 0);
- }
- std::string Game::getSearchString(const Position& fromPos, const Position& toPos, bool fromIsCreature/* = false*/, bool toIsCreature/* = false*/)
- {
- /*
- * When the position is on same level and 0 to 4 squares away, they are "[toIsCreature: standing] next to you"
- * When the position is on same level and 5 to 100 squares away they are "to the north/west/south/east."
- * When the position is on any level and 101 to 274 squares away they are "far to the north/west/south/east."
- * When the position is on any level and 275+ squares away they are "very far to the north/west/south/east."
- * When the position is not directly north/west/south/east of you they are "((very) far) to the north-west/south-west/south-east/north-east."
- * When the position is on a lower or higher level and 5 to 100 squares away they are "on a lower (or) higher level to the north/west/south/east."
- * When the position is on a lower or higher level and 0 to 4 squares away they are "below (or) above you."
- */
- enum distance_t
- {
- DISTANCE_BESIDE,
- DISTANCE_CLOSE,
- DISTANCE_FAR,
- DISTANCE_VERYFAR
- };
- enum direction_t
- {
- DIR_N, DIR_S, DIR_E, DIR_W,
- DIR_NE, DIR_NW, DIR_SE, DIR_SW
- };
- enum level_t
- {
- LEVEL_HIGHER,
- LEVEL_LOWER,
- LEVEL_SAME
- };
- distance_t distance;
- direction_t direction;
- level_t level;
- int32_t dx = fromPos.x - toPos.x, dy = fromPos.y - toPos.y, dz = fromPos.z - toPos.z;
- if(dz > 0)
- level = LEVEL_HIGHER;
- else if(dz < 0)
- level = LEVEL_LOWER;
- else
- level = LEVEL_SAME;
- if(std::abs(dx) < 5 && std::abs(dy) < 5)
- distance = DISTANCE_BESIDE;
- else
- {
- int32_t tmp = dx * dx + dy * dy;
- if(tmp < 10000)
- distance = DISTANCE_CLOSE;
- else if(tmp < 75625)
- distance = DISTANCE_FAR;
- else
- distance = DISTANCE_VERYFAR;
- }
- float tan;
- if(dx != 0)
- tan = (float)dy / (float)dx;
- else
- tan = 10.;
- if(std::abs(tan) < 0.4142)
- {
- if(dx > 0)
- direction = DIR_W;
- else
- direction = DIR_E;
- }
- else if(std::abs(tan) < 2.4142)
- {
- if(tan > 0)
- {
- if(dy > 0)
- direction = DIR_NW;
- else
- direction = DIR_SE;
- }
- else
- {
- if(dx > 0)
- direction = DIR_SW;
- else
- direction = DIR_NE;
- }
- }
- else
- {
- if(dy > 0)
- direction = DIR_N;
- else
- direction = DIR_S;
- }
- std::stringstream ss;
- switch(distance)
- {
- case DISTANCE_BESIDE:
- {
- switch(level)
- {
- case LEVEL_SAME:
- {
- ss << "is ";
- if(toIsCreature)
- ss << "standing ";
- ss << "next to you";
- break;
- }
- case LEVEL_HIGHER:
- {
- ss << "is above ";
- if(fromIsCreature)
- ss << "you";
- break;
- }
- case LEVEL_LOWER:
- {
- ss << "is below ";
- if(fromIsCreature)
- ss << "you";
- break;
- }
- default:
- break;
- }
- break;
- }
- case DISTANCE_CLOSE:
- {
- switch(level)
- {
- case LEVEL_SAME:
- ss << "is to the";
- break;
- case LEVEL_HIGHER:
- ss << "is on a higher level to the";
- break;
- case LEVEL_LOWER:
- ss << "is on a lower level to the";
- break;
- default:
- break;
- }
- break;
- }
- case DISTANCE_FAR:
- ss << "is far to the";
- break;
- case DISTANCE_VERYFAR:
- ss << "is very far to the";
- break;
- default:
- break;
- }
- if(distance != DISTANCE_BESIDE)
- {
- ss << " ";
- switch(direction)
- {
- case DIR_N:
- ss << "north";
- break;
- case DIR_S:
- ss << "south";
- break;
- case DIR_E:
- ss << "east";
- break;
- case DIR_W:
- ss << "west";
- break;
- case DIR_NE:
- ss << "north-east";
- break;
- case DIR_NW:
- ss << "north-west";
- break;
- case DIR_SE:
- ss << "south-east";
- break;
- case DIR_SW:
- ss << "south-west";
- break;
- default:
- break;
- }
- }
- return ss.str();
- }
- double Game::getExperienceStage(uint32_t level, double divider/* = 1.*/)
- {
- if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
- return g_config.getDouble(ConfigManager::RATE_EXPERIENCE) * divider;
- if(lastStageLevel && level >= lastStageLevel)
- return stages[lastStageLevel] * divider;
- return stages[level] * divider;
- }
- bool Game::loadExperienceStages()
- {
- if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
- {
- if(!stages.empty())
- stages.clear();
- return true;
- }
- xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_XML, "stages.xml").c_str());
- if(!doc)
- {
- std::clog << "[Warning - Game::loadExperienceStages] Cannot load stages file." << std::endl;
- std::clog << getLastXMLError() << std::endl;
- return false;
- }
- xmlNodePtr q, p, root = xmlDocGetRootElement(doc);
- if(xmlStrcmp(root->name, (const xmlChar*)"stages"))
- {
- std::clog << "[Error - Game::loadExperienceStages] Malformed stages file" << std::endl;
- xmlFreeDoc(doc);
- return false;
- }
- int32_t intValue, low = 0, high = 0;
- float floatValue, mul = 1.0f, defStageMultiplier;
- std::string strValue;
- lastStageLevel = 0;
- stages.clear();
- q = root->children;
- while(q)
- {
- if(!xmlStrcmp(q->name, (const xmlChar*)"world"))
- {
- if(readXMLString(q, "id", strValue))
- {
- IntegerVec intVector;
- if(!parseIntegerVec(strValue, intVector) || std::find(intVector.begin(),
- intVector.end(), g_config.getNumber(ConfigManager::WORLD_ID)) == intVector.end())
- {
- q = q->next;
- continue;
- }
- }
- defStageMultiplier = 1.0f;
- if(readXMLFloat(q, "multiplier", floatValue))
- defStageMultiplier = floatValue;
- p = q->children;
- while(p)
- {
- if(!xmlStrcmp(p->name, (const xmlChar*)"stage"))
- {
- low = 1;
- if(readXMLInteger(p, "minlevel", intValue) || readXMLInteger(p, "minLevel", intValue))
- low = intValue;
- high = 0;
- if(readXMLInteger(p, "maxlevel", intValue) || readXMLInteger(p, "maxLevel", intValue))
- high = intValue;
- else
- lastStageLevel = low;
- mul = 1.0f;
- if(readXMLFloat(p, "multiplier", floatValue))
- mul = floatValue;
- mul *= defStageMultiplier;
- if(lastStageLevel && lastStageLevel == (uint32_t)low)
- stages[lastStageLevel] = mul;
- else
- {
- for(int32_t i = low; i <= high; i++)
- stages[i] = mul;
- }
- }
- p = p->next;
- }
- }
- if(!xmlStrcmp(q->name, (const xmlChar*)"stage"))
- {
- low = 1;
- if(readXMLInteger(q, "minlevel", intValue))
- low = intValue;
- else
- high = 0;
- if(readXMLInteger(q, "maxlevel", intValue))
- high = intValue;
- else
- lastStageLevel = low;
- mul = 1.0f;
- if(readXMLFloat(q, "multiplier", floatValue))
- mul = floatValue;
- if(lastStageLevel && lastStageLevel == (uint32_t)low)
- stages[lastStageLevel] = mul;
- else
- {
- for(int32_t i = low; i <= high; i++)
- stages[i] = mul;
- }
- }
- q = q->next;
- }
- xmlFreeDoc(doc);
- return true;
- }
- bool Game::reloadHighscores()
- {
- lastHighscoreCheck = time(NULL);
- for(int16_t i = 0; i < 9; ++i)
- highscoreStorage[i] = getHighscore(i);
- return true;
- }
- void Game::checkHighscores()
- {
- reloadHighscores();
- uint32_t tmp = g_config.getNumber(ConfigManager::HIGHSCORES_UPDATETIME) * 60 * 1000;
- if(tmp <= 0)
- return;
- Scheduler::getInstance().addEvent(createSchedulerTask(tmp, boost::bind(&Game::checkHighscores, this)));
- }
- std::string Game::getHighscoreString(uint16_t skill)
- {
- Highscore hs = highscoreStorage[skill];
- std::stringstream ss;
- ss << "Highscore for " << getSkillName(skill) << "\n\nRank Level - Player Name";
- for(uint32_t i = 0; i < hs.size(); i++)
- ss << "\n" << (i + 1) << ". " << hs[i].second << " - " << hs[i].first;
- ss << "\n\nLast updated on:\n" << std::ctime(&lastHighscoreCheck);
- return ss.str();
- }
- Highscore Game::getHighscore(uint16_t skill)
- {
- Highscore hs;
- Database* db = Database::getInstance();
- DBResult* result;
- DBQuery query;
- if(skill >= SKILL__MAGLEVEL)
- {
- if(skill == SKILL__MAGLEVEL)
- query << "SELECT `maglevel`, `name` FROM `players` ORDER BY `maglevel` DESC, `manaspent` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
- else
- query << "SELECT `level`, `name` FROM `players` ORDER BY `level` DESC, `experience` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
- if(!(result = db->storeQuery(query.str())))
- return hs;
- do
- {
- uint32_t level;
- if(skill == SKILL__MAGLEVEL)
- level = result->getDataInt("maglevel");
- else
- level = result->getDataInt("level");
- std::string name = result->getDataString("name");
- if(name.length() > 0)
- hs.push_back(std::make_pair(name, level));
- }
- while(result->next());
- result->free();
- }
- else
- {
- query << "SELECT `player_skills`.`value`, `players`.`name` FROM `player_skills`,`players` WHERE `player_skills`.`skillid`=" << skill << " AND `player_skills`.`player_id`=`players`.`id` ORDER BY `player_skills`.`value` DESC, `player_skills`.`count` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
- if(!(result = db->storeQuery(query.str())))
- return hs;
- do
- {
- std::string name = result->getDataString("name");
- if(name.length() > 0)
- hs.push_back(std::make_pair(name, result->getDataInt("value")));
- }
- while(result->next());
- result->free();
- }
- return hs;
- }
- int32_t Game::getMotdId()
- {
- if(lastMotd == g_config.getString(ConfigManager::MOTD))
- return lastMotdId;
- lastMotd = g_config.getString(ConfigManager::MOTD);
- Database* db = Database::getInstance();
- DBQuery query;
- query << "INSERT INTO `server_motd` (`id`, `world_id`, `text`) VALUES (" << ++lastMotdId << ", " << g_config.getNumber(ConfigManager::WORLD_ID) << ", " << db->escapeString(lastMotd) << ")";
- if(db->query(query.str()))
- return lastMotdId;
- return --lastMotdId;
- }
- void Game::loadMotd()
- {
- Database* db = Database::getInstance();
- DBQuery query;
- query << "SELECT `id`, `text` FROM `server_motd` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `id` DESC LIMIT 1";
- DBResult* result;
- if(!(result = db->storeQuery(query.str())))
- {
- std::clog << "> ERROR: Failed to load motd!" << std::endl;
- lastMotdId = random_range(5, 500);
- return;
- }
- lastMotdId = result->getDataInt("id");
- lastMotd = result->getDataString("text");
- result->free();
- }
- void Game::checkPlayersRecord(Player* player)
- {
- uint32_t count = getPlayersOnline();
- if(count <= playersRecord)
- return;
- GlobalEventMap recordEvents = g_globalEvents->getEventMap(GLOBALEVENT_RECORD);
- for(GlobalEventMap::iterator it = recordEvents.begin(); it != recordEvents.end(); ++it)
- it->second->executeRecord(count, playersRecord, player);
- playersRecord = count;
- }
- void Game::loadPlayersRecord()
- {
- Database* db = Database::getInstance();
- DBQuery query;
- query << "SELECT `record` FROM `server_record` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `timestamp` DESC LIMIT 1";
- DBResult* result;
- if(!(result = db->storeQuery(query.str())))
- {
- std::clog << "> ERROR: Failed to load players record!" << std::endl;
- return;
- }
- playersRecord = result->getDataInt("record");
- result->free();
- }
- bool Game::reloadInfo(ReloadInfo_t reload, uint32_t playerId/* = 0*/)
- {
- bool done = false;
- switch(reload)
- {
- case RELOAD_ACTIONS:
- {
- if(g_actions->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload actions." << std::endl;
- break;
- }
- case RELOAD_CHAT:
- {
- if(g_chat.reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload chat." << std::endl;
- break;
- }
- case RELOAD_CONFIG:
- {
- if(g_config.reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload config." << std::endl;
- break;
- }
- case RELOAD_CREATUREEVENTS:
- {
- if(g_creatureEvents->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload creature events." << std::endl;
- break;
- }
- case RELOAD_GAMESERVERS:
- {
- #ifdef __LOGIN_SERVER__
- if(GameServers::getInstance()->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload game servers." << std::endl;
- #endif
- break;
- }
- case RELOAD_GLOBALEVENTS:
- {
- if(g_globalEvents->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload global events." << std::endl;
- break;
- }
- case RELOAD_GROUPS:
- {
- /*if(Groups::getInstance()->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload groups." << std::endl;*/
- break;
- }
- case RELOAD_HIGHSCORES:
- {
- if(reloadHighscores())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload highscores." << std::endl;
- break;
- }
- case RELOAD_ITEMS:
- {
- //TODO
- std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
- done = true;
- break;
- }
- case RELOAD_MONSTERS:
- {
- if(g_monsters.reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload monsters." << std::endl;
- break;
- }
- case RELOAD_MOVEEVENTS:
- {
- if(g_moveEvents->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload move events." << std::endl;
- break;
- }
- case RELOAD_NPCS:
- {
- g_npcs.reload();
- done = true;
- break;
- }
- case RELOAD_OUTFITS:
- {
- //TODO
- std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
- done = true;
- break;
- }
- case RELOAD_QUESTS:
- {
- if(Quests::getInstance()->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload quests." << std::endl;
- break;
- }
- case RELOAD_RAIDS:
- {
- if(!Raids::getInstance()->reload())
- std::clog << "[Error - Game::reloadInfo] Failed to reload raids." << std::endl;
- else if(!Raids::getInstance()->startup())
- std::clog << "[Error - Game::reloadInfo] Failed to startup raids when reloading." << std::endl;
- else
- done = true;
- break;
- }
- case RELOAD_SPELLS:
- {
- if(!g_spells->reload())
- std::clog << "[Error - Game::reloadInfo] Failed to reload spells." << std::endl;
- else if(!g_monsters.reload())
- std::clog << "[Error - Game::reloadInfo] Failed to reload monsters when reloading spells." << std::endl;
- else
- done = true;
- break;
- }
- case RELOAD_STAGES:
- {
- if(loadExperienceStages())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload stages." << std::endl;
- break;
- }
- case RELOAD_TALKACTIONS:
- {
- if(g_talkActions->reload())
- done = true;
- else
- std::clog << "[Error - Game::reloadInfo] Failed to reload talk actions." << std::endl;
- break;
- }
- case RELOAD_VOCATIONS:
- {
- if(Vocations::getInstance()->reload())
- done = true;
- else
- std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
- break;
- }
- case RELOAD_WEAPONS:
- {
- //TODO
- std::clog << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
- done = true;
- break;
- }
- case RELOAD_ALL:
- {
- done = true;
- for(int32_t i = RELOAD_FIRST; i <= RELOAD_LAST; i++)
- {
- if(!reloadInfo((ReloadInfo_t)i) && done)
- done = false;
- }
- break;
- }
- default:
- {
- std::clog << "[Warning - Game::reloadInfo] Reload type not found." << std::endl;
- break;
- }
- }
- if(reload != RELOAD_MODS && !ScriptManager::getInstance()->reloadMods())
- std::clog << "[Error - Game::reloadInfo] Failed to reload mods." << std::endl;
- if(!playerId)
- return done;
- Player* player = getPlayerByID(playerId);
- if(!player || player->isRemoved())
- return done;
- if(done)
- {
- player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Reloaded successfully.");
- return true;
- }
- if(reload == RELOAD_ALL)
- player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Failed to reload some parts.");
- else
- player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Failed to reload.");
- return false;
- }
- void Game::prepareGlobalSave(uint8_t minutes)
- {
- std::clog << "Game::prepareGlobalSave in " << (uint32_t)minutes << " minutes" << std::endl;
- switch(minutes)
- {
- case 5:
- setGameState(GAMESTATE_CLOSING);
- broadcastMessage("Server is going down for a global save within 5 minutes. Please logout.", MSG_STATUS_WARNING);
- Scheduler::getInstance().addEvent(createSchedulerTask(2 * 60000, boost::bind(&Game::prepareGlobalSave, this, 3)));
- break;
- case 3:
- broadcastMessage("Server is going down for a global save within 3 minutes. Please logout.", MSG_STATUS_WARNING);
- Scheduler::getInstance().addEvent(createSchedulerTask(2 * 60000, boost::bind(&Game::prepareGlobalSave, this, 1)));
- break;
- case 1:
- broadcastMessage("Server is going down for a global save in one minute, please logout!", MSG_STATUS_WARNING);
- Scheduler::getInstance().addEvent(createSchedulerTask(60000, boost::bind(&Game::prepareGlobalSave, this, 0)));
- break;
- case 0:
- globalSave();
- break;
- default:
- if(minutes > 5)
- Scheduler::getInstance().addEvent(createSchedulerTask((minutes - 5) * 1000, boost::bind(&Game::prepareGlobalSave, this, 5)));
- break;
- }
- }
- void Game::globalSave()
- {
- bool close = g_config.getBool(ConfigManager::SHUTDOWN_AT_GLOBALSAVE);
- if(close) // check are we're going to close the server
- setGameState(GAMESTATE_CLOSING);
- // call the global event
- g_globalEvents->execute(GLOBALEVENT_GLOBALSAVE);
- if(close)
- {
- //shutdown server
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAMESTATE_SHUTDOWN)));
- return;
- }
- //close server
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAMESTATE_CLOSED)));
- //clean map if configured to
- if(g_config.getBool(ConfigManager::CLEAN_MAP_AT_GLOBALSAVE))
- {
- uint32_t dummy;
- cleanMap(dummy);
- }
- //pay houses
- Houses::getInstance()->payHouses();
- //clear temporial and expired bans
- IOBan::getInstance()->clearTemporials();
- //remove premium days globally if configured to
- if(g_config.getBool(ConfigManager::INIT_PREMIUM_UPDATE))
- IOLoginData::getInstance()->updatePremiumDays();
- //reload everything
- reloadInfo(RELOAD_ALL);
- //prepare for next global save after 24 hours
- Scheduler::getInstance().addEvent(createSchedulerTask(((24 * 60 * 60) - (5 * 60)) * 1000, boost::bind(&Game::prepareGlobalSave, this, 5)));
- //open server
- Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAMESTATE_NORMAL)));
- }
- void Game::shutdown()
- {
- std::clog << "Preparing";
- Scheduler::getInstance().shutdown();
- std::clog << " to";
- Dispatcher::getInstance().shutdown();
- std::clog << " shutdown";
- Spawns::getInstance()->clear();
- std::clog << " the";
- Raids::getInstance()->clear();
- std::clog << " server";
- cleanup();
- std::clog << "- done." << std::endl;
- if (services)
- services->stop();
- #ifndef dont_force_shutdown
- exit(-1);
- #endif
- }
- void Game::cleanup()
- {
- //free memory
- for(std::vector<Thing*>::iterator it = releaseThings.begin(); it != releaseThings.end(); ++it)
- (*it)->unRef();
- releaseThings.clear();
- for(DecayList::iterator it = toDecayItems.begin(); it != toDecayItems.end(); ++it)
- {
- int32_t dur = (*it)->getDuration();
- if(dur >= EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS)
- decayItems[lastBucket].push_back(*it);
- else
- decayItems[(lastBucket + 1 + (*it)->getDuration() / 1000) % EVENT_DECAYBUCKETS].push_back(*it);
- }
- toDecayItems.clear();
- }
- void Game::freeThing(Thing* thing)
- {
- releaseThings.push_back(thing);
- }
- void Game::showHotkeyUseMessage(Player* player, Item* item)
- {
- const ItemType& it = Item::items[item->getID()];
- uint32_t count = player->__getItemTypeCount(item->getID(), item->isFluidContainer() ? item->getFluidType() : -1);
- std::stringstream stream;
- if(!it.showCount)
- stream << "Using one of " << it.name << "...";
- else if(count == 1)
- stream << "Using the last " << it.name.c_str() << "...";
- else
- stream << "Using one of " << count << " " << it.pluralName.c_str() << "...";
- player->sendTextMessage(MSG_INFO_DESCR, stream.str().c_str());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement