mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-02 19:42:05 -04:00
Compare commits
947 Commits
last_worki
...
develop
Author | SHA1 | Date | |
---|---|---|---|
|
612cfe22d9 | ||
|
1e311904cc | ||
|
8ceee35492 | ||
|
40b677f871 | ||
|
57e7ee1894 | ||
|
61069e6d49 | ||
|
0521b167fb | ||
|
6e1f13d17a | ||
|
bbf49123b6 | ||
|
48d996bd4f | ||
|
8ddcd24704 | ||
|
1c5fd48d03 | ||
|
31ec4efdcf | ||
|
20b1ec18a9 | ||
|
41b891feaf | ||
|
47a2eddaf0 | ||
|
2e5cf8dfec | ||
|
eecb5ac8a1 | ||
|
99c8aff702 | ||
|
d588dd0348 | ||
|
7883143089 | ||
|
c753e61b62 | ||
|
42f0046ee7 | ||
|
aa54fb11cc | ||
|
e4d43d952b | ||
|
ae3a6f1b27 | ||
|
5724cf53bf | ||
|
0ec9c5576c | ||
|
96641865bc | ||
|
ea7bf4b86d | ||
|
94d1915acb | ||
|
02e41f6103 | ||
|
b627ecf0fe | ||
|
ca4f00cfe3 | ||
|
8687e43191 | ||
|
d3027c3b26 | ||
|
afd056d82d | ||
|
e6802d514c | ||
|
66ed26617d | ||
|
f5bf5956b2 | ||
|
c14b117947 | ||
|
91549bff7a | ||
|
18ef69f3d1 | ||
|
104f3daf7c | ||
|
b85b35a2b6 | ||
|
0f61c4c0e1 | ||
|
7587a6e142 | ||
|
8940e65885 | ||
|
29ec6a9a88 | ||
|
3e26c491d4 | ||
|
9fd0e96b0e | ||
|
a9619a4b3c | ||
|
8276c5c247 | ||
|
e9b3f4e51e | ||
|
187d8300b0 | ||
|
8da65938b7 | ||
|
a92b558c88 | ||
|
57f3de66f8 | ||
|
561114833c | ||
|
324026874a | ||
|
dbdff59e0f | ||
|
a996797beb | ||
|
32330d557c | ||
|
ec85cfd590 | ||
|
89c6191710 | ||
|
eb43a7523d | ||
|
f5ebb3fb3b | ||
|
8a03c40af9 | ||
|
a07aa12783 | ||
|
e91960040c | ||
|
fea8638775 | ||
|
c286df6a91 | ||
|
3dcd9af6c0 | ||
|
4fbc388457 | ||
|
f2e34174c4 | ||
|
90078eb2e8 | ||
|
7339e08172 | ||
|
1fddfd50a6 | ||
|
2e906ae090 | ||
|
8ba3c195f2 | ||
|
e96cc0c758 | ||
|
2195b0b7dc | ||
|
ecf07317fc | ||
|
69d4b19979 | ||
|
fdb767f155 | ||
|
e1c86a4898 | ||
|
88ff22e55e | ||
|
d49516c03e | ||
|
42ee97d467 | ||
|
8f92fde00e | ||
|
3104478263 | ||
|
a92ece58c1 | ||
|
6fcfd58b33 | ||
|
905cbf7d3c | ||
|
4c850ea768 | ||
|
afe1e59889 | ||
|
f3fe8c1de8 | ||
|
4e054ca947 | ||
|
eb949a8602 | ||
|
315452d121 | ||
|
1a9a8c2116 | ||
|
97dcd765eb | ||
|
e00bb48386 | ||
|
ef117204b3 | ||
|
9cda72f1ab | ||
|
a99a129d9a | ||
|
6ae181fa0a | ||
|
1f3c98312c | ||
|
db0aac3647 | ||
|
00017468cc | ||
|
4f80023156 | ||
|
6127ad44cc | ||
|
d7c383d04a | ||
|
357805d04c | ||
|
706a9fa721 | ||
|
289e4dc24b | ||
|
a458608322 | ||
|
3e58cdbd6c | ||
|
3068a0c41b | ||
|
26ef649a6c | ||
|
cc07e1f453 | ||
|
75c6708ac5 | ||
|
ee1f4b0888 | ||
|
f6104812a5 | ||
|
d0dca62a91 | ||
|
3b451849ae | ||
|
9889b6011b | ||
|
9b566abb3d | ||
|
37cca32de8 | ||
|
02e1b8a82f | ||
|
267961233f | ||
|
d673670604 | ||
|
b955c38a2a | ||
|
044d7e5207 | ||
|
c1fdad2156 | ||
|
f038b525c6 | ||
|
bcb609e4f6 | ||
|
163f240cf9 | ||
|
3066efeebb | ||
|
10017b7e8c | ||
|
1e4a1cf263 | ||
|
080f9ea23d | ||
|
e236e1d207 | ||
|
1b69f5fc87 | ||
|
e4956edf50 | ||
|
384d134f1d | ||
|
f361ee61cd | ||
|
7e6e51c6bf | ||
|
5bdc760a5f | ||
|
83ae7df6d9 | ||
|
7c7742fb35 | ||
|
c55145d715 | ||
|
42aa3d7512 | ||
|
07c467e1af | ||
|
bec0cae0eb | ||
|
5bb3cc3b4e | ||
|
d614ea6968 | ||
|
1579aa3d6a | ||
|
cf30eef39e | ||
|
8c5375f609 | ||
|
c442dc9ecd | ||
|
ace4dfe58f | ||
|
79f2edf406 | ||
|
0209f3e617 | ||
|
e799e8327f | ||
|
0f7e6f359d | ||
|
0739532c7d | ||
|
d23a84d6cf | ||
|
8de606051a | ||
|
a7e59fa7e4 | ||
|
922fb80f3d | ||
|
8c9f841d63 | ||
|
c5ce2ec771 | ||
|
0492bc4c59 | ||
|
7abfbd5953 | ||
|
1d3dd99414 | ||
|
c3c19c3592 | ||
|
a19517cce4 | ||
|
880b1f3066 | ||
|
0b13b590a0 | ||
|
8aeaee1b19 | ||
|
29e3f61b6b | ||
|
bbd4fcef3b | ||
|
13727caf14 | ||
|
aba748cb5d | ||
|
611140568e | ||
|
08dfd22bfa | ||
|
5fd48fad6b | ||
|
7e2246e8d8 | ||
|
1e9d61c838 | ||
|
b8d6a943aa | ||
|
f30360f245 | ||
|
359ea8a40e | ||
|
127ac15936 | ||
|
0cb2fe1a68 | ||
|
c0312079ef | ||
|
a9d4e621e3 | ||
|
08c5980b22 | ||
|
f5ea82f735 | ||
|
81c97105b7 | ||
|
837c7a9223 | ||
|
cd60c571ac | ||
|
205d3619d6 | ||
|
1275c8b5da | ||
|
b2e273d7cf | ||
|
88233cf6d2 | ||
|
05eca7f22e | ||
|
7a02d38e94 | ||
|
af121f52bd | ||
|
e8c9904e1d | ||
|
bbac4b0fce | ||
|
3850860440 | ||
|
bb31bb0f23 | ||
|
b191da416b | ||
|
2a489953db | ||
|
fe4b9cb2bf | ||
|
95b003cc2b | ||
|
27200b8df5 | ||
|
520ae7a119 | ||
|
460722d3d5 | ||
|
92de857cda | ||
|
4323eb5385 | ||
|
324ebab2d2 | ||
|
5ccc2435b0 | ||
|
13708a2361 | ||
|
59e3b2379a | ||
|
9fc99faa5c | ||
|
116a573f85 | ||
|
a0c4d80c5e | ||
|
8ae4fbc045 | ||
|
e819603432 | ||
|
bab81a809c | ||
|
441c1a6383 | ||
|
58334a0e5f | ||
|
94491903f7 | ||
|
f3a823af03 | ||
|
5dfbc0f249 | ||
|
ab98f3662f | ||
|
33f8709d76 | ||
|
56491266cc | ||
|
c7e38b8b00 | ||
|
9649d755a9 | ||
|
e581727625 | ||
|
06e0c32062 | ||
|
77203bca4c | ||
|
7b1f95cd77 | ||
|
ba8184db89 | ||
|
da621dfc0e | ||
|
ce5030acd1 | ||
|
a309e651da | ||
|
16e99040e0 | ||
|
3f82ca1244 | ||
|
8f487689ba | ||
|
b092d447cc | ||
|
4160622556 | ||
|
64006d2351 | ||
|
52c707d66e | ||
|
9174801fdb | ||
|
9529a1374e | ||
|
8755ca4f33 | ||
|
a14e36fadc | ||
|
bc95c139de | ||
|
40ad1d8a29 | ||
|
76f073d85f | ||
|
9077c60b96 | ||
|
645a1fb4fb | ||
|
7c30b95c4b | ||
|
2bfaf376ef | ||
|
68a2d5f0b9 | ||
|
5bec522c8e | ||
|
81d82cd7a8 | ||
|
f437b36f5a | ||
|
b5054debea | ||
|
4e39b082f1 | ||
|
62484e2f87 | ||
|
50b4f517f2 | ||
|
2b5a6997f4 | ||
|
4978813c27 | ||
|
6e1983031b | ||
|
c5cc7c2f00 | ||
|
4762811347 | ||
|
c55acba1b6 | ||
|
4c7928da78 | ||
|
517bdc0638 | ||
|
2cee5ff573 | ||
|
c3fd8f917e | ||
|
91afda04ca | ||
|
e60da4f7b4 | ||
|
67485eafc0 | ||
|
d81832f256 | ||
|
7ad40f625a | ||
|
71d5bbc9ff | ||
|
37b8203dae | ||
|
f4016e1a12 | ||
|
6c74222b68 | ||
|
7e4fc52b9e | ||
|
e5a9658b5a | ||
|
6f5a480cbd | ||
|
ce2d22d984 | ||
|
52da0a671f | ||
|
afe79e6c5f | ||
|
d757ad39fc | ||
|
74ce5a2fe1 | ||
|
3b271980cc | ||
|
922f3ccd1e | ||
|
c070f5b80e | ||
|
ff93dc41ef | ||
|
546908acde | ||
|
1ae15df64c | ||
|
9024f3fad6 | ||
|
452f1cc8c0 | ||
|
11bbb023d9 | ||
|
88abd59ec3 | ||
|
5e2487c8cc | ||
|
9bb298b2f3 | ||
|
cbbfa4ed95 | ||
|
54af893570 | ||
|
c79b5c9992 | ||
|
e390138258 | ||
|
35f9251056 | ||
|
86bf0eec81 | ||
|
ebd295bfa4 | ||
|
a89fc64555 | ||
|
1856cc0634 | ||
|
68657e1edc | ||
|
c7b87c0d89 | ||
|
8bebba64b3 | ||
|
ddad27a5f9 | ||
|
53207a9ff0 | ||
|
d9d185d7e6 | ||
|
13af16ec0e | ||
|
f4687942af | ||
|
7c08420206 | ||
|
3734f22fc2 | ||
|
7ab40a30f1 | ||
|
4032258e76 | ||
|
4dee26e136 | ||
|
86a2e4aff3 | ||
|
b2e86d282a | ||
|
efdec5e472 | ||
|
84d5eee1fc | ||
|
59fab08230 | ||
|
1637bba167 | ||
|
372d50d7eb | ||
|
bac901c437 | ||
|
69f7fb5e47 | ||
|
24c46c0480 | ||
|
affff96837 | ||
|
77d6cb2e43 | ||
|
4ed8f3e5e2 | ||
|
c55c0b327d | ||
|
4695193aa0 | ||
|
247b5ca709 | ||
|
d895357182 | ||
|
5a5c0a3a5f | ||
|
caf254fd95 | ||
|
151756329c | ||
|
ddfc71d3af | ||
|
a77a90578f | ||
|
8c95543f6d | ||
|
5dff4cbdd3 | ||
|
cc1929a9fb | ||
|
100f3ae156 | ||
|
e56238a10c | ||
|
62055eff04 | ||
|
6b023ceb3c | ||
|
637f7f3d95 | ||
|
c162fb0eab | ||
|
2c9ae60bbf | ||
|
b9bfe5e985 | ||
|
3bcaa4cc3e | ||
|
04890660c0 | ||
|
c70cf022b7 | ||
|
872e56f8f9 | ||
|
b640c87c69 | ||
|
dd552ba69d | ||
|
e09cb197b3 | ||
|
a62475e81e | ||
|
bd97e72774 | ||
|
4ad37f1011 | ||
|
d72a2af641 | ||
|
fc0c504c28 | ||
|
f12ffc468d | ||
|
33e580ed38 | ||
|
ab3e152b7d | ||
|
3370309dd0 | ||
|
4aa3a444d0 | ||
|
08477780f8 | ||
|
516564a896 | ||
|
9353f77db0 | ||
|
1339975ade | ||
|
7c4091a196 | ||
|
d8ac8216c4 | ||
|
a264745207 | ||
|
c09471ed43 | ||
|
00757b4ae7 | ||
|
fc96dac7c7 | ||
|
b5db036d71 | ||
|
573b9a7202 | ||
|
e5afe8791b | ||
|
cd0bb10ef6 | ||
|
c071b9d684 | ||
|
019e305525 | ||
|
875b76634a | ||
|
c42f1a08de | ||
|
c78fa033af | ||
|
8fb4910320 | ||
|
186d5b5cc5 | ||
|
25cd75d40c | ||
|
8ccd3439c1 | ||
|
bfaa25cb39 | ||
|
c7acef20a9 | ||
|
a80c80454b | ||
|
eb17da1c89 | ||
|
2d7d10a417 | ||
|
44a76c94af | ||
|
f00e878dd0 | ||
|
0c8642d6ab | ||
|
793f5323fb | ||
|
7f6b291366 | ||
|
c1d67538f3 | ||
|
dbaea65c19 | ||
|
ed5ee01ba6 | ||
|
b838027cba | ||
|
1d9f57a385 | ||
|
0e8de966a9 | ||
|
cdfa2f682e | ||
|
866e2d3559 | ||
|
d96d5b29a5 | ||
|
fdf30b4615 | ||
|
cfb3a473c1 | ||
|
5c350e4ffa | ||
|
4e8ce558a7 | ||
|
72099e92bb | ||
|
52cacb1ded | ||
|
c67c5f3bdf | ||
|
5d65965ec0 | ||
|
08b3564d7e | ||
|
9505cd71be | ||
|
844f21d9a4 | ||
|
1516e0bc50 | ||
|
8c9ecebae6 | ||
|
cc44d6b63c | ||
|
9c2cdf9b5d | ||
|
9a2a79095c | ||
|
2de4934c41 | ||
|
9513389e0a | ||
|
b490cdf124 | ||
|
c6307dde35 | ||
|
8c07e3f549 | ||
|
0d4ed1d1c8 | ||
|
90e48f9ddd | ||
|
3d4bf3465b | ||
|
3145ec5663 | ||
|
4bb222a47a | ||
|
3269621dec | ||
|
c71aa0b45e | ||
|
e38a995574 | ||
|
96c0f3444e | ||
|
7fa4a1eb80 | ||
|
9d63be52e3 | ||
|
c0f7f1b1ad | ||
|
a866688344 | ||
|
0546b81cff | ||
|
358afbace3 | ||
|
be5a517aaa | ||
|
91820dc933 | ||
|
6642ed7e12 | ||
|
248ea0cce1 | ||
|
be4b3b506f | ||
|
43e1fbfab3 | ||
|
2b780687dd | ||
|
e0c9ca2bc2 | ||
|
6c366110ef | ||
|
6dd8bdda0c | ||
|
a2a30003e0 | ||
|
b345521f79 | ||
|
6e12668176 | ||
|
8f89eb8f23 | ||
|
a77d2a9b48 | ||
|
0a94840419 | ||
|
7c25b14640 | ||
|
1bf25b2a2b | ||
|
4f339709d5 | ||
|
7b205c7b9b | ||
|
77e0639410 | ||
|
545ce18f1f | ||
|
43c0925dee | ||
|
ce13827bce | ||
|
b81141a158 | ||
|
718bc28c57 | ||
|
bc30958d37 | ||
|
0c3f6cc9c4 | ||
|
eb324062da | ||
|
de8877c1a4 | ||
|
dc0b886691 | ||
|
8871f47066 | ||
|
23ce361801 | ||
|
d918ad3776 | ||
|
e898c045f7 | ||
|
dcaad5729d | ||
|
f7482781e5 | ||
|
40deaf3075 | ||
|
663c591a89 | ||
|
031dae2c84 | ||
|
ab3ca412b3 | ||
|
ad88c0b28a | ||
|
9372b4bc32 | ||
|
6a6ee67ae2 | ||
|
e6af0ef842 | ||
|
b5a48b0eff | ||
|
a8f3fe28d4 | ||
|
63b3098592 | ||
|
8b4eb8c57e | ||
|
b9c0084080 | ||
|
c961ccd5bf | ||
|
4a544a9ea3 | ||
|
fb1d22d731 | ||
|
9bc3fc8dd7 | ||
|
fe1a652cd1 | ||
|
79de4fd1ff | ||
|
bc72147622 | ||
|
771b5b6d81 | ||
|
61e4effd74 | ||
|
68772a2011 | ||
|
108d8be013 | ||
|
8499eeff39 | ||
|
4b0ffb3882 | ||
|
5b5bbc23b4 | ||
|
8a0ebe7ec4 | ||
|
5d494255ad | ||
|
5af1f6dba6 | ||
|
6ba1f968c3 | ||
|
7c29a850c4 | ||
|
2b10221a75 | ||
|
506bcbaf87 | ||
|
16c9b741bf | ||
|
e89b7557b3 | ||
|
ae38ee1bc1 | ||
|
bf9095822e | ||
|
2bdc238bc2 | ||
|
a68866617f | ||
|
4109f33b6e | ||
|
7036ef363d | ||
|
31446f37fa | ||
|
2cc63960a7 | ||
|
1148619ca5 | ||
|
6c409e93a9 | ||
|
fd2df829de | ||
|
31b13300ac | ||
|
09e1e31e79 | ||
|
b2c1c2895d | ||
|
feb73a8444 | ||
|
f4e238f4be | ||
|
ca44400048 | ||
|
a2d4879cdd | ||
|
4a320d7096 | ||
|
96a29a9f04 | ||
|
25e55bf6df | ||
|
c2a3641d08 | ||
|
f286922974 | ||
|
0317bea83b | ||
|
18e9ee5f63 | ||
|
52703537e9 | ||
|
df6e16103c | ||
|
7e535a9398 | ||
|
c04680ea38 | ||
|
101070954d | ||
|
b1998d5f73 | ||
|
3864bf6d85 | ||
|
4ce4647a75 | ||
|
260878df38 | ||
|
ebd8ab0580 | ||
|
e30831fdc5 | ||
|
315f2e579c | ||
|
6e7459a2f8 | ||
|
58fda93b45 | ||
|
5370f13b2b | ||
|
d931f71b06 | ||
|
62daa4db89 | ||
|
e106eafb6c | ||
|
c9feef07b7 | ||
|
cf38454c8f | ||
|
06e7ea59f4 | ||
|
37b098e87a | ||
|
6bffe69b21 | ||
|
bd26a71fef | ||
|
0f093235f8 | ||
|
92be59d020 | ||
|
364ab40b3f | ||
|
4aae16e458 | ||
|
a1ca960543 | ||
|
e24a6f99cb | ||
|
c67f74130f | ||
|
62cc343f51 | ||
|
8725377168 | ||
|
d5f17c01a8 | ||
|
d6277bc722 | ||
|
316e326d71 | ||
|
685fe7dd5a | ||
|
c087fb44c0 | ||
|
00e5e4f642 | ||
|
46350a0724 | ||
|
fb18c1fbe4 | ||
|
4f3828e594 | ||
|
270d4ce436 | ||
|
7c9077beec | ||
|
d7166cadc0 | ||
|
38014f8a16 | ||
|
4f48643c5c | ||
|
3490f366a2 | ||
|
13362d347c | ||
|
8665c1a226 | ||
|
b6c3c7f71c | ||
|
63ac56224e | ||
|
09705bec4e | ||
|
d5f0cbef8c | ||
|
595a53ed9e | ||
|
b3920f9630 | ||
|
c4c43421f3 | ||
|
5e926bf668 | ||
|
0c435d91c9 | ||
|
2233f48719 | ||
|
67928ee875 | ||
|
8eb257aba4 | ||
|
b43a6885c5 | ||
|
63edbe81f3 | ||
|
205136d661 | ||
|
a4d3e91085 | ||
|
065fe05795 | ||
|
2939683183 | ||
|
4ef62a16ec | ||
|
7f65cfcbbf | ||
|
70b4fc8630 | ||
|
2c30b7dfc1 | ||
|
59f3cfa2f1 | ||
|
136ced3aae | ||
|
5b7ad2364b | ||
|
302d7bd68a | ||
|
d26b64b458 | ||
|
8839e75557 | ||
|
5fc0e0eeca | ||
|
30b0d4a97d | ||
|
110cfbccc2 | ||
|
3cd181f5da | ||
|
7a25c818f2 | ||
|
bb02f94d38 | ||
|
b8a563f9d7 | ||
|
926e9146e2 | ||
|
4c7316702d | ||
|
0c197f34a1 | ||
|
590ad3e002 | ||
|
44acee7e6d | ||
|
d06bf5499f | ||
|
3969fff64a | ||
|
0aac675b30 | ||
|
8b44d90114 | ||
|
ff2f587959 | ||
|
1242a8b00c | ||
|
1546ed54fc | ||
|
97c1fb06cf | ||
|
8743042950 | ||
|
51bbf4ae2e | ||
|
37d91480f9 | ||
|
1ad2b5d7d0 | ||
|
4e69022072 | ||
|
cdf4b3a2f2 | ||
|
57b9d5ab99 | ||
|
f4060e16bf | ||
|
ac01224769 | ||
|
8eaa920751 | ||
|
fbf6810c5c | ||
|
9b3712044d | ||
|
1159c75ab8 | ||
|
1bac69c893 | ||
|
9a29d0806a | ||
|
c413006a91 | ||
|
2b81660dce | ||
|
884a26dc52 | ||
|
c612b885dd | ||
|
ba13d5798d | ||
|
b633126568 | ||
|
335a59204c | ||
|
24f55139dd | ||
|
ed0a0a58f7 | ||
|
f5619ff800 | ||
|
c5516511b0 | ||
|
d1c8987091 | ||
|
65389e3362 | ||
|
5723f77b1f | ||
|
a4ea5f024b | ||
|
fec348136e | ||
|
957a8d89bb | ||
|
c23f9c7ca9 | ||
|
16d4779970 | ||
|
554c8b5514 | ||
|
33a52c4fa8 | ||
|
1c712c7533 | ||
|
f0d4429f65 | ||
|
8b93abe86e | ||
|
23b6ede128 | ||
|
92339ba0c4 | ||
|
d486650143 | ||
|
62d1fec8b3 | ||
|
abbdaf1368 | ||
|
fc51b7f564 | ||
|
62ed9b22f1 | ||
|
f0ec2125ac | ||
|
b45390adb6 | ||
|
8df79c9e6f | ||
|
78f2b18641 | ||
|
320d662abe | ||
|
6dcdabf9a4 | ||
|
c02c09a237 | ||
|
59f1ef0594 | ||
|
c80eb623b1 | ||
|
a99a348c36 | ||
|
101a2d50ed | ||
|
11a371f32b | ||
|
2c18016a29 | ||
|
541456bd8e | ||
|
a7959d9263 | ||
|
9e2960c047 | ||
|
01dd955376 | ||
|
426750f931 | ||
|
c944d262b3 | ||
|
7827fbf8d3 | ||
|
d01c780cac | ||
|
ffae2b744f | ||
|
53064a7345 | ||
|
3d5fa45730 | ||
|
79eaf5d79e | ||
|
4a8b241e4e | ||
|
20427400ef | ||
|
95849e1c1c | ||
|
bd4e4a293c | ||
|
d989ec2a58 | ||
|
14a7a4172a | ||
|
108f5aa677 | ||
|
863e006830 | ||
|
e33bd05f09 | ||
|
c9838254b9 | ||
|
1ce34914bc | ||
|
73d5b9fbf1 | ||
|
fe111ab6ca | ||
|
de7484a931 | ||
|
b8a3d4f1e0 | ||
|
44650bc4a5 | ||
|
02e9b52a02 | ||
|
10d4d7c148 | ||
|
5c7ca212aa | ||
|
c38fbc0c09 | ||
|
06606c5f01 | ||
|
2eb40a0d7c | ||
|
b1a9ced93e | ||
|
dbbd1fa0d8 | ||
|
de2ec984e4 | ||
|
29228a0c11 | ||
|
5920d93b19 | ||
|
3790920db3 | ||
|
21745a6aa8 | ||
|
574b2da4f8 | ||
|
fc07d2e24d | ||
|
33be97ea9d | ||
|
c0cd7555e1 | ||
|
1f5788def8 | ||
|
cc5d0b139a | ||
|
ecc61ea5f9 | ||
|
b17d193a59 | ||
|
7c0594b749 | ||
|
8b55993f25 | ||
|
b16ea7bc44 | ||
|
4cf005467a | ||
|
cd8cb1acb3 | ||
|
26f5e1be28 | ||
|
ea1e16aea7 | ||
|
cdcdd6a584 | ||
|
c74e40f7d0 | ||
|
cb86bcb3af | ||
|
dabbff1fda | ||
|
77c12c489c | ||
|
49a4bf1ab0 | ||
|
1ef3e350c0 | ||
|
7a8e53a8ac | ||
|
5892887e4c | ||
|
23aef8cc46 | ||
|
9a2977a094 | ||
|
1a43f15800 | ||
|
aa4fc09a32 | ||
|
64155dc752 | ||
|
8cb1ae99e8 | ||
|
f8a2b7efc7 | ||
|
5d3f25f1a8 | ||
|
ddf4d0d202 | ||
|
b68d13ea7f | ||
|
e501d5b796 | ||
|
4c391f64bc | ||
|
ae9a712477 | ||
|
91842ab08a | ||
|
1dd04e2174 | ||
|
6c3918ac2f | ||
|
cf73522291 | ||
|
8da3a6ff9c | ||
|
60b4035ec5 | ||
|
597a800599 | ||
|
48b9fa39b5 | ||
|
52806d2f3d | ||
|
eaafba79e2 | ||
|
6124e6906d | ||
|
48f1fbc8f5 | ||
|
1dccc0530e | ||
|
94db8336df | ||
|
b33b0b1bc4 | ||
|
b69e18ff3c | ||
|
a615f29e63 | ||
|
4d57aa72a6 | ||
|
a30311d12a | ||
|
f8ab0cd86d | ||
|
9c28e966f7 | ||
|
49a13effca | ||
|
3162bedb17 | ||
|
2048d8d188 | ||
|
08fd862939 | ||
|
0876b293e8 | ||
|
67fed3dba5 | ||
|
1417a0d841 | ||
|
01ba37c50d | ||
|
d80e9bed0e | ||
|
d9bccb5bff | ||
|
335ec414d6 | ||
|
1f60bcf4fc | ||
|
d2a5eaa2c8 | ||
|
a93843510e | ||
|
6ef28e590c | ||
|
81abefcf39 | ||
|
e4c296ca7e | ||
|
d4a3b601fa | ||
|
c91e0ef146 | ||
|
3ece02932f | ||
|
f92d9ea2f3 | ||
|
978f31e64a | ||
|
01eceee58f | ||
|
f71b4ef031 | ||
|
e409d3792c | ||
|
e851c767df | ||
|
44e5430fdc | ||
|
88cb73bc09 | ||
|
c9116005d6 | ||
|
83fb9badd7 | ||
|
4bebeb387a | ||
|
0e4b9f4263 | ||
|
e72f1d3dcf | ||
|
2f3f677ec4 | ||
|
d66d2908ec | ||
|
d2ac603efa | ||
|
c2f0b9d999 | ||
|
b7fd3e442c | ||
|
5acc769505 | ||
|
d5f07b97a8 | ||
|
1c5f8b3d0b | ||
|
23dcc1dafe | ||
|
a47d5f96a5 | ||
|
8c73f6e926 | ||
|
c6ac8b2f14 | ||
|
cb4171f1fd | ||
|
47be08fbf7 | ||
|
110a112328 | ||
|
73732ac542 | ||
|
1f3cd8eaf3 | ||
|
69b34fdce7 | ||
|
df2ac1fb32 | ||
|
c4dea467e3 | ||
|
0d880b6b75 | ||
|
6d8064aa6c | ||
|
42ba95b69d | ||
|
c83b4a12b9 | ||
|
cfb29b912f | ||
|
fe69f069ea | ||
|
45b9f9a064 | ||
|
5c8277fbb9 | ||
|
789df97d48 | ||
|
300748668f | ||
|
74be19c51d | ||
|
e043be5ca4 | ||
|
f1025f89d3 | ||
|
7bc3c8c2dd | ||
|
3b48ed1f74 | ||
|
ea6b1e33c7 | ||
|
02b90edd3f | ||
|
3fcc9eea49 | ||
|
d90dc0cb80 | ||
|
093d3b7c15 | ||
|
0462b790b7 | ||
|
5d11a0b356 | ||
|
887da7b503 | ||
|
a640e08fe1 | ||
|
db62b05fdc | ||
|
d77344b725 | ||
|
0e85e2bddf | ||
|
9d67718060 | ||
|
1c845e62e3 | ||
|
724445a54a | ||
|
f7702bca13 | ||
|
2bf532a6db | ||
|
e47904dc30 | ||
|
aebaa1b70e | ||
|
d9e274eb09 | ||
|
5b5b99bb4b | ||
|
d42dac543f | ||
|
156f8e1e7d | ||
|
bea796ec85 | ||
|
625ee299f7 | ||
|
3205bd1c83 | ||
|
44c45c4ad2 | ||
|
524b57ed30 | ||
|
af4a0d5546 | ||
|
ad0cfca160 | ||
|
0c1d993b32 | ||
|
2f98046d15 | ||
|
6e33f39ae2 | ||
|
82ec583528 | ||
|
733c857c3f | ||
|
3796bd3ebe | ||
|
0f711ab694 | ||
|
ddf1d2d1a3 | ||
|
caf3968e5b | ||
|
9c4220bfd2 | ||
|
d9302db3a0 | ||
|
b717f6aeb1 | ||
|
aadca3968d | ||
|
d6ec5e7240 | ||
|
d96f5be7ac | ||
|
e90a25d0ab | ||
|
d90cf6d953 | ||
|
443212830a | ||
|
9dfd6906b9 | ||
|
7834b737eb | ||
|
f566c14ea0 | ||
|
754f14862a | ||
|
c78414f9be | ||
|
6c869353cc | ||
|
e7e267bd44 | ||
|
a65e81273b | ||
|
091166b41a | ||
|
c982493d66 | ||
|
f996f727dc | ||
|
c1e214175f |
219
.gitignore
vendored
219
.gitignore
vendored
@ -1,4 +1,215 @@
|
|||||||
FFXIVClassic Map Server/bin/Debug/packets/wireshark packets/
|
# Ignore files obtained from game client
|
||||||
FFXIVClassic Map Server/bin/
|
/data/staticactors.bin
|
||||||
FFXIVClassic Map Server/obj/
|
/data/packets/login/login*.bin
|
||||||
config.ini
|
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
build/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# DNX
|
||||||
|
project.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
## TODO: Comment the next line if you want to checkin your
|
||||||
|
## web deploy settings but do note that will include unencrypted
|
||||||
|
## passwords
|
||||||
|
#*.pubxml
|
||||||
|
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# LightSwitch generated files
|
||||||
|
GeneratedArtifacts/
|
||||||
|
_Pvt_Extensions/
|
||||||
|
ModelManifest.xml
|
477
Common Class Lib/BasePacket.cs
Normal file
477
Common Class Lib/BasePacket.cs
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
|
|
||||||
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using Ionic.Zlib;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Targets;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct BasePacketHeader
|
||||||
|
{
|
||||||
|
public byte isAuthenticated;
|
||||||
|
public byte isCompressed;
|
||||||
|
public ushort connectionType;
|
||||||
|
public ushort packetSize;
|
||||||
|
public ushort numSubpackets;
|
||||||
|
public ulong timestamp; //Miliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BasePacket
|
||||||
|
{
|
||||||
|
public const int TYPE_ZONE = 1;
|
||||||
|
public const int TYPE_CHAT = 2;
|
||||||
|
public const int BASEPACKET_SIZE = 0x10;
|
||||||
|
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||||
|
public byte[] data;
|
||||||
|
|
||||||
|
public BasePacketHeader header;
|
||||||
|
|
||||||
|
//Loads a sniffed packet from a file
|
||||||
|
public unsafe BasePacket(string path)
|
||||||
|
{
|
||||||
|
var bytes = File.ReadAllBytes(path);
|
||||||
|
|
||||||
|
if (bytes.Length < BASEPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Packet was too small");
|
||||||
|
|
||||||
|
fixed (byte* pdata = &bytes[0])
|
||||||
|
{
|
||||||
|
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes.Length < header.packetSize)
|
||||||
|
throw new OverflowException("Packet Error: Packet size didn't equal given size");
|
||||||
|
|
||||||
|
int packetSize = header.packetSize;
|
||||||
|
|
||||||
|
if (packetSize - BASEPACKET_SIZE != 0)
|
||||||
|
{
|
||||||
|
data = new byte[packetSize - BASEPACKET_SIZE];
|
||||||
|
Array.Copy(bytes, BASEPACKET_SIZE, data, 0, packetSize - BASEPACKET_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
data = new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Loads a sniffed packet from a byte array
|
||||||
|
public unsafe BasePacket(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes.Length < BASEPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Packet was too small");
|
||||||
|
|
||||||
|
fixed (byte* pdata = &bytes[0])
|
||||||
|
{
|
||||||
|
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes.Length < header.packetSize)
|
||||||
|
throw new OverflowException("Packet Error: Packet size didn't equal given size");
|
||||||
|
|
||||||
|
int packetSize = header.packetSize;
|
||||||
|
|
||||||
|
data = new byte[packetSize - BASEPACKET_SIZE];
|
||||||
|
Array.Copy(bytes, BASEPACKET_SIZE, data, 0, packetSize - BASEPACKET_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe BasePacket(byte[] bytes, ref int offset)
|
||||||
|
{
|
||||||
|
if (bytes.Length < offset + BASEPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Packet was too small");
|
||||||
|
|
||||||
|
fixed (byte* pdata = &bytes[offset])
|
||||||
|
{
|
||||||
|
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
int packetSize = header.packetSize;
|
||||||
|
|
||||||
|
if (bytes.Length < offset + header.packetSize)
|
||||||
|
throw new OverflowException("Packet Error: Packet size didn't equal given size");
|
||||||
|
|
||||||
|
data = new byte[packetSize - BASEPACKET_SIZE];
|
||||||
|
Array.Copy(bytes, offset + BASEPACKET_SIZE, data, 0, packetSize - BASEPACKET_SIZE);
|
||||||
|
|
||||||
|
offset += packetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasePacket(BasePacketHeader header, byte[] data)
|
||||||
|
{
|
||||||
|
this.header = header;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SubPacket> GetSubpackets()
|
||||||
|
{
|
||||||
|
var subpackets = new List<SubPacket>(header.numSubpackets);
|
||||||
|
|
||||||
|
var offset = 0;
|
||||||
|
|
||||||
|
while (offset < data.Length)
|
||||||
|
subpackets.Add(new SubPacket(data, ref offset));
|
||||||
|
|
||||||
|
return subpackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe BasePacketHeader GetHeader(byte[] bytes)
|
||||||
|
{
|
||||||
|
BasePacketHeader header;
|
||||||
|
if (bytes.Length < BASEPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Packet was too small");
|
||||||
|
|
||||||
|
fixed (byte* pdata = &bytes[0])
|
||||||
|
{
|
||||||
|
header = (BasePacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(BasePacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetHeaderBytes()
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf(header);
|
||||||
|
var arr = new byte[size];
|
||||||
|
|
||||||
|
var ptr = Marshal.AllocHGlobal(size);
|
||||||
|
Marshal.StructureToPtr(header, ptr, true);
|
||||||
|
Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetPacketBytes()
|
||||||
|
{
|
||||||
|
var outBytes = new byte[header.packetSize];
|
||||||
|
Array.Copy(GetHeaderBytes(), 0, outBytes, 0, BASEPACKET_SIZE);
|
||||||
|
Array.Copy(data, 0, outBytes, BASEPACKET_SIZE, data.Length);
|
||||||
|
return outBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replaces all instances of the sniffed actorID with the given one
|
||||||
|
public void ReplaceActorID(uint actorID)
|
||||||
|
{
|
||||||
|
using (var mem = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (var binWriter = new BinaryWriter(mem))
|
||||||
|
{
|
||||||
|
using (var binreader = new BinaryReader(mem))
|
||||||
|
{
|
||||||
|
while (binreader.BaseStream.Position + 4 < data.Length)
|
||||||
|
{
|
||||||
|
var read = binreader.ReadUInt32();
|
||||||
|
if (read == 0x029B2941 || read == 0x02977DC7 || read == 0x0297D2C8 || read == 0x0230d573 ||
|
||||||
|
read == 0x23317df || read == 0x23344a3 || read == 0x1730bdb || read == 0x6c)
|
||||||
|
//Original ID
|
||||||
|
{
|
||||||
|
binWriter.BaseStream.Seek(binreader.BaseStream.Position - 0x4, SeekOrigin.Begin);
|
||||||
|
binWriter.Write(actorID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replaces all instances of the sniffed actorID with the given one
|
||||||
|
public void ReplaceActorID(uint fromActorID, uint actorID)
|
||||||
|
{
|
||||||
|
using (var mem = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (var binWriter = new BinaryWriter(mem))
|
||||||
|
{
|
||||||
|
using (var binreader = new BinaryReader(mem))
|
||||||
|
{
|
||||||
|
while (binreader.BaseStream.Position + 4 < data.Length)
|
||||||
|
{
|
||||||
|
var read = binreader.ReadUInt32();
|
||||||
|
if (read == fromActorID) //Original ID
|
||||||
|
{
|
||||||
|
binWriter.BaseStream.Seek(binreader.BaseStream.Position - 0x4, SeekOrigin.Begin);
|
||||||
|
binWriter.Write(actorID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DebugPrintPacket()
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
logger.ColorDebug(
|
||||||
|
string.Format("IsAuth:{0} IsEncrypted:{1}, Size:0x{2:X}, NumSubpackets:{3}{4}{5}",
|
||||||
|
header.isAuthenticated, header.isCompressed, header.packetSize, header.numSubpackets,
|
||||||
|
Environment.NewLine, Utils.ByteArrayToHex(GetHeaderBytes())), ConsoleOutputColor.DarkYellow);
|
||||||
|
|
||||||
|
foreach (var sub in GetSubpackets())
|
||||||
|
{
|
||||||
|
sub.DebugPrintSubPacket();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Utility Functions
|
||||||
|
|
||||||
|
public static BasePacket CreatePacket(List<SubPacket> subpackets, bool isAuthed, bool isCompressed)
|
||||||
|
{
|
||||||
|
//Create Header
|
||||||
|
var header = new BasePacketHeader();
|
||||||
|
byte[] data = null;
|
||||||
|
|
||||||
|
header.isAuthenticated = isAuthed ? (byte) 1 : (byte) 0;
|
||||||
|
header.isCompressed = isCompressed ? (byte) 1 : (byte) 0;
|
||||||
|
header.numSubpackets = (ushort) subpackets.Count;
|
||||||
|
header.packetSize = BASEPACKET_SIZE;
|
||||||
|
header.timestamp = Utils.MilisUnixTimeStampUTC();
|
||||||
|
|
||||||
|
//Get packet size
|
||||||
|
foreach (var subpacket in subpackets)
|
||||||
|
header.packetSize += subpacket.header.subpacketSize;
|
||||||
|
|
||||||
|
data = new byte[header.packetSize - 0x10];
|
||||||
|
|
||||||
|
//Add Subpackets
|
||||||
|
var offset = 0;
|
||||||
|
foreach (var subpacket in subpackets)
|
||||||
|
{
|
||||||
|
var subpacketData = subpacket.GetBytes();
|
||||||
|
Array.Copy(subpacketData, 0, data, offset, subpacketData.Length);
|
||||||
|
offset += (ushort)subpacketData.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Compress this array into a new one if needed
|
||||||
|
if (isCompressed)
|
||||||
|
{
|
||||||
|
data = CompressData(data);
|
||||||
|
header.packetSize = (ushort)(BASEPACKET_SIZE + data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Assert(data != null && offset == data.Length && header.packetSize == 0x10 + offset);
|
||||||
|
|
||||||
|
var packet = new BasePacket(header, data);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BasePacket CreatePacket(SubPacket subpacket, bool isAuthed, bool isCompressed)
|
||||||
|
{
|
||||||
|
//Create Header
|
||||||
|
var header = new BasePacketHeader();
|
||||||
|
byte[] data = null;
|
||||||
|
|
||||||
|
header.isAuthenticated = isAuthed ? (byte) 1 : (byte) 0;
|
||||||
|
header.isCompressed = isCompressed ? (byte) 1 : (byte) 0;
|
||||||
|
header.numSubpackets = 1;
|
||||||
|
header.packetSize = BASEPACKET_SIZE;
|
||||||
|
header.timestamp = Utils.MilisUnixTimeStampUTC();
|
||||||
|
|
||||||
|
//Get packet size
|
||||||
|
header.packetSize += subpacket.header.subpacketSize;
|
||||||
|
|
||||||
|
data = new byte[header.packetSize - 0x10];
|
||||||
|
|
||||||
|
//Add Subpackets
|
||||||
|
byte[] subpacketData = subpacket.GetBytes();
|
||||||
|
|
||||||
|
//Compress this array into a new one if needed
|
||||||
|
if (isCompressed)
|
||||||
|
{
|
||||||
|
subpacketData = CompressData(subpacketData);
|
||||||
|
header.packetSize = (ushort)(BASEPACKET_SIZE + data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.Copy(subpacketData, 0, data, 0, subpacketData.Length);
|
||||||
|
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
|
||||||
|
var packet = new BasePacket(header, data);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BasePacket CreatePacket(byte[] data, bool isAuthed, bool isCompressed)
|
||||||
|
{
|
||||||
|
Debug.Assert(data != null);
|
||||||
|
|
||||||
|
//Create Header
|
||||||
|
var header = new BasePacketHeader();
|
||||||
|
|
||||||
|
header.isAuthenticated = isAuthed ? (byte) 1 : (byte) 0;
|
||||||
|
header.isCompressed = isCompressed ? (byte) 1 : (byte) 0;
|
||||||
|
header.numSubpackets = 1;
|
||||||
|
header.packetSize = BASEPACKET_SIZE;
|
||||||
|
header.timestamp = Utils.MilisUnixTimeStampUTC();
|
||||||
|
|
||||||
|
//Get packet size
|
||||||
|
header.packetSize += (ushort) data.Length;
|
||||||
|
|
||||||
|
//Compress this array into a new one if needed
|
||||||
|
if (isCompressed)
|
||||||
|
{
|
||||||
|
data = CompressData(data);
|
||||||
|
header.packetSize = (ushort)(BASEPACKET_SIZE + data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var packet = new BasePacket(header, data);
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">Current offset in buffer.</param>
|
||||||
|
/// <param name="buffer">Incoming buffer.</param>
|
||||||
|
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
|
||||||
|
public static BasePacket CreatePacket(ref int offset, byte[] buffer, int bytesRead)
|
||||||
|
{
|
||||||
|
BasePacket newPacket = null;
|
||||||
|
|
||||||
|
//Too small to even get length
|
||||||
|
if (bytesRead <= offset)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
|
||||||
|
|
||||||
|
//Too small to whole packet
|
||||||
|
if (bytesRead < offset + packetSize)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (buffer.Length < offset + packetSize)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newPacket = new BasePacket(buffer, ref offset);
|
||||||
|
}
|
||||||
|
catch (OverflowException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe void EncryptPacket(Blowfish blowfish, BasePacket packet)
|
||||||
|
{
|
||||||
|
var data = packet.data;
|
||||||
|
int size = packet.header.packetSize;
|
||||||
|
|
||||||
|
var offset = 0;
|
||||||
|
while (offset < data.Length)
|
||||||
|
{
|
||||||
|
if (data.Length < offset + SubPacket.SUBPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Subpacket was too small");
|
||||||
|
|
||||||
|
SubPacketHeader header;
|
||||||
|
fixed (byte* pdata = &data[offset])
|
||||||
|
{
|
||||||
|
header = (SubPacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(SubPacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.Length < offset + header.subpacketSize)
|
||||||
|
throw new OverflowException("Packet Error: Subpacket size didn't equal subpacket data");
|
||||||
|
|
||||||
|
blowfish.Encipher(data, offset + 0x10, header.subpacketSize - 0x10);
|
||||||
|
|
||||||
|
offset += header.subpacketSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe void DecryptPacket(Blowfish blowfish, ref BasePacket packet)
|
||||||
|
{
|
||||||
|
var data = packet.data;
|
||||||
|
int size = packet.header.packetSize;
|
||||||
|
|
||||||
|
var offset = 0;
|
||||||
|
while (offset < data.Length)
|
||||||
|
{
|
||||||
|
if (data.Length < offset + SubPacket.SUBPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Subpacket was too small");
|
||||||
|
|
||||||
|
SubPacketHeader header;
|
||||||
|
fixed (byte* pdata = &data[offset])
|
||||||
|
{
|
||||||
|
header = (SubPacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(SubPacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.Length < offset + header.subpacketSize)
|
||||||
|
throw new OverflowException("Packet Error: Subpacket size didn't equal subpacket data");
|
||||||
|
|
||||||
|
blowfish.Decipher(data, offset + 0x10, header.subpacketSize - 0x10);
|
||||||
|
|
||||||
|
offset += header.subpacketSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe void DecompressPacket(ref BasePacket packet)
|
||||||
|
{
|
||||||
|
using (var compressedStream = new MemoryStream(packet.data))
|
||||||
|
using (var zipStream = new ZlibStream(compressedStream, Ionic.Zlib.CompressionMode.Decompress))
|
||||||
|
using (var resultStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
zipStream.CopyTo(resultStream);
|
||||||
|
packet.data = resultStream.ToArray();
|
||||||
|
packet.header.isCompressed = 0;
|
||||||
|
packet.header.packetSize = (ushort)(BASEPACKET_SIZE + packet.data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe BasePacket CompressPacket(BasePacket uncompressedPacket)
|
||||||
|
{
|
||||||
|
using (var compressedStream = new MemoryStream(uncompressedPacket.data))
|
||||||
|
using (var zipStream = new ZlibStream(compressedStream, Ionic.Zlib.CompressionMode.Compress))
|
||||||
|
using (var resultStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
zipStream.CopyTo(resultStream);
|
||||||
|
BasePacket compressedPacket = BasePacket.CreatePacket(resultStream.ToArray(), uncompressedPacket.header.isAuthenticated == 1, true);
|
||||||
|
return compressedPacket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe byte[] CompressData(byte[] data)
|
||||||
|
{
|
||||||
|
using (var compressedStream = new MemoryStream(data))
|
||||||
|
using (var zipStream = new ZlibStream(compressedStream, Ionic.Zlib.CompressionMode.Compress))
|
||||||
|
using (var resultStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
zipStream.CopyTo(resultStream);
|
||||||
|
return resultStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LoggerExtensions
|
||||||
|
{
|
||||||
|
public static void ColorDebug(this Logger logger, string message, ConsoleOutputColor color)
|
||||||
|
{
|
||||||
|
var logEvent = new LogEventInfo(LogLevel.Debug, logger.Name, message);
|
||||||
|
logEvent.Properties["color"] = (int) color;
|
||||||
|
logger.Log(logEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,30 @@
|
|||||||
using System;
|
/*
|
||||||
using System.Collections.Generic;
|
===========================================================================
|
||||||
using System.Linq;
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FFXIVClassic_Lobby_Server.common
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
{
|
{
|
||||||
[global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
|
[global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
|
||||||
sealed class BitfieldLengthAttribute : Attribute
|
public sealed class BitfieldLengthAttribute : Attribute
|
||||||
{
|
{
|
||||||
uint length;
|
uint length;
|
||||||
|
|
||||||
@ -19,7 +36,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
public uint Length { get { return length; } }
|
public uint Length { get { return length; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PrimitiveConversion
|
public static class PrimitiveConversion
|
||||||
{
|
{
|
||||||
public static UInt32 ToUInt32<T>(T t) where T : struct
|
public static UInt32 ToUInt32<T>(T t) where T : struct
|
||||||
{
|
{
|
||||||
@ -64,7 +81,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
// Calculate a bitmask of the desired length
|
// Calculate a bitmask of the desired length
|
||||||
long mask = 0;
|
long mask = 0;
|
||||||
for (int i = 0; i < fieldLength; i++)
|
for (int i = 0; i < fieldLength; i++)
|
||||||
mask |= 1 << i;
|
mask |= 1L << i;
|
||||||
|
|
||||||
r |= ((UInt32)f.GetValue(t) & mask) << offset;
|
r |= ((UInt32)f.GetValue(t) & mask) << offset;
|
||||||
|
|
@ -1,10 +1,27 @@
|
|||||||
using System;
|
/*
|
||||||
using System.Collections.Generic;
|
===========================================================================
|
||||||
using System.Linq;
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FFXIVClassic_Lobby_Server.common
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
{
|
{
|
||||||
public class Blowfish
|
public class Blowfish
|
||||||
{
|
{
|
||||||
@ -287,7 +304,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
|
|
||||||
public Blowfish(byte[] key)
|
public Blowfish(byte[] key)
|
||||||
{
|
{
|
||||||
initializeBlowfish(key);
|
InitializeBlowfish(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Encipher(byte[] data, int offset, int length)
|
public void Encipher(byte[] data, int offset, int length)
|
||||||
@ -299,7 +316,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
{
|
{
|
||||||
uint xl = (uint)((data[i + 0]) | (data[i + 1] << 8) | (data[i + 2] << 16) | (data[i + 3] << 24));
|
uint xl = (uint)((data[i + 0]) | (data[i + 1] << 8) | (data[i + 2] << 16) | (data[i + 3] << 24));
|
||||||
uint xr = (uint)((data[i + 4]) | (data[i + 5] << 8) | (data[i + 6] << 16) | (data[i + 7] << 24));
|
uint xr = (uint)((data[i + 4]) | (data[i + 5] << 8) | (data[i + 6] << 16) | (data[i + 7] << 24));
|
||||||
blowfish_encipher(ref xl, ref xr);
|
BlowfishEncipher(ref xl, ref xr);
|
||||||
data[i + 0] = (byte)(xl >> 0);
|
data[i + 0] = (byte)(xl >> 0);
|
||||||
data[i + 1] = (byte)(xl >> 8);
|
data[i + 1] = (byte)(xl >> 8);
|
||||||
data[i + 2] = (byte)(xl >> 16);
|
data[i + 2] = (byte)(xl >> 16);
|
||||||
@ -320,7 +337,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
{
|
{
|
||||||
uint xl = (uint)((data[i + 0]) | (data[i + 1] << 8) | (data[i + 2] << 16) | (data[i + 3] << 24));
|
uint xl = (uint)((data[i + 0]) | (data[i + 1] << 8) | (data[i + 2] << 16) | (data[i + 3] << 24));
|
||||||
uint xr = (uint)((data[i + 4]) | (data[i + 5] << 8) | (data[i + 6] << 16) | (data[i + 7] << 24));
|
uint xr = (uint)((data[i + 4]) | (data[i + 5] << 8) | (data[i + 6] << 16) | (data[i + 7] << 24));
|
||||||
blowfish_decipher(ref xl, ref xr);
|
BlowfishDecipher(ref xl, ref xr);
|
||||||
data[i + 0] = (byte)(xl >> 0);
|
data[i + 0] = (byte)(xl >> 0);
|
||||||
data[i + 1] = (byte)(xl >> 8);
|
data[i + 1] = (byte)(xl >> 8);
|
||||||
data[i + 2] = (byte)(xl >> 16);
|
data[i + 2] = (byte)(xl >> 16);
|
||||||
@ -355,7 +372,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void blowfish_encipher(ref UInt32 xl, ref UInt32 xr)
|
private void BlowfishEncipher(ref UInt32 xl, ref UInt32 xr)
|
||||||
{
|
{
|
||||||
UInt32 temp;
|
UInt32 temp;
|
||||||
Int32 i;
|
Int32 i;
|
||||||
@ -378,7 +395,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void blowfish_decipher(ref UInt32 xl, ref UInt32 xr)
|
private void BlowfishDecipher(ref UInt32 xl, ref UInt32 xr)
|
||||||
{
|
{
|
||||||
UInt32 temp;
|
UInt32 temp;
|
||||||
Int32 i;
|
Int32 i;
|
||||||
@ -387,13 +404,13 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
xl = xl ^ P[i];
|
xl = xl ^ P[i];
|
||||||
xr = F(xl) ^ xr;
|
xr = F(xl) ^ xr;
|
||||||
|
|
||||||
/* Exchange xl and xr */
|
/* ExChange xl and xr */
|
||||||
temp = xl;
|
temp = xl;
|
||||||
xl = xr;
|
xl = xr;
|
||||||
xr = temp;
|
xr = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exchange xl and xr */
|
/* ExChange xl and xr */
|
||||||
temp = xl;
|
temp = xl;
|
||||||
xl = xr;
|
xl = xr;
|
||||||
xr = temp;
|
xr = temp;
|
||||||
@ -403,7 +420,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int initializeBlowfish(byte [] key)
|
private int InitializeBlowfish(byte [] key)
|
||||||
{
|
{
|
||||||
Int16 i;
|
Int16 i;
|
||||||
Int16 j;
|
Int16 j;
|
||||||
@ -437,7 +454,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
|
|
||||||
for (i = 0; i < N + 2; i += 2)
|
for (i = 0; i < N + 2; i += 2)
|
||||||
{
|
{
|
||||||
blowfish_encipher(ref datal, ref datar);
|
BlowfishEncipher(ref datal, ref datar);
|
||||||
|
|
||||||
P[i] = datal;
|
P[i] = datal;
|
||||||
P[i + 1] = datar;
|
P[i + 1] = datar;
|
||||||
@ -447,7 +464,7 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
{
|
{
|
||||||
for (j = 0; j < 256; j += 2)
|
for (j = 0; j < 256; j += 2)
|
||||||
{
|
{
|
||||||
blowfish_encipher(ref datal, ref datar);
|
BlowfishEncipher(ref datal, ref datar);
|
||||||
S[i,j] = datal;
|
S[i,j] = datal;
|
||||||
S[i,j + 1] = datar;
|
S[i,j + 1] = datar;
|
||||||
}
|
}
|
148
Common Class Lib/Common Class Lib.csproj
Normal file
148
Common Class Lib/Common Class Lib.csproj
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props') AND '$(OS)' == 'Windows_NT'" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props') AND '$(OS)' == 'Windows_NT'" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{3A3D6626-C820-4C18-8C81-64811424F20E}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Meteor.Common</RootNamespace>
|
||||||
|
<AssemblyName>Meteor.Common</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile>
|
||||||
|
</TargetFrameworkProfile>
|
||||||
|
<NuGetPackageImportStamp>792e4711</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<RegisterForComInterop>false</RegisterForComInterop>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>bin\x64\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="BouncyCastle.Crypto, Version=1.9.0.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="DotNetZip">
|
||||||
|
<HintPath>..\packages\DotNetZip.1.10.1\lib\net20\DotNetZip.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Google.Protobuf, Version=3.19.4.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Google.Protobuf.3.19.4\lib\net45\Google.Protobuf.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="K4os.Compression.LZ4, Version=1.2.6.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\K4os.Compression.LZ4.1.2.6\lib\net46\K4os.Compression.LZ4.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="K4os.Compression.LZ4.Streams, Version=1.2.6.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\K4os.Compression.LZ4.Streams.1.2.6\lib\net46\K4os.Compression.LZ4.Streams.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="K4os.Hash.xxHash, Version=1.0.6.0, Culture=neutral, PublicKeyToken=32cd54395057cec3, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\K4os.Hash.xxHash.1.0.6\lib\net46\K4os.Hash.xxHash.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MySql.Data, Version=8.0.31.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MySql.Data.8.0.31\lib\net452\MySql.Data.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\NLog.4.5.0\lib\net45\NLog.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
|
<Reference Include="System.Configuration.Install" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.IO.Compression" />
|
||||||
|
<Reference Include="System.Management" />
|
||||||
|
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.Serialization" />
|
||||||
|
<Reference Include="System.ServiceModel" />
|
||||||
|
<Reference Include="System.Transactions" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="ZstdNet, Version=1.4.5.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MySql.Data.8.0.31\lib\net452\ZstdNet.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="BasePacket.cs" />
|
||||||
|
<Compile Include="Bitfield.cs" />
|
||||||
|
<Compile Include="Blowfish.cs" />
|
||||||
|
<Compile Include="EfficientHashTables.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Sql.cs" />
|
||||||
|
<Compile Include="STA_INIFile.cs" />
|
||||||
|
<Compile Include="SubPacket.cs" />
|
||||||
|
<Compile Include="Utils.cs" />
|
||||||
|
<Compile Include="Vector3.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.0.0-beta3\build\Microsoft.Net.Compilers.props'))" />
|
||||||
|
</Target>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
179
Common Class Lib/EfficientHashTables.cs
Normal file
179
Common Class Lib/EfficientHashTables.cs
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
|
|
||||||
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
|
{
|
||||||
|
namespace EfficientHashTables
|
||||||
|
{
|
||||||
|
public class Efficient64bitHashTable<T>
|
||||||
|
{
|
||||||
|
private class element
|
||||||
|
{
|
||||||
|
public ulong _key;
|
||||||
|
public T _value;
|
||||||
|
};
|
||||||
|
private element[][] _buckets;
|
||||||
|
private uint _capacity;
|
||||||
|
|
||||||
|
public Efficient64bitHashTable()
|
||||||
|
{
|
||||||
|
_capacity = 214373; // some prime number
|
||||||
|
_buckets = new element[_capacity][];
|
||||||
|
}
|
||||||
|
public Efficient64bitHashTable(uint capacity)
|
||||||
|
{
|
||||||
|
_capacity = capacity;
|
||||||
|
_buckets = new element[_capacity][];
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Hash(ulong key)
|
||||||
|
{
|
||||||
|
return (uint)(key % _capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(ulong key, T value)
|
||||||
|
{
|
||||||
|
uint hsh = Hash(key);
|
||||||
|
element[] e;
|
||||||
|
if (_buckets[hsh] == null)
|
||||||
|
_buckets[hsh] = e = new element[1];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var elem in _buckets[hsh])
|
||||||
|
if (elem._key == key)
|
||||||
|
{
|
||||||
|
elem._value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e = new element[_buckets[hsh].Length + 1];
|
||||||
|
Array.Copy(_buckets[hsh], 0, e, 1, _buckets[hsh].Length);
|
||||||
|
_buckets[hsh] = e;
|
||||||
|
}
|
||||||
|
e[0] = new element { _key = key, _value = value };
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get(ulong key)
|
||||||
|
{
|
||||||
|
uint hsh = Hash(key);
|
||||||
|
element[] e = _buckets[hsh];
|
||||||
|
if (e == null) return default(T);
|
||||||
|
foreach (var f in e)
|
||||||
|
if (f._key == key)
|
||||||
|
return f._value;
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Has(ulong key)
|
||||||
|
{
|
||||||
|
uint hsh = Hash(key);
|
||||||
|
element[] e = _buckets[hsh];
|
||||||
|
if (e == null) return false;
|
||||||
|
foreach (var f in e)
|
||||||
|
if (f._key == key)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count()
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
foreach (var e in _buckets)
|
||||||
|
if (e != null)
|
||||||
|
r += e.Length;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Efficient32bitHashTable<T>
|
||||||
|
{
|
||||||
|
private class element
|
||||||
|
{
|
||||||
|
public uint _key;
|
||||||
|
public T _value;
|
||||||
|
};
|
||||||
|
private element[][] _buckets;
|
||||||
|
private uint _capacity;
|
||||||
|
|
||||||
|
public Efficient32bitHashTable()
|
||||||
|
{
|
||||||
|
_capacity = 463; // some prime number
|
||||||
|
_buckets = new element[_capacity][];
|
||||||
|
}
|
||||||
|
public Efficient32bitHashTable(uint capacity)
|
||||||
|
{
|
||||||
|
_capacity = capacity;
|
||||||
|
_buckets = new element[_capacity][];
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Hash(uint key)
|
||||||
|
{
|
||||||
|
return (uint)(key % _capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(uint key, T value)
|
||||||
|
{
|
||||||
|
uint hsh = Hash(key);
|
||||||
|
element[] e;
|
||||||
|
if (_buckets[hsh] == null)
|
||||||
|
_buckets[hsh] = e = new element[1];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var elem in _buckets[hsh])
|
||||||
|
if (elem._key == key)
|
||||||
|
{
|
||||||
|
elem._value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e = new element[_buckets[hsh].Length + 1];
|
||||||
|
Array.Copy(_buckets[hsh], 0, e, 1, _buckets[hsh].Length);
|
||||||
|
_buckets[hsh] = e;
|
||||||
|
}
|
||||||
|
e[0] = new element { _key = key, _value = value };
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get(uint key)
|
||||||
|
{
|
||||||
|
uint hsh = Hash(key);
|
||||||
|
element[] e = _buckets[hsh];
|
||||||
|
if (e == null) return default(T);
|
||||||
|
foreach (var f in e)
|
||||||
|
if (f._key == key)
|
||||||
|
return f._value;
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count()
|
||||||
|
{
|
||||||
|
int r = 0;
|
||||||
|
foreach (var e in _buckets)
|
||||||
|
if (e != null)
|
||||||
|
r += e.Length;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
Common Class Lib/Properties/AssemblyInfo.cs
Normal file
35
Common Class Lib/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("FFXIVClassic.Common")]
|
||||||
|
[assembly: AssemblyDescription("Common class library for FFXIVClassic project")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("ffxivclassic.fragmenterworks.com")]
|
||||||
|
[assembly: AssemblyProduct("FFXIVClassic.Common")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("3a3d6626-c820-4c18-8c81-64811424f20e")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -3,16 +3,16 @@
|
|||||||
// *******************************
|
// *******************************
|
||||||
// *** (C)2009-2013 S.T.A. snc ***
|
// *** (C)2009-2013 S.T.A. snc ***
|
||||||
// *******************************
|
// *******************************
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace STA.Settings
|
namespace Meteor.Common
|
||||||
{
|
{
|
||||||
|
public class INIFile
|
||||||
internal class INIFile
|
|
||||||
{
|
{
|
||||||
|
|
||||||
#region "Declarations"
|
#region "Declarations"
|
||||||
@ -179,7 +179,7 @@ namespace STA.Settings
|
|||||||
// *** Check if original file exists ***
|
// *** Check if original file exists ***
|
||||||
bool OriginalFileExists = File.Exists(m_FileName);
|
bool OriginalFileExists = File.Exists(m_FileName);
|
||||||
|
|
||||||
// *** Get temporary file name ***
|
// *** get temporary file name ***
|
||||||
string TmpFileName = Path.ChangeExtension(m_FileName, "$n$");
|
string TmpFileName = Path.ChangeExtension(m_FileName, "$n$");
|
||||||
|
|
||||||
// *** Copy content of original file to temporary file, replace modified values ***
|
// *** Copy content of original file to temporary file, replace modified values ***
|
||||||
@ -199,7 +199,7 @@ namespace STA.Settings
|
|||||||
// *** Open the original file ***
|
// *** Open the original file ***
|
||||||
sr = new StreamReader(m_FileName);
|
sr = new StreamReader(m_FileName);
|
||||||
|
|
||||||
// *** Read the file original content, replace changes with local cache values ***
|
// *** Read the file original content, replace Changes with local cache values ***
|
||||||
string s;
|
string s;
|
||||||
string SectionName;
|
string SectionName;
|
||||||
string Key = null;
|
string Key = null;
|
||||||
@ -337,7 +337,7 @@ namespace STA.Settings
|
|||||||
}
|
}
|
||||||
|
|
||||||
// *** Read a value from local cache ***
|
// *** Read a value from local cache ***
|
||||||
internal string GetValue(string SectionName, string Key, string DefaultValue)
|
public string GetValue(string SectionName, string Key, string DefaultValue)
|
||||||
{
|
{
|
||||||
// *** Lazy loading ***
|
// *** Lazy loading ***
|
||||||
if (m_Lazy)
|
if (m_Lazy)
|
||||||
@ -380,7 +380,7 @@ namespace STA.Settings
|
|||||||
Dictionary<string, string> Section;
|
Dictionary<string, string> Section;
|
||||||
if (!m_Sections.TryGetValue(SectionName, out Section))
|
if (!m_Sections.TryGetValue(SectionName, out Section))
|
||||||
{
|
{
|
||||||
// *** If it doesn't, add it ***
|
// *** If it Doesn't, Add it ***
|
||||||
Section = new Dictionary<string, string>();
|
Section = new Dictionary<string, string>();
|
||||||
m_Sections.Add(SectionName,Section);
|
m_Sections.Add(SectionName,Section);
|
||||||
}
|
}
|
||||||
@ -474,7 +474,7 @@ namespace STA.Settings
|
|||||||
return DefaultValue;
|
return DefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal double GetValue(string SectionName, string Key, double DefaultValue)
|
internal Double GetValue(string SectionName, string Key, Double DefaultValue)
|
||||||
{
|
{
|
||||||
string StringValue = GetValue(SectionName, Key, DefaultValue.ToString(CultureInfo.InvariantCulture));
|
string StringValue = GetValue(SectionName, Key, DefaultValue.ToString(CultureInfo.InvariantCulture));
|
||||||
double Value;
|
double Value;
|
||||||
@ -519,7 +519,7 @@ namespace STA.Settings
|
|||||||
SetValue(SectionName, Key, Value.ToString(CultureInfo.InvariantCulture));
|
SetValue(SectionName, Key, Value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void SetValue(string SectionName, string Key, double Value)
|
internal void SetValue(string SectionName, string Key, Double Value)
|
||||||
{
|
{
|
||||||
SetValue(SectionName, Key, Value.ToString(CultureInfo.InvariantCulture));
|
SetValue(SectionName, Key, Value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
33
Common Class Lib/Sql.cs
Normal file
33
Common Class Lib/Sql.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
|
|
||||||
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
|
{
|
||||||
|
// todo:
|
||||||
|
// havent decided whether it's worth wrapping every sql class
|
||||||
|
// so i'll just leave it with logger for now
|
||||||
|
public class Sql
|
||||||
|
{
|
||||||
|
public static Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
}
|
||||||
|
}
|
239
Common Class Lib/SubPacket.cs
Normal file
239
Common Class Lib/SubPacket.cs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
|
|
||||||
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using NLog;
|
||||||
|
using NLog.Targets;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct SubPacketHeader
|
||||||
|
{
|
||||||
|
public ushort subpacketSize;
|
||||||
|
public ushort type;
|
||||||
|
public uint sourceId;
|
||||||
|
public uint targetId;
|
||||||
|
public uint unknown1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct GameMessageHeader
|
||||||
|
{
|
||||||
|
public ushort unknown4; //Always 0x14
|
||||||
|
public ushort opcode;
|
||||||
|
public uint unknown5;
|
||||||
|
public uint timestamp;
|
||||||
|
public uint unknown6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubPacket
|
||||||
|
{
|
||||||
|
public const int SUBPACKET_SIZE = 0x10;
|
||||||
|
public const int GAMEMESSAGE_SIZE = 0x10;
|
||||||
|
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||||
|
public byte[] data;
|
||||||
|
public GameMessageHeader gameMessage;
|
||||||
|
|
||||||
|
public SubPacketHeader header;
|
||||||
|
|
||||||
|
public unsafe SubPacket(byte[] bytes, ref int offset)
|
||||||
|
{
|
||||||
|
if (bytes.Length < offset + SUBPACKET_SIZE)
|
||||||
|
throw new OverflowException("Packet Error: Subpacket was too small");
|
||||||
|
|
||||||
|
fixed (byte* pdata = &bytes[offset])
|
||||||
|
{
|
||||||
|
header = (SubPacketHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(SubPacketHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.type == 0x3)
|
||||||
|
{
|
||||||
|
fixed (byte* pdata = &bytes[offset + SUBPACKET_SIZE])
|
||||||
|
{
|
||||||
|
gameMessage =
|
||||||
|
(GameMessageHeader) Marshal.PtrToStructure(new IntPtr(pdata), typeof(GameMessageHeader));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes.Length < offset + header.subpacketSize)
|
||||||
|
throw new OverflowException("Packet Error: Subpacket size didn't equal subpacket data");
|
||||||
|
|
||||||
|
if (header.type == 0x3)
|
||||||
|
{
|
||||||
|
data = new byte[header.subpacketSize - SUBPACKET_SIZE - GAMEMESSAGE_SIZE];
|
||||||
|
Array.Copy(bytes, offset + SUBPACKET_SIZE + GAMEMESSAGE_SIZE, data, 0, data.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = new byte[header.subpacketSize - SUBPACKET_SIZE];
|
||||||
|
Array.Copy(bytes, offset + SUBPACKET_SIZE, data, 0, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += header.subpacketSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubPacket(ushort opcode, uint sourceId, byte[] data) : this(true, opcode, sourceId, data) { }
|
||||||
|
|
||||||
|
public SubPacket(bool isGameMessage, ushort opcode, uint sourceId, byte[] data)
|
||||||
|
{
|
||||||
|
header = new SubPacketHeader();
|
||||||
|
|
||||||
|
if (isGameMessage)
|
||||||
|
{
|
||||||
|
gameMessage = new GameMessageHeader();
|
||||||
|
gameMessage.opcode = opcode;
|
||||||
|
gameMessage.timestamp = Utils.UnixTimeStampUTC();
|
||||||
|
gameMessage.unknown4 = 0x14;
|
||||||
|
gameMessage.unknown5 = 0x00;
|
||||||
|
gameMessage.unknown6 = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.sourceId = sourceId;
|
||||||
|
header.targetId = 0;
|
||||||
|
|
||||||
|
if (isGameMessage)
|
||||||
|
header.type = 0x03;
|
||||||
|
else
|
||||||
|
header.type = opcode;
|
||||||
|
|
||||||
|
header.unknown1 = 0x00;
|
||||||
|
|
||||||
|
this.data = data;
|
||||||
|
|
||||||
|
header.subpacketSize = (ushort) (SUBPACKET_SIZE + data.Length);
|
||||||
|
|
||||||
|
if (isGameMessage)
|
||||||
|
header.subpacketSize += GAMEMESSAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubPacket(SubPacket original, uint newTargetId)
|
||||||
|
{
|
||||||
|
header = new SubPacketHeader();
|
||||||
|
gameMessage = original.gameMessage;
|
||||||
|
header.subpacketSize = original.header.subpacketSize;
|
||||||
|
header.type = original.header.type;
|
||||||
|
header.sourceId = original.header.sourceId;
|
||||||
|
header.targetId = newTargetId;
|
||||||
|
data = original.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTargetId(uint target)
|
||||||
|
{
|
||||||
|
this.header.targetId = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetHeaderBytes()
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf(header);
|
||||||
|
var arr = new byte[size];
|
||||||
|
|
||||||
|
var ptr = Marshal.AllocHGlobal(size);
|
||||||
|
Marshal.StructureToPtr(header, ptr, true);
|
||||||
|
Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetGameMessageBytes()
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf(gameMessage);
|
||||||
|
var arr = new byte[size];
|
||||||
|
|
||||||
|
var ptr = Marshal.AllocHGlobal(size);
|
||||||
|
Marshal.StructureToPtr(gameMessage, ptr, true);
|
||||||
|
Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetBytes()
|
||||||
|
{
|
||||||
|
var outBytes = new byte[header.subpacketSize];
|
||||||
|
Array.Copy(GetHeaderBytes(), 0, outBytes, 0, SUBPACKET_SIZE);
|
||||||
|
|
||||||
|
if (header.type == 0x3)
|
||||||
|
Array.Copy(GetGameMessageBytes(), 0, outBytes, SUBPACKET_SIZE, GAMEMESSAGE_SIZE);
|
||||||
|
|
||||||
|
Array.Copy(data, 0, outBytes, SUBPACKET_SIZE + (header.type == 0x3 ? GAMEMESSAGE_SIZE : 0), data.Length);
|
||||||
|
return outBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a packet from the incoming buffer + offset. If a packet can be built, it is returned else null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">Current offset in buffer.</param>
|
||||||
|
/// <param name="buffer">Incoming buffer.</param>
|
||||||
|
/// <returns>Returns either a BasePacket or null if not enough data.</returns>
|
||||||
|
public static SubPacket CreatePacket(ref int offset, byte[] buffer, int bytesRead)
|
||||||
|
{
|
||||||
|
SubPacket newPacket = null;
|
||||||
|
|
||||||
|
//Too small to even get length
|
||||||
|
if (bytesRead <= offset)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
ushort packetSize = BitConverter.ToUInt16(buffer, offset);
|
||||||
|
|
||||||
|
//Too small to whole packet
|
||||||
|
if (bytesRead < offset + packetSize)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (buffer.Length < offset + packetSize)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newPacket = new SubPacket(buffer, ref offset);
|
||||||
|
}
|
||||||
|
catch (OverflowException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DebugPrintSubPacket()
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
logger.ColorDebug(
|
||||||
|
string.Format("Size:0x{0:X} Opcode:0x{1:X}{2}{3}", header.subpacketSize, gameMessage.opcode,
|
||||||
|
Environment.NewLine,
|
||||||
|
Utils.ByteArrayToHex(GetHeaderBytes())), ConsoleOutputColor.DarkRed);
|
||||||
|
|
||||||
|
if (header.type == 0x03)
|
||||||
|
{
|
||||||
|
logger.ColorDebug(Utils.ByteArrayToHex(GetGameMessageBytes(), SUBPACKET_SIZE),
|
||||||
|
ConsoleOutputColor.DarkRed);
|
||||||
|
|
||||||
|
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE + GAMEMESSAGE_SIZE),
|
||||||
|
ConsoleOutputColor.DarkMagenta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logger.ColorDebug(Utils.ByteArrayToHex(data, SUBPACKET_SIZE),
|
||||||
|
ConsoleOutputColor.DarkMagenta);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
487
Common Class Lib/Utils.cs
Normal file
487
Common Class Lib/Utils.cs
Normal file
@ -0,0 +1,487 @@
|
|||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
|
|
||||||
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
|
{
|
||||||
|
public static class Utils
|
||||||
|
{
|
||||||
|
private static readonly uint[] _lookup32 = CreateLookup32();
|
||||||
|
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
private static uint[] CreateLookup32()
|
||||||
|
{
|
||||||
|
var result = new uint[256];
|
||||||
|
for (var i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
var s = i.ToString("X2");
|
||||||
|
result[i] = s[0] + ((uint)s[1] << 16);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ByteArrayToHex(byte[] bytes, int offset = 0, int bytesPerLine = 16)
|
||||||
|
{
|
||||||
|
if (bytes == null)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hexChars = "0123456789ABCDEF".ToCharArray();
|
||||||
|
|
||||||
|
var offsetBlock = 8 + 3;
|
||||||
|
var byteBlock = offsetBlock + bytesPerLine * 3 + (bytesPerLine - 1) / 8 + 2;
|
||||||
|
var lineLength = byteBlock + bytesPerLine + Environment.NewLine.Length;
|
||||||
|
|
||||||
|
var line = (new string(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray();
|
||||||
|
var numLines = (bytes.Length + bytesPerLine - 1) / bytesPerLine;
|
||||||
|
|
||||||
|
var sb = new StringBuilder(numLines * lineLength);
|
||||||
|
|
||||||
|
for (var i = 0; i < bytes.Length; i += bytesPerLine)
|
||||||
|
{
|
||||||
|
var h = i + offset;
|
||||||
|
|
||||||
|
line[0] = hexChars[(h >> 28) & 0xF];
|
||||||
|
line[1] = hexChars[(h >> 24) & 0xF];
|
||||||
|
line[2] = hexChars[(h >> 20) & 0xF];
|
||||||
|
line[3] = hexChars[(h >> 16) & 0xF];
|
||||||
|
line[4] = hexChars[(h >> 12) & 0xF];
|
||||||
|
line[5] = hexChars[(h >> 8) & 0xF];
|
||||||
|
line[6] = hexChars[(h >> 4) & 0xF];
|
||||||
|
line[7] = hexChars[(h >> 0) & 0xF];
|
||||||
|
|
||||||
|
var hexColumn = offsetBlock;
|
||||||
|
var charColumn = byteBlock;
|
||||||
|
|
||||||
|
for (var j = 0; j < bytesPerLine; j++)
|
||||||
|
{
|
||||||
|
if (j > 0 && (j & 7) == 0)
|
||||||
|
{
|
||||||
|
hexColumn++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + j >= bytes.Length)
|
||||||
|
{
|
||||||
|
line[hexColumn] = ' ';
|
||||||
|
line[hexColumn + 1] = ' ';
|
||||||
|
line[charColumn] = ' ';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var by = bytes[i + j];
|
||||||
|
line[hexColumn] = hexChars[(by >> 4) & 0xF];
|
||||||
|
line[hexColumn + 1] = hexChars[by & 0xF];
|
||||||
|
line[charColumn] = by < 32 ? '.' : (char)by;
|
||||||
|
}
|
||||||
|
|
||||||
|
hexColumn += 3;
|
||||||
|
charColumn++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString().TrimEnd(Environment.NewLine.ToCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint UnixTimeStampUTC(DateTime? time = null)
|
||||||
|
{
|
||||||
|
uint unixTimeStamp;
|
||||||
|
var currentTime = time ?? DateTime.Now;
|
||||||
|
var zuluTime = currentTime.ToUniversalTime();
|
||||||
|
var unixEpoch = new DateTime(1970, 1, 1);
|
||||||
|
unixTimeStamp = (uint)zuluTime.Subtract(unixEpoch).TotalSeconds;
|
||||||
|
|
||||||
|
return unixTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ulong MilisUnixTimeStampUTC(DateTime? time = null)
|
||||||
|
{
|
||||||
|
ulong unixTimeStamp;
|
||||||
|
var currentTime = time ?? DateTime.Now;
|
||||||
|
var zuluTime = currentTime.ToUniversalTime();
|
||||||
|
var unixEpoch = new DateTime(1970, 1, 1);
|
||||||
|
unixTimeStamp = (ulong)zuluTime.Subtract(unixEpoch).TotalMilliseconds;
|
||||||
|
|
||||||
|
return unixTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime UnixTimeStampToDateTime(uint timestamp)
|
||||||
|
{
|
||||||
|
return epoch.AddSeconds(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ulong SwapEndian(ulong input)
|
||||||
|
{
|
||||||
|
return 0x00000000000000FF & (input >> 56) |
|
||||||
|
0x000000000000FF00 & (input >> 40) |
|
||||||
|
0x0000000000FF0000 & (input >> 24) |
|
||||||
|
0x00000000FF000000 & (input >> 8) |
|
||||||
|
0x000000FF00000000 & (input << 8) |
|
||||||
|
0x0000FF0000000000 & (input << 24) |
|
||||||
|
0x00FF000000000000 & (input << 40) |
|
||||||
|
0xFF00000000000000 & (input << 56);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint SwapEndian(uint input)
|
||||||
|
{
|
||||||
|
return ((input >> 24) & 0xff) |
|
||||||
|
((input << 8) & 0xff0000) |
|
||||||
|
((input >> 8) & 0xff00) |
|
||||||
|
((input << 24) & 0xff000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SwapEndian(int input)
|
||||||
|
{
|
||||||
|
var inputAsUint = (uint)input;
|
||||||
|
|
||||||
|
input = (int)
|
||||||
|
(((inputAsUint >> 24) & 0xff) |
|
||||||
|
((inputAsUint << 8) & 0xff0000) |
|
||||||
|
((inputAsUint >> 8) & 0xff00) |
|
||||||
|
((inputAsUint << 24) & 0xff000000));
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ushort SwapEndian(ushort input)
|
||||||
|
{
|
||||||
|
return (ushort)(((input << 8) & 0xff00) |
|
||||||
|
((input >> 8) & 0x00ff));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint MurmurHash2(string key, uint seed)
|
||||||
|
{
|
||||||
|
// 'm' and 'r' are mixing constants generated offline.
|
||||||
|
// They're not really 'magic', they just happen to work well.
|
||||||
|
|
||||||
|
var data = Encoding.ASCII.GetBytes(key);
|
||||||
|
const uint m = 0x5bd1e995;
|
||||||
|
const int r = 24;
|
||||||
|
var len = key.Length;
|
||||||
|
var dataIndex = len - 4;
|
||||||
|
|
||||||
|
// Initialize the hash to a 'random' value
|
||||||
|
|
||||||
|
var h = seed ^ (uint)len;
|
||||||
|
|
||||||
|
// Mix 4 bytes at a time into the hash
|
||||||
|
|
||||||
|
|
||||||
|
while (len >= 4)
|
||||||
|
{
|
||||||
|
h *= m;
|
||||||
|
|
||||||
|
var k = (uint)BitConverter.ToInt32(data, dataIndex);
|
||||||
|
k = ((k >> 24) & 0xff) | // move byte 3 to byte 0
|
||||||
|
((k << 8) & 0xff0000) | // move byte 1 to byte 2
|
||||||
|
((k >> 8) & 0xff00) | // move byte 2 to byte 1
|
||||||
|
((k << 24) & 0xff000000); // byte 0 to byte 3
|
||||||
|
|
||||||
|
k *= m;
|
||||||
|
k ^= k >> r;
|
||||||
|
k *= m;
|
||||||
|
|
||||||
|
h ^= k;
|
||||||
|
|
||||||
|
dataIndex -= 4;
|
||||||
|
len -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the last few bytes of the input array
|
||||||
|
switch (len)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
h ^= (uint)data[0] << 16;
|
||||||
|
goto case 2;
|
||||||
|
case 2:
|
||||||
|
h ^= (uint)data[len - 2] << 8;
|
||||||
|
goto case 1;
|
||||||
|
case 1:
|
||||||
|
h ^= data[len - 1];
|
||||||
|
h *= m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
// Do a few final mixes of the hash to ensure the last few
|
||||||
|
// bytes are well-incorporated.
|
||||||
|
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= m;
|
||||||
|
h ^= h >> 15;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ConvertBoolArrayToBinaryStream(bool[] array)
|
||||||
|
{
|
||||||
|
var data = new byte[array.Length / 8 + (array.Length % 8 != 0 ? 1 : 0)];
|
||||||
|
|
||||||
|
var dataCounter = 0;
|
||||||
|
for (var i = 0; i < array.Length; i += 8)
|
||||||
|
{
|
||||||
|
for (var bitCount = 0; bitCount < 8; bitCount++)
|
||||||
|
{
|
||||||
|
if (i + bitCount >= array.Length)
|
||||||
|
break;
|
||||||
|
data[dataCounter] = (byte)(((array[i + bitCount] ? 1 : 0) << 7 - bitCount) | data[dataCounter]);
|
||||||
|
}
|
||||||
|
dataCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToStringBase63(int number)
|
||||||
|
{
|
||||||
|
var lookup = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
var secondDigit = lookup.Substring((int)Math.Floor(number / (double)lookup.Length), 1);
|
||||||
|
var firstDigit = lookup.Substring(number % lookup.Length, 1);
|
||||||
|
|
||||||
|
return secondDigit + firstDigit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReadNullTermString(BinaryReader reader, int maxSize = 0x20)
|
||||||
|
{
|
||||||
|
return Encoding.ASCII.GetString(reader.ReadBytes(maxSize)).Trim(new[] { '\0' });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteNullTermString(BinaryWriter writer, string value, int maxSize = 0x20)
|
||||||
|
{
|
||||||
|
writer.Write(Encoding.ASCII.GetBytes(value), 0, Encoding.ASCII.GetByteCount(value) >= maxSize ? maxSize : Encoding.ASCII.GetByteCount(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FFXIVLoginStringDecodeBinary(string path)
|
||||||
|
{
|
||||||
|
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||||
|
byte[] data = File.ReadAllBytes(path);
|
||||||
|
int offset = 0x5405a;
|
||||||
|
//int offset = 0x5425d;
|
||||||
|
//int offset = 0x53ea0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
uint key = (uint)data[offset + 0] << 8 | data[offset + 1];
|
||||||
|
uint key2 = data[offset + 2];
|
||||||
|
key = RotateRight(key, 1) & 0xFFFF;
|
||||||
|
key -= 0x22AF;
|
||||||
|
key &= 0xFFFF;
|
||||||
|
key2 = key2 ^ key;
|
||||||
|
key = RotateRight(key, 1) & 0xFFFF;
|
||||||
|
key -= 0x22AF;
|
||||||
|
key &= 0xFFFF;
|
||||||
|
uint finalKey = key;
|
||||||
|
key = data[offset + 3];
|
||||||
|
uint count = (key2 & 0xFF) << 8;
|
||||||
|
key = key ^ finalKey;
|
||||||
|
key &= 0xFF;
|
||||||
|
count |= key;
|
||||||
|
|
||||||
|
int count2 = 0;
|
||||||
|
while (count != 0)
|
||||||
|
{
|
||||||
|
uint encrypted = data[offset + 4 + count2];
|
||||||
|
finalKey = RotateRight(finalKey, 1) & 0xFFFF;
|
||||||
|
finalKey -= 0x22AF;
|
||||||
|
finalKey &= 0xFFFF;
|
||||||
|
encrypted = encrypted ^ (finalKey & 0xFF);
|
||||||
|
|
||||||
|
result += (char)encrypted;
|
||||||
|
count--;
|
||||||
|
count2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += 4 + count2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FFXIVLoginStringDecode(byte[] data)
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
uint key = (uint)data[0] << 8 | data[1];
|
||||||
|
uint key2 = data[2];
|
||||||
|
key = RotateRight(key, 1) & 0xFFFF;
|
||||||
|
key -= 0x22AF;
|
||||||
|
key2 = key2 ^ key;
|
||||||
|
key = RotateRight(key, 1) & 0xFFFF;
|
||||||
|
key -= 0x22AF;
|
||||||
|
uint finalKey = key;
|
||||||
|
key = data[3];
|
||||||
|
uint count = (key2 & 0xFF) << 8;
|
||||||
|
key = key ^ finalKey;
|
||||||
|
key &= 0xFF;
|
||||||
|
count |= key;
|
||||||
|
|
||||||
|
int count2 = 0;
|
||||||
|
while (count != 0)
|
||||||
|
{
|
||||||
|
uint encrypted = data[4 + count2];
|
||||||
|
finalKey = RotateRight(finalKey, 1) & 0xFFFF;
|
||||||
|
finalKey -= 0x22AF;
|
||||||
|
encrypted = encrypted ^ (finalKey & 0xFF);
|
||||||
|
result += (char)encrypted;
|
||||||
|
count--;
|
||||||
|
count2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] FFXIVLoginStringEncode(uint key, string text)
|
||||||
|
{
|
||||||
|
key = key & 0xFFFF;
|
||||||
|
|
||||||
|
uint count = 0;
|
||||||
|
byte[] asciiBytes = Encoding.ASCII.GetBytes(text);
|
||||||
|
byte[] result = new byte[4 + text.Length];
|
||||||
|
for (count = 0; count < text.Length; count++)
|
||||||
|
{
|
||||||
|
result[result.Length - count - 1] = (byte)(asciiBytes[asciiBytes.Length - count - 1] ^ (key & 0xFF));
|
||||||
|
key += 0x22AF;
|
||||||
|
key &= 0xFFFF;
|
||||||
|
key = RotateLeft(key, 1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = count ^ key;
|
||||||
|
result[3] = (byte)(count & 0xFF);
|
||||||
|
|
||||||
|
key += 0x22AF & 0xFFFF;
|
||||||
|
key = RotateLeft(key, 1) & 0xFFFF;
|
||||||
|
|
||||||
|
result[2] = (byte)(key & 0xFF);
|
||||||
|
|
||||||
|
key += 0x22AF & 0xFFFF;
|
||||||
|
key = RotateLeft(key, 1) & 0xFFFF;
|
||||||
|
|
||||||
|
|
||||||
|
result[1] = (byte)(key & 0xFF);
|
||||||
|
result[0] = (byte)((key >> 8) & 0xFF);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint RotateLeft(uint value, int bits)
|
||||||
|
{
|
||||||
|
return (value << bits) | (value >> (16 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint RotateRight(uint value, int bits)
|
||||||
|
{
|
||||||
|
return (value >> bits) | (value << (16 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Clamp<T>(this T value, T min, T max) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(min) < 0)
|
||||||
|
return min;
|
||||||
|
else if (value.CompareTo(max) > 0)
|
||||||
|
return max;
|
||||||
|
else
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Min<T>(this T value, T min) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
if (value.CompareTo(min) > 0)
|
||||||
|
return min;
|
||||||
|
else
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Max<T>(this T value, T max) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
|
||||||
|
if (value.CompareTo(max) < 0)
|
||||||
|
return max;
|
||||||
|
else
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float DistanceSquared(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return DistanceSquared(lhs.X, lhs.Y, lhs.Z, rhs.X, rhs.Y, rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Distance(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return Distance(lhs.X, lhs.Y, lhs.Z, rhs.X, rhs.Y, rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Distance(float x, float y, float z, float x2, float y2, float z2)
|
||||||
|
{
|
||||||
|
if (x == x2 && y == y2 && z == z2)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return (float)Math.Sqrt(DistanceSquared(x, y, z, x2, y2, z2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float DistanceSquared(float x, float y, float z, float x2, float y2, float z2)
|
||||||
|
{
|
||||||
|
if (x == x2 && y == y2 && z == z2)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
// todo: my maths is shit
|
||||||
|
var dx = x - x2;
|
||||||
|
var dy = y - y2;
|
||||||
|
var dz = z - z2;
|
||||||
|
|
||||||
|
return dx * dx + dy * dy + dz * dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Distance of just the x and z valeus, ignoring y
|
||||||
|
public static float XZDistanceSquared(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return XZDistanceSquared(lhs.X, lhs.Z, rhs.X, rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float XZDistance(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return XZDistance(lhs.X, lhs.Z, rhs.X, rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float XZDistance(float x, float z, float x2, float z2)
|
||||||
|
{
|
||||||
|
if (x == x2 && z == z2)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return (float)Math.Sqrt(XZDistanceSquared(x, z, x2, z2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static float XZDistanceSquared(float x, float z, float x2, float z2)
|
||||||
|
{
|
||||||
|
if (x == x2 && z == z2)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
// todo: mz maths is shit
|
||||||
|
var dx = x - x2;
|
||||||
|
var dz = z - z2;
|
||||||
|
|
||||||
|
return dx * dx + dz * dz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
180
Common Class Lib/Vector3.cs
Normal file
180
Common Class Lib/Vector3.cs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
===========================================================================
|
||||||
|
Copyright (C) 2015-2019 Project Meteor Dev Team
|
||||||
|
|
||||||
|
This file is part of Project Meteor Server.
|
||||||
|
|
||||||
|
Project Meteor Server is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Project Meteor Server 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Meteor.Common
|
||||||
|
{
|
||||||
|
public class Vector3
|
||||||
|
{
|
||||||
|
public float X;
|
||||||
|
public float Y;
|
||||||
|
public float Z;
|
||||||
|
public static Vector3 Zero = new Vector3();
|
||||||
|
|
||||||
|
public Vector3(float x, float y, float z)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3()
|
||||||
|
{
|
||||||
|
X = 0.0f;
|
||||||
|
Y = 0.0f;
|
||||||
|
Z = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 operator +(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
Vector3 newVec = new Vector3(lhs.X, lhs.Y, lhs.Z);
|
||||||
|
newVec.X += rhs.X;
|
||||||
|
newVec.Y += rhs.Y;
|
||||||
|
newVec.Z += rhs.Z;
|
||||||
|
return newVec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 operator -(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 operator *(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return new Vector3(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 operator *(float scalar, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return new Vector3(scalar * rhs.X, scalar * rhs.Y, scalar * rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 operator /(Vector3 lhs, float scalar)
|
||||||
|
{
|
||||||
|
return new Vector3(lhs.X / scalar, lhs.Y / scalar, lhs.Z / scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return !(lhs?.X == rhs?.X && lhs?.Y == rhs?.Y && lhs?.Z == rhs?.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return (lhs?.X == rhs?.X && lhs?.Y == rhs?.Y && lhs?.Z == rhs?.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Length()
|
||||||
|
{
|
||||||
|
return (float)Math.Sqrt(this.LengthSquared());
|
||||||
|
}
|
||||||
|
|
||||||
|
public float LengthSquared()
|
||||||
|
{
|
||||||
|
return (this.X * this.X) + (this.Y * this.Y) + (this.Z * this.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Dot(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return (lhs.X * rhs.X) + (lhs.Y * rhs.Y) + (lhs.Z * rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetAngle(Vector3 lhs, Vector3 rhs)
|
||||||
|
{
|
||||||
|
return GetAngle(lhs.X, lhs.Z, rhs.X, rhs.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetAngle(float x, float z, float x2, float z2)
|
||||||
|
{
|
||||||
|
if (x == x2)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
var angle = (float)(Math.Atan((z2 - z) / (x2 - x)));
|
||||||
|
return (float)(x > x2 ? angle + Math.PI : angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 NewHorizontalVector(float angle, float extents)
|
||||||
|
{
|
||||||
|
var newVec = new Vector3();
|
||||||
|
newVec.Y = this.Y;
|
||||||
|
newVec.X = this.X + (float)Math.Cos(angle) * extents;
|
||||||
|
newVec.Z = this.Z + (float)Math.Sin(angle) * extents;
|
||||||
|
|
||||||
|
return newVec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsWithinCircle(Vector3 center, float maxRadius, float minRadius)
|
||||||
|
{
|
||||||
|
if (this.X == center.X && this.Z == center.Z)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
float diffX = center.X - this.X;
|
||||||
|
float diffZ = center.Z - this.Z;
|
||||||
|
|
||||||
|
float distance = Utils.XZDistance(center.X, center.Z, X, Z);
|
||||||
|
|
||||||
|
return distance <= maxRadius && distance >= minRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsWithinBox(Vector3 upperLeftCorner, Vector3 lowerRightCorner)
|
||||||
|
{
|
||||||
|
return upperLeftCorner.X <= this.X &&
|
||||||
|
upperLeftCorner.Y <= this.Y &&
|
||||||
|
upperLeftCorner.Z <= this.Z &&
|
||||||
|
lowerRightCorner.X >= this.X &&
|
||||||
|
lowerRightCorner.Y >= this.Y &&
|
||||||
|
lowerRightCorner.Z >= this.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Checks if this vector is in a cone, note it doesn't check for distance
|
||||||
|
public bool IsWithinCone(Vector3 coneCenter, float coneRotation, float coneAngle)
|
||||||
|
{
|
||||||
|
float angleToTarget = GetAngle(coneCenter, this);
|
||||||
|
float halfAngleOfAoe = (float) (coneAngle * Math.PI / 2);
|
||||||
|
float rotationToAdd = coneRotation + halfAngleOfAoe;
|
||||||
|
|
||||||
|
//This is the angle relative to the lower angle of the cone
|
||||||
|
angleToTarget = (angleToTarget + rotationToAdd - (0.5f * (float)Math.PI)) % (2 * (float) Math.PI);
|
||||||
|
|
||||||
|
//If the relative angle is less than the total angle of the cone, the target is inside the cone
|
||||||
|
return angleToTarget >= 0 && angleToTarget <= (coneAngle * Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
var vector = obj as Vector3;
|
||||||
|
return vector != null &&
|
||||||
|
X == vector.X &&
|
||||||
|
Y == vector.Y &&
|
||||||
|
Z == vector.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var hashCode = -307843816;
|
||||||
|
hashCode = hashCode * -1521134295 + X.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Y.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Z.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Common Class Lib/app.config
Normal file
13
Common Class Lib/app.config
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /></startup>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
15
Common Class Lib/packages.config
Normal file
15
Common Class Lib/packages.config
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="DotNetZip" version="1.10.1" targetFramework="net45" />
|
||||||
|
<package id="Google.Protobuf" version="3.19.4" targetFramework="net472" />
|
||||||
|
<package id="K4os.Compression.LZ4" version="1.2.6" targetFramework="net472" />
|
||||||
|
<package id="K4os.Compression.LZ4.Streams" version="1.2.6" targetFramework="net472" />
|
||||||
|
<package id="K4os.Hash.xxHash" version="1.0.6" targetFramework="net472" />
|
||||||
|
<package id="MySql.Data" version="8.0.31" targetFramework="net472" />
|
||||||
|
<package id="NLog" version="4.5.0" targetFramework="net451" />
|
||||||
|
<package id="Portable.BouncyCastle" version="1.9.0" targetFramework="net472" />
|
||||||
|
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
|
||||||
|
<package id="System.Memory" version="4.5.4" targetFramework="net472" />
|
||||||
|
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
|
||||||
|
<package id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" targetFramework="net472" />
|
||||||
|
</packages>
|
11
Data/lobby_config.ini
Normal file
11
Data/lobby_config.ini
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[General]
|
||||||
|
server_ip=0.0.0.0
|
||||||
|
showtimestamp = true
|
||||||
|
|
||||||
|
[Database]
|
||||||
|
worldid=1
|
||||||
|
host=127.0.0.1
|
||||||
|
port=3306
|
||||||
|
database=ffxiv_server
|
||||||
|
username=root
|
||||||
|
password=
|
11
Data/map_config.ini
Normal file
11
Data/map_config.ini
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[General]
|
||||||
|
server_ip=127.0.0.1
|
||||||
|
showtimestamp = true
|
||||||
|
|
||||||
|
[Database]
|
||||||
|
worldid=1
|
||||||
|
host=127.0.0.1
|
||||||
|
port=3306
|
||||||
|
database=ffxiv_server
|
||||||
|
username=root
|
||||||
|
password=
|
110
Data/postbuild_copy.bat
Normal file
110
Data/postbuild_copy.bat
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
REM SETLOCAL
|
||||||
|
SET CWD = %~dp0
|
||||||
|
|
||||||
|
REM Echo Launch dir: "%~dp0"
|
||||||
|
REM Echo Current dir: "%CD%"
|
||||||
|
|
||||||
|
REM =============
|
||||||
|
REM COPY LOBBY CONFIG
|
||||||
|
REM =============
|
||||||
|
REM Required files: lobby_config.ini
|
||||||
|
|
||||||
|
SET /a foundlfolders = 0
|
||||||
|
|
||||||
|
if exist "%~dp0\..\Lobby Server\bin\Debug" (
|
||||||
|
SET /a foundlfolders = %foundlfolders% + 1
|
||||||
|
echo Found Lobby Debug build folder.
|
||||||
|
|
||||||
|
echo Copying lobby_config.ini if needed...
|
||||||
|
xcopy lobby_config.ini "%~dp0\..\Lobby Server\bin\Debug\" /d /y /q
|
||||||
|
)
|
||||||
|
|
||||||
|
if exist "%~dp0\..\Lobby Server\bin\Release" (
|
||||||
|
SET /a foundlfolders = %foundlfolders% + 1
|
||||||
|
echo Found Lobby Release build folder.
|
||||||
|
|
||||||
|
echo Copying lobby_config.ini if needed...
|
||||||
|
xcopy lobby_config.ini "%~dp0\..\Lobby Server\bin\Release\" /d /y /q
|
||||||
|
)
|
||||||
|
|
||||||
|
if %foundlfolders% LSS 1 (
|
||||||
|
echo Could not find debug or release folder for the Lobby server. Please compile the project first!
|
||||||
|
)
|
||||||
|
|
||||||
|
REM =============
|
||||||
|
REM COPY WORLD CONFIG
|
||||||
|
REM =============
|
||||||
|
REM Required files: world_config.ini
|
||||||
|
|
||||||
|
SET /a foundwfolders = 0
|
||||||
|
|
||||||
|
if exist "%~dp0\..\World Server\bin\Debug" (
|
||||||
|
SET /a foundwfolders = %foundwfolders% + 1
|
||||||
|
echo Found World Debug build folder.
|
||||||
|
|
||||||
|
echo Copying world_config.ini if needed...
|
||||||
|
xcopy world_config.ini "%~dp0\..\World Server\bin\Debug\" /d /y /q
|
||||||
|
)
|
||||||
|
|
||||||
|
if exist "%~dp0\..\World Server\bin\Release" (
|
||||||
|
SET /a foundwfolders = %foundwfolders% + 1
|
||||||
|
echo Found World Release build folder.
|
||||||
|
|
||||||
|
echo Copying world_config.ini if needed...
|
||||||
|
xcopy world_config.ini "%~dp0\..\World Server\bin\Release\" /d /y /q
|
||||||
|
)
|
||||||
|
|
||||||
|
if %foundwfolders% LSS 1 (
|
||||||
|
echo Could not find debug or release folder for the World server. Please compile the project first!
|
||||||
|
)
|
||||||
|
|
||||||
|
REM =============
|
||||||
|
REM COPY MAP CONFIG
|
||||||
|
REM =============
|
||||||
|
REM Required files: map_config.ini staticactors.bin scripts/
|
||||||
|
|
||||||
|
SET /a foundmfolders = 0
|
||||||
|
|
||||||
|
if exist "%~dp0\..\Map Server\bin\Debug" (
|
||||||
|
SET /a foundmfolders = %foundmfolders% + 1
|
||||||
|
echo Found Map Debug build folder.
|
||||||
|
|
||||||
|
echo Copying map_config.ini if needed...
|
||||||
|
xcopy map_config.ini "%~dp0\..\Map Server\bin\Debug\" /d /y /q
|
||||||
|
|
||||||
|
if exist staticactors.bin (
|
||||||
|
echo Copying staticactors.bin if needed...
|
||||||
|
xcopy staticactors.bin "%~dp0\..\Map Server\bin\Debug\" /d /y /q
|
||||||
|
) else (
|
||||||
|
echo Cannot copy the staticactors.bin file because it doesn't exist in data\
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
echo Copying scripts folder if needed...
|
||||||
|
xcopy scripts "%~dp0\..\Map Server\bin\Debug\scripts\" /e /d /y /s /q
|
||||||
|
)
|
||||||
|
|
||||||
|
if exist "%~dp0\..\Map Server\bin\Release" (
|
||||||
|
SET /a foundmfolders = %foundmfolders% + 1
|
||||||
|
echo Found Map Release build folder.
|
||||||
|
|
||||||
|
echo Copying map_config.ini if needed...
|
||||||
|
xcopy map_config.ini "%~dp0\..\Map Server\bin\Release\" /d /y /q
|
||||||
|
|
||||||
|
if exist staticactors.bin (
|
||||||
|
echo Copying staticactors.bin if needed...
|
||||||
|
xcopy staticactors.bin "%~dp0\..\Map Server\bin\Release\" /d /y /q
|
||||||
|
) else (
|
||||||
|
echo Cannot copy the staticactors.bin file because it doesn't exist in data\
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Copying scripts folder if needed...
|
||||||
|
xcopy scripts "%~dp0\..\Map Server\bin\Release\scripts\" /e /d /y /s /q
|
||||||
|
)
|
||||||
|
|
||||||
|
if %foundmfolders% LSS 1 (
|
||||||
|
echo Could not find debug or release folder for the Map server. Please compile the project first!
|
||||||
|
)
|
||||||
|
|
||||||
|
Pause
|
58
Data/scripts/ability.lua
Normal file
58
Data/scripts/ability.lua
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
-- todo: add enums for status effects in global.lua
|
||||||
|
require("global")
|
||||||
|
require("battleutils")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
statId - see BattleTemp.cs
|
||||||
|
modifier - Modifier.Intelligence, Modifier.Mind (see Modifier.cs)
|
||||||
|
multiplier -
|
||||||
|
]]
|
||||||
|
function HandleHealingSkill(caster, target, skill, action, statId, modifierId, multiplier, baseAmount)
|
||||||
|
potency = potency or 1.0;
|
||||||
|
healAmount = baseAmount;
|
||||||
|
|
||||||
|
-- todo: shit based on mnd
|
||||||
|
local mind = caster.GetMod(Modifier.Mind);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function HandleAttackSkill(caster, target, skill, action, statId, modifierId, multiplier, baseAmount)
|
||||||
|
-- todo: actually handle this
|
||||||
|
damage = baseAmount or math.random(1,10) * 10;
|
||||||
|
|
||||||
|
return damage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function HandleStoneskin(caster, target, skill, action, statId, modifierId, damage)
|
||||||
|
--[[
|
||||||
|
if target.statusEffects.HasStatusEffect(StatusEffect.Stoneskin) then
|
||||||
|
-- todo: damage reduction
|
||||||
|
return true;
|
||||||
|
end;
|
||||||
|
]]
|
||||||
|
return false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
--For abilities that inflict statuses, like aegis boon or taunt
|
||||||
|
function onStatusAbilityFinish(caster, target, skill, action)
|
||||||
|
--action.CalcHitType(caster, target, skill);
|
||||||
|
action.DoAction(caster, target, skill);
|
||||||
|
action.TryStatus(caster, target, skill, false);
|
||||||
|
|
||||||
|
return action.amount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onAttackAbilityFinish(caster, target, skill, action)
|
||||||
|
local damage = math.random(50, 150);
|
||||||
|
action.amount = damage;
|
||||||
|
action.DoAction(caster, target, skill);
|
||||||
|
|
||||||
|
return action.amount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function onHealAbilityFinish(caster, target, skill, action)
|
||||||
|
local amount = math.random(150, 250);
|
||||||
|
action.amount = amount;
|
||||||
|
action.DoAction(caster, target, skill);
|
||||||
|
action.TryStatus(caster, target, skill, true);
|
||||||
|
return action.amount;
|
||||||
|
end;
|
205
Data/scripts/aetheryte.lua
Normal file
205
Data/scripts/aetheryte.lua
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
Aetheryte related info
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
aetheryteParentLinks = {
|
||||||
|
--La Noscea
|
||||||
|
[1280001] = nil,
|
||||||
|
[1280002] = {1280007, 1280008, 1280009, 0, 0},
|
||||||
|
[1280003] = {1280010, 0, 0, 0, 0},
|
||||||
|
[1280004] = {1280011, 1280018, 0, 0, 0},
|
||||||
|
[1280005] = {1280020, 1280012, 1280013, 1280014, 0},
|
||||||
|
[1280006] = {1280015, 1280016, 1280017, 0, 0},
|
||||||
|
--Thanalan
|
||||||
|
[1280031] = nil,
|
||||||
|
[1280032] = {1280037, 1280038, 1280052, 0, 0},
|
||||||
|
[1280033] = {1280039, 1280040, 1280041, 0, 0},
|
||||||
|
[1280034] = {1280042, 1280043, 1280044, 1280054, 0},
|
||||||
|
[1280035] = {1280045, 1280046, 1280047, 0, 0},
|
||||||
|
[1280036] = {1280048, 1280049, 1280050, 0, 0},
|
||||||
|
--Black Shroud
|
||||||
|
[1280061] = nil,
|
||||||
|
[1280062] = {1280067, 1280068, 1280069, 1280083, 0},
|
||||||
|
[1280063] = {1280070, 1280071, 1280072, 0, 0},
|
||||||
|
[1280064] = {1280073, 1280074, 1280075, 1280082, 0},
|
||||||
|
[1280065] = {1280076, 1280077, 1280078, 0, 0},
|
||||||
|
[1280066] = {1280079, 1280080, 1280081, 0, 0},
|
||||||
|
--Coerthas
|
||||||
|
[1280092] = {1280097, 1280098, 1280099, 0, 0},
|
||||||
|
[1280093] = {1280100, 1280101, 1280102, 0, 0},
|
||||||
|
[1280094] = {1280103, 1280104, 0, 0, 0},
|
||||||
|
[1280095] = {1280105, 1280106, 1280107, 0, 0},
|
||||||
|
[1280096] = {1280108, 1280109, 1280110, 0, 0},
|
||||||
|
--Mor Dhona
|
||||||
|
[1280121] = {1280124, 1280125, 0, 0, 0},
|
||||||
|
[1280122] = {1280123, 0, 0, 0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
aetheryteChildLinks = {
|
||||||
|
--La Noscea
|
||||||
|
[1280007] = 1280002,
|
||||||
|
[1280008] = 1280002,
|
||||||
|
[1280009] = 1280002,
|
||||||
|
[1280010] = 1280003,
|
||||||
|
[1280011] = 1280004,
|
||||||
|
[1280012] = 1280005,
|
||||||
|
[1280013] = 1280005,
|
||||||
|
[1280014] = 1280005,
|
||||||
|
[1280015] = 1280006,
|
||||||
|
[1280016] = 1280006,
|
||||||
|
[1280017] = 1280006,
|
||||||
|
[1280018] = 1280004,
|
||||||
|
[1280020] = 1280005,
|
||||||
|
--Thanalan
|
||||||
|
[1280037] = 1280032,
|
||||||
|
[1280038] = 1280032,
|
||||||
|
[1280039] = 1280033,
|
||||||
|
[1280040] = 1280033,
|
||||||
|
[1280041] = 1280033,
|
||||||
|
[1280042] = 1280034,
|
||||||
|
[1280043] = 1280034,
|
||||||
|
[1280044] = 1280034,
|
||||||
|
[1280045] = 1280035,
|
||||||
|
[1280046] = 1280035,
|
||||||
|
[1280047] = 1280035,
|
||||||
|
[1280048] = 1280036,
|
||||||
|
[1280049] = 1280036,
|
||||||
|
[1280050] = 1280036,
|
||||||
|
[1280052] = 1280032,
|
||||||
|
[1280054] = 1280034,
|
||||||
|
--Black Shroud
|
||||||
|
[1280067] = 1280062,
|
||||||
|
[1280068] = 1280062,
|
||||||
|
[1280069] = 1280062,
|
||||||
|
[1280070] = 1280063,
|
||||||
|
[1280071] = 1280063,
|
||||||
|
[1280072] = 1280063,
|
||||||
|
[1280073] = 1280064,
|
||||||
|
[1280074] = 1280064,
|
||||||
|
[1280075] = 1280064,
|
||||||
|
[1280076] = 1280065,
|
||||||
|
[1280077] = 1280065,
|
||||||
|
[1280078] = 1280065,
|
||||||
|
[1280079] = 1280066,
|
||||||
|
[1280080] = 1280066,
|
||||||
|
[1280081] = 1280066,
|
||||||
|
[1280082] = 1280064,
|
||||||
|
[1280083] = 1280062,
|
||||||
|
--Coerthas
|
||||||
|
[1280097] = 1280092,
|
||||||
|
[1280098] = 1280092,
|
||||||
|
[1280099] = 1280092,
|
||||||
|
[1280100] = 1280093,
|
||||||
|
[1280101] = 1280093,
|
||||||
|
[1280102] = 1280093,
|
||||||
|
[1280103] = 1280094,
|
||||||
|
[1280104] = 1280094,
|
||||||
|
[1280105] = 1280095,
|
||||||
|
[1280106] = 1280095,
|
||||||
|
[1280107] = 1280095,
|
||||||
|
[1280108] = 1280096,
|
||||||
|
[1280109] = 1280096,
|
||||||
|
[1280110] = 1280096,
|
||||||
|
--Mor Dhona
|
||||||
|
[1280123] = 1280122,
|
||||||
|
[1280124] = 1280121,
|
||||||
|
[1280125] = 1280121
|
||||||
|
}
|
||||||
|
|
||||||
|
aetheryteTeleportPositions = {
|
||||||
|
--La Noscea
|
||||||
|
[1280001] = {230, -407, 42.5, 337}, -- CAP
|
||||||
|
[1280002] = {128, 29.97, 45.83, -35.47}, -- CAP
|
||||||
|
[1280003] = {129, -991.88, 61.71, -1120.79}, -- CAP
|
||||||
|
[1280004] = {129, -1883.47, 53.77, -1372.68}, -- CAP
|
||||||
|
[1280005] = {130, 1123.29, 45.7, -928.69}, -- CAP
|
||||||
|
[1280006] = {135, -278.181, 77.63, -2260.79}, -- CAP
|
||||||
|
[1280007] = {128, 582.47, 54.52, -1.2},
|
||||||
|
[1280008] = {128, 962.836, 46.507, 832.206}, -- Widow Cliffs http://ic.pics.livejournal.com/eijih/14054410/1355/1355_original.jpg
|
||||||
|
[1280009] = {128, 318, 24.5, 581}, -- Moraby Bay http://ic.pics.livejournal.com/eijih/14054410/1092/1092_original.jpg
|
||||||
|
[1280010] = {129, -636, 48.8, -1287}, -- Woad Whisper Canyon
|
||||||
|
[1280011] = {129, -2016.72, 60.055, -766.962}, -- Isles of Umbra http://ic.pics.livejournal.com/eijih/14054410/2243/2243_original.jpg
|
||||||
|
[1280012] = {130, 1628, 60.3, -449}, -- Tiger Helm Island http://ic.pics.livejournal.com/eijih/14054410/2032/2032_original.jpg
|
||||||
|
[1280013] = {130, 1522, 1.7, -669},-- Bloodshore http://ic.pics.livejournal.com/eijih/14054410/1607/1607_original.jpg
|
||||||
|
[1280014] = {130, 1410, 53.3, -1650}, -- Agelyss Wise
|
||||||
|
[1280015] = {135, -123.315, 60.061, -1438.8}, -- Zelma's Run https://youtu.be/97Ju0Xv-aaQ?t=102
|
||||||
|
[1280016] = {135, -320.322, 52.835, -1823.68}, -- Bronze Lake http://ic.pics.livejournal.com/eijih/14054410/2503/2503_original.jpg
|
||||||
|
[1280017] = {135, -894, 41.2, -2188}, -- Oakwood
|
||||||
|
[1280018] = {131, -1694.5, -19.9, -1534.}, -- Mistbeard Cove
|
||||||
|
[1280020] = {132, 1343.5, -54.38, -870.84}, -- CAP
|
||||||
|
--Thanalan
|
||||||
|
[1280031] = {175, -235, 185, -3.9}, -- CAP
|
||||||
|
[1280032] = {170, 33, 200.1, -482}, -- Camp Black Brush
|
||||||
|
[1280033] = {171, 1250.9, 264, -544.2}, -- CAP
|
||||||
|
[1280034] = {172, -1313.91, 56.023, -145.597}, -- Camp Horizon https://www.youtube.com/watch?v=mQAK4QVnx3c
|
||||||
|
[1280035] = {173, -165.816, 280.002, -1698.45}, -- Camp Bluefog
|
||||||
|
[1280036] = {174, 1687.64, 296.002, 992.283}, -- Camp Brokenwater https://www.youtube.com/watch?v=YyBYHg9h2AM
|
||||||
|
[1280037] = {170, 639, 183.9, 122}, -- Cactus Basin
|
||||||
|
[1280038] = {170, 539, 215.8, -14}, -- Four Sisters
|
||||||
|
[1280039] = {171, 1599, 256.7, -233}, -- Halatali
|
||||||
|
[1280040] = {171, 2010, 280.3, -768}, -- Burning Wall
|
||||||
|
[1280041] = {171, 2015, 247.8, 64}, -- Sandgate
|
||||||
|
[1280042] = {172, -864.991, 88.84, 375.18}, -- Nophica's Wells https://www.youtube.com/watch?v=pk4POCDQ9QE
|
||||||
|
[1280043] = {172, -1653, 24.5, -469}, -- Footfalls
|
||||||
|
[1280044] = {172, -1220.38, 69.854, 194.365}, -- Scorpion Keep
|
||||||
|
[1280045] = {173, -635, 280, -1797}, -- Hidden Gorge
|
||||||
|
[1280046] = {173, 447, 259.1, -2158}, -- Sea of Spires
|
||||||
|
[1280047] = {173, -710, 280.4, -2212}, -- Cutters Pass
|
||||||
|
[1280048] = {174, 1797, 248, 1856}, -- Red Labyrinth
|
||||||
|
[1280049] = {174, 1185, 279.8, 1407}, -- Burnt Lizard Creek
|
||||||
|
[1280050] = {174, 2416, 248.3, 1535}, -- Zanr'ak
|
||||||
|
[1280052] = {176, 80.056, 167.929, -1267.94}, -- Nanawa Mines https://www.youtube.com/watch?v=9H-NveJx9EI
|
||||||
|
[1280054] = {178, -620.374, 110.429, -113.903}, -- Copperbell Mines
|
||||||
|
-- Black Shroud
|
||||||
|
[1280061] = {206, -120, 16, -1332}, -- CAP
|
||||||
|
[1280062] = {150, 288, 4, -543.928}, -- CAP
|
||||||
|
[1280063] = {151, 1702, 20, -862}, -- CAP
|
||||||
|
[1280064] = {152, -1052, 20, -1760}, -- CAP
|
||||||
|
[1280065] = {153, -1566.035, -11.89, -550.51}, -- CAP
|
||||||
|
[1280066] = {154, 734, -12, 1126}, -- CAP
|
||||||
|
[1280067] = {150, -94.07, 4, -543.16}, -- Humblehearth
|
||||||
|
[1280068] = {150, -285, -21.8, -46}, -- Sorrel Haven
|
||||||
|
[1280069] = {150, 636, 16.2, -324}, -- Five Hangs
|
||||||
|
[1280070] = {151, 1529.83, 26.991, -1140.15}, -- Verdant Drop
|
||||||
|
[1280071] = {151, 1296, 47.2, -1534}, -- Lynxpelt Patch
|
||||||
|
[1280072] = {151, 2297.02, 31.546, -697.828}, -- Larkscall http://www.gwcdn.com/albums/images/4f7ce3a389118b43470005b1.jpg
|
||||||
|
[1280073] = {152, -883.769, 34.688, -2187.45}, -- Treespeak
|
||||||
|
[1280074] = {152, -1567, 16.1, -2593}, -- Aldersprings
|
||||||
|
[1280075] = {152, -800.277, 32, -2785.4}, -- Lasthold
|
||||||
|
[1280076] = {153, -1908, 0.3, -1042}, -- Lichenweed
|
||||||
|
[1280077] = {153, -2158, -46.1, -166}, -- Murmur Rills
|
||||||
|
[1280078] = {153, -1333, -14.2, 324}, -- Turning Leaf
|
||||||
|
[1280079] = {154, 991, -11.8, 600}, -- Silent Arbor
|
||||||
|
[1280080] = {154, 1126, -0.1, 1440}, -- Longroot
|
||||||
|
[1280081] = {154, 189, 0.1, 1337}, -- Snakemolt
|
||||||
|
[1280082] = {157, -687.916, -15.308, -2063.94}, -- Mun-Tuy Cellars https://www.youtube.com/watch?v=ty6f9Gy0uws
|
||||||
|
[1280083] = {158, 314.801, -36.2, -167.843}, -- Tam-Tara Deepcroft https://www.youtube.com/watch?v=eLJPTUG-dE0
|
||||||
|
-- Coerthas
|
||||||
|
[1280092] = {143, 216, 302.1, -258}, -- Camp Dragonhead
|
||||||
|
[1280093] = {144, 1122.21, 270.004, -1149.29}, -- Camp Crooked Fork https://www.youtube.com/watch?v=Q7-0r6ELCAU
|
||||||
|
[1280094] = {145, 1500.78, 206.036, 767.546}, -- Camp Glory
|
||||||
|
[1280095] = {147, -159.828, 222.037, 1154.81}, -- Camp Ever Lakes https://youtu.be/3wKNidix0Ls?t=274
|
||||||
|
[1280096] = {148, -1760.36, 270.059, -194.713}, -- Camp Riversmeet https://www.youtube.com/watch?v=gt7Tc9gbTpk
|
||||||
|
[1280097] = {143, -517, 207.9, 543}, -- Boulder Downs
|
||||||
|
[1280098] = {143, 190, 367.4, -662}, -- Prominence Point
|
||||||
|
[1280099] = {143, 960, 287.4, -22}, -- Feathergorge
|
||||||
|
[1280100] = {144, 1737, 176.5, -1250}, -- Maiden Glen
|
||||||
|
[1280101] = {144, 1390, 222.6, -736}, -- Hushed Boughs
|
||||||
|
[1280102] = {144, 1788, 164.8, -829}, -- Scarwing Fall
|
||||||
|
[1280103] = {145, 1383, 231.8, 422}, -- Weeping Vale
|
||||||
|
[1280104] = {145, 2160, 142.7, 622}, -- Clearwater
|
||||||
|
[1280105] = {147, -1, 144.1, 1373}, -- Teriggans Stand
|
||||||
|
[1280106] = {147, -64, 185.1, 1924}, -- Shepherd Peak
|
||||||
|
[1280107] = {147, -908, 191.7, 2162}, -- Fellwood
|
||||||
|
[1280108] = {148, -1734.82, 285.069, -839.63}, -- Wyrmkings Perch
|
||||||
|
[1280109] = {148, -2366.07, 336.041, -1054.75}, -- The Lance
|
||||||
|
[1280110] = {148, -2821, 256.1, -290}, -- Twinpools
|
||||||
|
-- Mor Dhona
|
||||||
|
[1280121] = {190, 487.445, 18.531, 672.244}, -- Camp Brittlebark https://youtu.be/mkbYeaUqcr4 - I can barely make the ground out
|
||||||
|
[1280122] = {190, -215.76, 18.54, -668.703}, -- Camp Revenant's Toll
|
||||||
|
[1280123] = {190, -458, -40.9, -318}, -- Fogfens
|
||||||
|
[1280124] = {190, 580, 58.2, 206}, -- Singing Shards
|
||||||
|
[1280125] = {190, -365.724, -18.591, -25.448} -- Jagged Crest Cave
|
||||||
|
}
|
117
Data/scripts/ally.lua
Normal file
117
Data/scripts/ally.lua
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
require ("global")
|
||||||
|
require ("magic")
|
||||||
|
require ("weaponskill")
|
||||||
|
|
||||||
|
allyGlobal =
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
function allyGlobal.onSpawn(ally, target)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.onEngage(ally, target)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.onAttack(ally, target, damage)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.onDamageTaken(ally, attacker, damage)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.onCombatTick(ally, target, tick, contentGroupCharas)
|
||||||
|
allyGlobal.HelpPlayers(ally, contentGroupCharas)
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.onDeath(ally, player, lastAttacker)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.onDespawn(ally)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.HelpPlayers(ally, contentGroupCharas, pickRandomTarget)
|
||||||
|
print("helpPlayers");
|
||||||
|
if contentGroupCharas and not ally.IsEngaged() then
|
||||||
|
print("contentGroup exists");
|
||||||
|
for chara in contentGroupCharas do
|
||||||
|
print("looping");
|
||||||
|
if chara then
|
||||||
|
-- probably a player, or another ally
|
||||||
|
-- todo: queue support actions, heal, try pull hate off player etc
|
||||||
|
if chara.IsPlayer() then
|
||||||
|
print("chara is a player");
|
||||||
|
-- do stuff
|
||||||
|
if not ally.IsEngaged() then
|
||||||
|
if chara.IsEngaged() then
|
||||||
|
allyGlobal.EngageTarget(ally, chara.target, nil);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif chara.IsMonster() and chara.IsEngaged() then
|
||||||
|
if not ally.IsEngaged() then
|
||||||
|
print("Engaging monster that is engaged");
|
||||||
|
allyGlobal.EngageTarget(ally, chara, nil);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.tryAggro(ally, contentGroupCharas)
|
||||||
|
local count = 0;
|
||||||
|
if contentGroupCharas and not ally.IsEngaged() then
|
||||||
|
for i = 0, #contentGroupCharas - 1 do
|
||||||
|
if contentGroupCharas[i] and ally then
|
||||||
|
if contentGroupCharas[i].IsPlayer() then
|
||||||
|
-- probably a player, or another ally
|
||||||
|
-- todo: queue support actions, heal, try pull hate off player etc
|
||||||
|
if contentGroupCharas[i].target then
|
||||||
|
if ally.aiContainer:GetTargetFind():CanTarget(contentGroupCharas[i].target) and contentGroupCharas[i].target.IsMonster() and contentGroupCharas[i].target.hateContainer:HasHateForTarget(contentGroupCharas[i]) then
|
||||||
|
-- do stuff
|
||||||
|
allyGlobal.EngageTarget(ally, contentGroupCharas[i].target, nil);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif contentGroupCharas[i].IsMonster() and contentGroupCharas[i].IsEngaged() then
|
||||||
|
if not ally.IsEngaged() then
|
||||||
|
print("Engaging monster that is engaged");
|
||||||
|
allyGlobal.EngageTarget(ally, contentGroupCharas[i], nil);
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.HealPlayer(ally, player)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.SupportAction(ally, player)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function allyGlobal.EngageTarget(ally, target, contentGroupCharas)
|
||||||
|
if contentGroupCharas then
|
||||||
|
for chara in contentGroupCharas do
|
||||||
|
if chara.IsMonster() then
|
||||||
|
if chara.allegiance ~= ally.allegiance then
|
||||||
|
ally.Engage(chara)
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif target then
|
||||||
|
print("Engaging");
|
||||||
|
ally.Engage(target)
|
||||||
|
ally.hateContainer.AddBaseHate(target);
|
||||||
|
end
|
||||||
|
end
|
3
Data/scripts/base/chara/npc/mapobj/DoorStandard.lua
Normal file
3
Data/scripts/base/chara/npc/mapobj/DoorStandard.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0, 0, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0, 0, 0;
|
||||||
|
end
|
3
Data/scripts/base/chara/npc/mapobj/MapObjStandard.lua
Normal file
3
Data/scripts/base/chara/npc/mapobj/MapObjStandard.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0, 303, 10405;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
5
Data/scripts/base/chara/npc/monster/Ifrit/IfritDummy.lua
Normal file
5
Data/scripts/base/chara/npc/monster/Ifrit/IfritDummy.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, true, true, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 3, 1, true, false, false, false, false, true, true, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 3, 1, false, false, false, false, false, true, true, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, false, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return true, true, 10, 0, 1, true, false, false, false, false, false, false, false, 0;
|
||||||
|
end
|
5
Data/scripts/base/chara/npc/object/BgKeepout.lua
Normal file
5
Data/scripts/base/chara/npc/object/BgKeepout.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
10
Data/scripts/base/chara/npc/object/BookShelf.lua
Normal file
10
Data/scripts/base/chara/npc/object/BookShelf.lua
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
callClientFunction(player, "bookTalk");
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
5
Data/scripts/base/chara/npc/object/ElevatorStandard.lua
Normal file
5
Data/scripts/base/chara/npc/object/ElevatorStandard.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
43
Data/scripts/base/chara/npc/object/GuildleveWarpPoint.lua
Normal file
43
Data/scripts/base/chara/npc/object/GuildleveWarpPoint.lua
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
GuildleveWarpPoint Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventGuildleveReward(glId, completionTimeSec, completeReward, difficultyBonus, faction, gil???, factionBonus, RewardId1, RewardAmount1, RewardId2, RewardAmount2, difficulty) - Open Reward Dialog
|
||||||
|
eventTalkGuildleveWarp(returnAetheryteID1, returnAetheryte2) - Opens choice menu
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("aetheryte")
|
||||||
|
require ("utils")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local currentGLDirector = player:GetGuildleveDirector();
|
||||||
|
local glData = currentGLDirector.guildleveData;
|
||||||
|
|
||||||
|
callClientFunction(player, "eventGuildleveReward", currentGLDirector.guildleveId, currentGLDirector.completionTime, 24, 24, 0, 0, 0, 0, 0, 0, 0, currentGLDirector.selectedDifficulty);
|
||||||
|
|
||||||
|
local choice = callClientFunction(player, "eventTalkGuildleveWarp", glData.aetheryte, 0);
|
||||||
|
|
||||||
|
if (choice == 3) then
|
||||||
|
local destination = aetheryteTeleportPositions[glData.aetheryte];
|
||||||
|
if (destination ~= nil) then
|
||||||
|
randoPos = getRandomPointInBand(destination[2], destination[4], 3, 5);
|
||||||
|
rotation = getAngleFacing(randoPos.x, randoPos.y, destination[2], destination[4]);
|
||||||
|
GetWorldManager():DoZoneChange(player, destination[1], nil, 0, 2, randoPos.x, destination[3], randoPos.y, rotation);
|
||||||
|
currentGLDirector:EndDirector();
|
||||||
|
end
|
||||||
|
elseif (choice == 4) then
|
||||||
|
currentGLDirector:EndDirector();
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
--50023: GL COMPLETE!
|
||||||
|
--50132: You earn faction credits from X
|
152
Data/scripts/base/chara/npc/object/MarketEntrance.lua
Normal file
152
Data/scripts/base/chara/npc/object/MarketEntrance.lua
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
MarketEntrance Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
Parameters mostly rely on the xtx_placeName sheet for its strings.
|
||||||
|
|
||||||
|
eventPushChoiceAreaOrQuest(
|
||||||
|
exitPlaceName[Fronds, etc], - Retail only showed it when inside a Market Ward/Office Set to 0 to hide the menu.
|
||||||
|
showMarketWards/Houses - If > 0, client script adds nation-specific Mercentile Houses as well.
|
||||||
|
gcHQPlaceName, - Set to the placeName id for the Grand Company office of that city
|
||||||
|
questAreaName, - Set to the placeName id of applicable quest instance, ex. Sailors Ward.
|
||||||
|
showItemSearchCounter, - If true, shows the Item Search menu
|
||||||
|
itemSearchId - If > 0 & showItemSearchCounter = true, displays the item name with a "Stop Searching"
|
||||||
|
)
|
||||||
|
eventPushStepPrvMarket(
|
||||||
|
staringWard, - Sets the starting placeName id
|
||||||
|
wardCount, - Valid number 1-20. Sets the amount of market ward entries. Client continues sequentially from startingWard id.
|
||||||
|
excludeWard - Hides the ward in the list that matches the id. Use on the ward you're currently in.
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
MarketEntrance City TriggerBox details
|
||||||
|
Limsa - !warp 230 -416.5 40 446 ActorClass Id = 1090238
|
||||||
|
bgObj Id - [0xB3B] 2875
|
||||||
|
Layout Id - [0x79 ] 121 (0x29d90001)
|
||||||
|
Condition - in
|
||||||
|
reactName - dwti - Not a typo compared to the other cities
|
||||||
|
Gridania - !warp 206 -192.57 23.48 -1407.58 ActorClass Id = 1090264
|
||||||
|
|
||||||
|
bgObj Id - [0xCFA] 3322
|
||||||
|
Layout Id - [0x141] 321 (0x29b00001)
|
||||||
|
Condition - in
|
||||||
|
reactName - dtwi
|
||||||
|
Ul'dah - !warp 175 -235 189 50.5 ActorClass Id = 1500394
|
||||||
|
bgObj Id - [0x102F] 4143
|
||||||
|
Layout Id - [0x1A5] 421 (0x615a0001)
|
||||||
|
Condition - in
|
||||||
|
reactName - dtwi
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
CITY_INFO = { -- wardPlaceName, exitPlaceName, gcHQPlaceName, questAreaName, wardListStart, wardListCount
|
||||||
|
{1093, 1087, 1512, 1091, 1261, 20}, -- Limsa
|
||||||
|
{2099, 2091, 2526, 2095, 2261, 20}, -- Gridania
|
||||||
|
{3098, 3091, 3514, 3095, 3261, 20}, -- Ul'dah
|
||||||
|
}
|
||||||
|
|
||||||
|
-- TO-DO: Add some X/Z pos jitter to Entrances/Exits when called
|
||||||
|
MARKETWARD_ENTRANCE = {
|
||||||
|
{134, 160, 0, 135}, -- Limsa Market
|
||||||
|
{160, 160, 0, 138}, -- Gridania Market
|
||||||
|
{180, 160, 0, 185} -- Ul'dah Market
|
||||||
|
}
|
||||||
|
|
||||||
|
MARKETWARD_EXIT = {
|
||||||
|
{230, -420, 41, 435, -3.14}, -- Educated guess for Limsa, need video reference to confirm
|
||||||
|
{206, -180, 22, -1408, 1.5},
|
||||||
|
{175, -210, 190, 25, 0.65}
|
||||||
|
}
|
||||||
|
|
||||||
|
GC_ENTRANCE = {
|
||||||
|
[1512] = {232, 160, 0, -155}, -- Maelstrom Command
|
||||||
|
[2526] = {234, 160, 0, -155}, -- Adders' Nest
|
||||||
|
[3514] = {233, 160, 0, -155} -- Hall of Flames
|
||||||
|
}
|
||||||
|
|
||||||
|
city = {
|
||||||
|
[1090238] = 1, -- Limsa Market Ward Entrance
|
||||||
|
[1090264] = 2, -- Gridania Market Ward Entrance
|
||||||
|
[1090265] = 3, -- Ul'dah Market Ward Entrance
|
||||||
|
[1500392] = 1, -- Limsa : M'septha
|
||||||
|
[1500393] = 2, -- Gridania : Torsefers
|
||||||
|
[1500394] = 3, -- Ul'dah : Edine
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
local npcCity = city[npc:GetActorClassId()] or 1;
|
||||||
|
local wardPlaceName = CITY_INFO[npcCity][1]; -- Market Wards category name. Identical in all languages except Japanese
|
||||||
|
local exitPlaceName = CITY_INFO[npcCity][2]; -- Central Limsa Lominsa / Heartstream / The Fronds
|
||||||
|
local gcHQPlaceName = CITY_INFO[npcCity][3]; -- Maelstrom Command / Adders' Nest / Hall of Flames
|
||||||
|
local questAreaName = 0; --CITY_INFO[npcCity][4]; -- Sailors Ward / Peasants Ward / Merchants Ward
|
||||||
|
local wardListStart = CITY_INFO[npcCity][5]; -- Starting id for the market wards
|
||||||
|
local wardListCount = CITY_INFO[npcCity][6]; -- Amount of wards in the list
|
||||||
|
local showItemSearchCounter = false;
|
||||||
|
local itemSearchId = 11000125;
|
||||||
|
|
||||||
|
local worldMaster = GetWorldMaster();
|
||||||
|
local pos = player:GetPos();
|
||||||
|
local currZone = pos[4];
|
||||||
|
|
||||||
|
if (currZone == 133 or currZone == 230 or currZone == 155 or currZone == 206 or currZone == 175 or currZone == 209) then
|
||||||
|
exitPlaceName = 0; -- If in city, hide city menu option
|
||||||
|
elseif (currZone == 232 or currZone == 234 or currZone == 233) then
|
||||||
|
gcHQPlaceName = 0; -- If in GC Office, hide office menu option
|
||||||
|
end
|
||||||
|
|
||||||
|
choice = callClientFunction(player, "eventPushChoiceAreaOrQuest", exitPlaceName, wardPlaceName, gcHQPlaceName, questAreaName, showItemSearchCounter, itemSearchId);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
if choice == wardPlaceName then -- Market Wards
|
||||||
|
wardSelect = callClientFunction(player, "eventPushStepPrvMarket", wardListStart, wardListCount, 0);
|
||||||
|
|
||||||
|
if wardSelect and (wardSelect >= wardListStart and wardSelect <= (wardListStart+wardListCount)) then
|
||||||
|
player:SendGameMessage(player, worldMaster, 60004, 0x20, wardSelect);
|
||||||
|
warp = MARKETWARD_ENTRANCE[npcCity];
|
||||||
|
playerRot = math.random(-3.14, 3.14);
|
||||||
|
wait(1);
|
||||||
|
GetWorldManager():DoZoneChange(player, warp[1], nil, 0, 0x02, warp[2], warp[3], warp[4], playerRot);
|
||||||
|
player:SendDataPacket("attention", worldMaster, "", 60003, wardSelect);
|
||||||
|
-- Temp: Pop-up display after Ward zone-in. Client should automate this with PrivateArea's properly setup
|
||||||
|
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (choice == 1519 or choice == 2534 or choice == 3533) then -- Mercentile Wards
|
||||||
|
player:SendMessage(0x20, "", "[MarketEntrance] DEBUG: "..choice);
|
||||||
|
elseif (choice == 1512 or choice == 2526 or choice == 3514) then -- GC Office
|
||||||
|
warp = GC_ENTRANCE[choice];
|
||||||
|
player:SendGameMessage(player, worldMaster, 60004, 0x20, choice);
|
||||||
|
wait(1);
|
||||||
|
GetWorldManager():DoZoneChange(player, warp[1], nil, 0, 0x02, warp[2], warp[3], warp[4], math.pi);
|
||||||
|
break;
|
||||||
|
elseif (choice == 1087 or choice == 2091 or choice == 3091) then -- Exiting to City
|
||||||
|
player:SendGameMessage(player, worldMaster, 60004, 0x20, choice);
|
||||||
|
warp = MARKETWARD_EXIT[npcCity];
|
||||||
|
wait(1);
|
||||||
|
GetWorldManager():DoZoneChange(player, warp[1], nil, 0, 0x02, warp[2], warp[3], warp[4], warp[5]);
|
||||||
|
break;
|
||||||
|
elseif (choice == 0 or choice == -3) then -- Menu Closed
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
|
||||||
|
choice = callClientFunction(player, "eventPushChoiceAreaOrQuest", exitPlaceName, wardPlaceName, gcHQPlaceName, questAreaName, showItemSearchCounter, itemSearchId);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
10
Data/scripts/base/chara/npc/object/MateriaBook.lua
Normal file
10
Data/scripts/base/chara/npc/object/MateriaBook.lua
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
callClientFunction(player, "materiabookTalk");
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
19
Data/scripts/base/chara/npc/object/MiningPoint.lua
Normal file
19
Data/scripts/base/chara/npc/object/MiningPoint.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
harvestJudge = GetStaticActor("HarvestJudge");
|
||||||
|
|
||||||
|
--callClientFunction(player, "delegateEvent", player, harvestJudge, "loadTextData", dummy);
|
||||||
|
--callClientFunction(player, "delegateEvent", player, harvestJudge, "targetCancel", dummy);
|
||||||
|
--callClientFunction(player, "delegateEvent", player, harvestJudge, "turnToTarget", dummy, 0);
|
||||||
|
--callClientFunction(player, "delegateEvent", player, harvestJudge, "openInputWidget", 22002, 1);
|
||||||
|
--callClientFunction(player, "delegateEvent", player, harvestJudge, "textInputWidget", harvestJudge, 22002, npc, false);
|
||||||
|
--callClientFunction(player, "delegateEvent", player, harvestJudge, "askInputWidget", harvestJudge, 22002, 1);
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
23
Data/scripts/base/chara/npc/object/ObjectBed.lua
Normal file
23
Data/scripts/base/chara/npc/object/ObjectBed.lua
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
choice = callClientFunction(player, "askLogout", player);
|
||||||
|
|
||||||
|
if (choice == 2) then
|
||||||
|
player:SetSleeping();
|
||||||
|
player:QuitGame();
|
||||||
|
elseif (choice == 3) then
|
||||||
|
player:SetSleeping();
|
||||||
|
player:Logout();
|
||||||
|
elseif (choice == 4) then
|
||||||
|
player:SendMessage(33, "", "Heck the bed");
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
25
Data/scripts/base/chara/npc/object/ObjectEventDoor.lua
Normal file
25
Data/scripts/base/chara/npc/object/ObjectEventDoor.lua
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ObjectEventDoor Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventDoorMoveAsk() - Shows confirm to move into event
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
choice = callClientFunction(player, "eventDoorMoveAsk");
|
||||||
|
|
||||||
|
if (choice == 1) then
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
16
Data/scripts/base/chara/npc/object/ObjectInnDoor.lua
Normal file
16
Data/scripts/base/chara/npc/object/ObjectInnDoor.lua
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
defaultFst = GetStaticActor("DftFst");
|
||||||
|
choice = callClientFunction(player, "delegateEvent", player, defaultFst, "defaultTalkWithInn_ExitDoor", nil, nil, nil);
|
||||||
|
|
||||||
|
if (choice == 1) then
|
||||||
|
GetWorldManager():DoZoneChange(player, 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
54
Data/scripts/base/chara/npc/object/ObjectItemStorage.lua
Normal file
54
Data/scripts/base/chara/npc/object/ObjectItemStorage.lua
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ObjectItemStorage Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
storageMenu() - Shows store/retrieve/help menu.
|
||||||
|
selectCategory() - Shows the category menu
|
||||||
|
selectStoreItem(nil, categoryId) - Shows store item menu
|
||||||
|
selectReceiveItem(nil, categoryId) - Shows retrieve item menu
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
::TOP_MENU::
|
||||||
|
storageChoice = callClientFunction(player, "storageMenu");
|
||||||
|
|
||||||
|
if (storageChoice == 1) then
|
||||||
|
categoryChoice = callClientFunction(player, "selectCategory");
|
||||||
|
|
||||||
|
if (categoryChoice == 5) then
|
||||||
|
goto TOP_MENU;
|
||||||
|
end
|
||||||
|
|
||||||
|
itemId = callClientFunction(player, "selectStoreItem", nil, categoryChoice);
|
||||||
|
|
||||||
|
if (itemId ~= nil) then
|
||||||
|
player:GetItemPackage(INVENTORY_NORMAL):RemoveItem(itemId, 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (storageChoice == 2) then
|
||||||
|
categoryChoice = callClientFunction(player, "selectCategory");
|
||||||
|
|
||||||
|
if (categoryChoice == 5) then
|
||||||
|
goto TOP_MENU;
|
||||||
|
end
|
||||||
|
|
||||||
|
itemId = callClientFunction(player, "selectReceiveItem", nil, categoryChoice);
|
||||||
|
|
||||||
|
if (itemId ~= nil) then
|
||||||
|
player:GetItemPackage(INVENTORY_NORMAL):AddItem(itemId, 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
6
Data/scripts/base/chara/npc/object/ObjectShip.lua
Normal file
6
Data/scripts/base/chara/npc/object/ObjectShip.lua
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
13
Data/scripts/base/chara/npc/object/OpeningStoperF0B1.lua
Normal file
13
Data/scripts/base/chara/npc/object/OpeningStoperF0B1.lua
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
if (triggerName == "caution") then
|
||||||
|
worldMaster = GetWorldMaster();
|
||||||
|
player:SendGameMessage(player, worldMaster, 34109, 0x20);
|
||||||
|
elseif (triggerName == "exit") then
|
||||||
|
GetWorldManager():DoPlayerMoveInZone(player, 5);
|
||||||
|
end
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
12
Data/scripts/base/chara/npc/object/PrivateAreaPastExit.lua
Normal file
12
Data/scripts/base/chara/npc/object/PrivateAreaPastExit.lua
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
if (triggerName == "caution") then
|
||||||
|
worldMaster = GetWorldMaster();
|
||||||
|
player:SendGameMessage(player, worldMaster, 34109, 0x20);
|
||||||
|
elseif (triggerName == "exit") then
|
||||||
|
end
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
19
Data/scripts/base/chara/npc/object/RaidDungeonBarrier.lua
Normal file
19
Data/scripts/base/chara/npc/object/RaidDungeonBarrier.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
isActive = true;
|
||||||
|
|
||||||
|
if (isActive) then
|
||||||
|
choice = callClientFunction(player, "askYesNo");
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkRead");
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
56
Data/scripts/base/chara/npc/object/RetainerFurniture.lua
Normal file
56
Data/scripts/base/chara/npc/object/RetainerFurniture.lua
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
RetainerFurniture Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventPushStepOpenRetainerMenu() - Opens menu to choose retainer
|
||||||
|
eventRingBell() - Plays the bell ring animation
|
||||||
|
eventPushRetainerCallCaution() - Shows warning that a open bazaar will be closed if retainer chosen
|
||||||
|
eventTalkRetainerMenu(hasPossessions, showDispatchChoice) - Opens retainer menu.
|
||||||
|
eventTalkRetainerDismissal(hasPossessions) - Show dismiss confirmation.
|
||||||
|
eventTalkRetainerMannequin(0:Enable/1:Disable) - Shows dialog to enable/disable modeling.
|
||||||
|
eventTalkRetainerItemTrade(operationCode) - Operate RetainerTradeWidget. Codes: 1 - Open, 2 - Select Mode, 3 - Close.
|
||||||
|
eventTalkRetainerItemList(operationCode) - Operate Bazaar Widget. Codes: 1 - Open, 2 - Select Mode, 3 - Close.
|
||||||
|
eventReturnResult(resultCode, ?) - Redraws the RetainerTrade UI.
|
||||||
|
eventTalkSelectBazaarStreet(limitsWardChoices) - Shows the dialog to send a retainer to a street. Set to 20.
|
||||||
|
eventTalkFinish() - Finishs the talk with retainer
|
||||||
|
eventPlayerTurn(rotation) - Turns the player
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("retainer")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
retainerNumber = callClientFunction(player, "eventPushStepOpenRetainerMenu");
|
||||||
|
|
||||||
|
if (retainerNumber == nil or retainerNumber == 0) then
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "eventRingBell");
|
||||||
|
retainer = player:SpawnMyRetainer(npc, retainerNumber);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
choice = callClientFunction(player, "eventTalkRetainerMenu", false, true);
|
||||||
|
if (choice == 1) then
|
||||||
|
doItemTrade(player, retainer);
|
||||||
|
elseif (choice == 2) then
|
||||||
|
doBazaar(player, retainer);
|
||||||
|
elseif (choice == 7) then
|
||||||
|
callClientFunction(player, "eventTalkRetainerMannequin", 0);
|
||||||
|
elseif (choice == 8) then
|
||||||
|
callClientFunction(player, "eventTalkSelectBazaarStreet", 20);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:DespawnMyRetainer();
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
19
Data/scripts/base/chara/npc/object/TaskBoard.lua
Normal file
19
Data/scripts/base/chara/npc/object/TaskBoard.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
questNOC = GetStaticActor("Noc000");
|
||||||
|
|
||||||
|
if (npc:GetActorClassId() == 1200193) then
|
||||||
|
callClientFunction(player, "delegateEvent", player, questNOC, "pETaskBoardAskLimsa", nil, nil, nil);
|
||||||
|
elseif (npc:GetActorClassId() == 1200194) then
|
||||||
|
callClientFunction(player, "delegateEvent", player, questNOC, "pETaskBoardAskUldah", nil, nil, nil);
|
||||||
|
else
|
||||||
|
callClientFunction(player, "delegateEvent", player, questNOC, "pETaskBoardAskGridania", nil, nil, nil);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
119
Data/scripts/base/chara/npc/object/aetheryte/AetheryteChild.lua
Normal file
119
Data/scripts/base/chara/npc/object/aetheryte/AetheryteChild.lua
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
AetheryteChild Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventAetheryteChildSelect(showTeleport, parentAetheryteID, animaAmount, animaCost(always 1)): Opens menu
|
||||||
|
eventAetheryteChildDesion(aetheryteId): "Your homepoint is now X"
|
||||||
|
|
||||||
|
eventGLSelect(?) - Open GL selector
|
||||||
|
eventGLSelectDetail(glid, ?, reward, rewardQuantity, subreward, subrewardQuantity, faction, ?, completed) - Show GL details
|
||||||
|
eventGLDifficulty() - Open difficulty selector
|
||||||
|
eventGLStart(glId, difficulty, evaluatingFaction, areaFactionStanding, factionReward, warningBoundByDuty, warningTooFar, warningYouCannotRecieve, warningChangingClass) - Confirmation dialog
|
||||||
|
|
||||||
|
eventGLBoost(currentFavor, minNeeded) - Ask player for Guardian Aspect
|
||||||
|
eventGLPlay(??) - Open Menu (GL active version)
|
||||||
|
eventGLReward (glId, clearTime, missionBonus, difficultyBonus, factionNumber, factionBonus, factionCredit, reward, rewardQuantity, subreward, subrewardQuantity, difficulty) - Open reward window
|
||||||
|
eventGLJoin () - Ask to join party leader's leve
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("aetheryte")
|
||||||
|
require ("utils")
|
||||||
|
require ("guildleve")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, aetheryte, triggerName)
|
||||||
|
|
||||||
|
if (player:GetGuildleveDirector() ~= nil) then
|
||||||
|
doGuildleveMenu(player, aetheryte);
|
||||||
|
else
|
||||||
|
doNormalMenu(player, aetheryte);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
function doGuildleveMenu(player, aetheryte)
|
||||||
|
|
||||||
|
local currentGLDirector = player:GetGuildleveDirector();
|
||||||
|
local choice = callClientFunction(player, "eventGLPlay", currentGLDirector.guildleveId, true, 1, 500, 400, guardian, 8, currentGLDirector.selectedDifficulty, 2);
|
||||||
|
|
||||||
|
--Abandon
|
||||||
|
if (choice == 6) then
|
||||||
|
currentGLDirector:AbandonGuildleve();
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function doNormalMenu(player, aetheryte)
|
||||||
|
|
||||||
|
local aetheryteId = aetheryte:GetActorClassId();
|
||||||
|
local parentNode = aetheryteChildLinks[aetheryteId];
|
||||||
|
local menuChoice = callClientFunction(player, "eventAetheryteChildSelect", true, parentNode, 100, 1);
|
||||||
|
|
||||||
|
--Teleport
|
||||||
|
if (menuChoice == 2) then
|
||||||
|
printf("%ud", parentNode);
|
||||||
|
destination = aetheryteTeleportPositions[parentNode];
|
||||||
|
|
||||||
|
if (destination ~= nil) then
|
||||||
|
randoPos = getRandomPointInBand(destination[2], destination[4], 3, 5);
|
||||||
|
rotation = getAngleFacing(randoPos.x, randoPos.y, destination[2], destination[4]);
|
||||||
|
GetWorldManager():DoZoneChange(player, destination[1], nil, 0, 2, randoPos.x, destination[3], randoPos.y, rotation);
|
||||||
|
end
|
||||||
|
--Init Levequest
|
||||||
|
elseif (menuChoice == -1) then
|
||||||
|
doLevequestInit(player, aetheryte);
|
||||||
|
--Set Homepoint
|
||||||
|
elseif (menuChoice == -2) then
|
||||||
|
player:SetHomePoint(aetheryteId);
|
||||||
|
callClientFunction(player, "eventAetheryteChildDesion", aetheryteId);
|
||||||
|
--View Faction Standing
|
||||||
|
elseif (menuChoice == -3) then
|
||||||
|
player:SendGameMessage(player, aetheryte, 27, 0x20);
|
||||||
|
player:SendGameMessage(player, aetheryte, 28, 0x20, 1, 15);
|
||||||
|
player:SendGameMessage(player, aetheryte, 29, 0x20, 2, 10);
|
||||||
|
player:SendGameMessage(player, aetheryte, 30, 0x20, 3, 5);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function doLevequestInit(player, aetheryte)
|
||||||
|
local worldMaster = GetWorldMaster();
|
||||||
|
::SELECT_LOOP::
|
||||||
|
unknown, glId = callClientFunction(player, "eventGLSelect", 0x0);
|
||||||
|
if (glId ~= 0) then
|
||||||
|
::SELECT_DETAIL::
|
||||||
|
guildleveData = GetGuildleveGamedata(glId);
|
||||||
|
|
||||||
|
if (guildleveData == nil) then
|
||||||
|
player:SendMessage(0x20, "", "An error has occured... aborting.");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
unknown, begin = callClientFunction(player, "eventGLSelectDetail", glId, 0xa, 0xf4241, 1000, 0, 0, 0, true, false);
|
||||||
|
if (begin) then
|
||||||
|
::SELECT_DIFFICULTY::
|
||||||
|
player:SendGameMessage(worldMaster, 50014, 0x20); --"Please select a difficulty level. This may be lowered later."
|
||||||
|
difficulty = callClientFunction(player, "eventGLDifficulty", glId);
|
||||||
|
if (difficulty == nil) then goto SELECT_DETAIL; end
|
||||||
|
confirmResult = callClientFunction(player, "eventGLStart", glId, difficulty, 1, 10, 20, 0, 0, 0, 0);
|
||||||
|
if (confirmResult == nil) then goto SELECT_DIFFICULTY; else
|
||||||
|
|
||||||
|
player:SendGameMessage(worldMaster, 50036, 0x20, glId, player);
|
||||||
|
player:PlayAnimation(getGLStartAnimationFromSheet(guildleveData.borderId, guildleveData.plateId, true));
|
||||||
|
director = player:GetZone():CreateGuildleveDirector(glId, difficulty, player);
|
||||||
|
player:AddDirector(director);
|
||||||
|
director:StartDirector(true, glId)
|
||||||
|
|
||||||
|
end
|
||||||
|
else
|
||||||
|
goto SELECT_LOOP;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
154
Data/scripts/base/chara/npc/object/aetheryte/AetheryteParent.lua
Normal file
154
Data/scripts/base/chara/npc/object/aetheryte/AetheryteParent.lua
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
AetheryteParent Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventAetheryteParentSelect(showTeleportMenu, animaAmount, gate1, gate2, gate3, gate4, gate5) - Open Menu
|
||||||
|
eventAetheryteParentDesion(sheetId) - Show Homepoint Set Message
|
||||||
|
|
||||||
|
eventGLSelect(?) - Open GL selector
|
||||||
|
eventGLSelectDetail(glid, ?, reward, rewardQuantity, subreward, subrewardQuantity, faction, ?, completed) - Show GL details
|
||||||
|
eventGLDifficulty() - Open difficulty selector
|
||||||
|
eventGLStart(glId, difficulty, evaluatingFaction, areaFactionStanding, factionReward, warningBoundByDuty, warningTooFar, warningYouCannotRecieve, warningChangingClass) - Confirmation dialog
|
||||||
|
eventGLBoost(currentFavor, minNeeded) - Ask player for Guardian Aspect
|
||||||
|
eventGLPlay(glId, showLeveLink, leveLinkFaction, leveLinkFactionStanding, leveLinkReward, guardianFavorAmount, guardianFavorNeeded, currentDifficulty, jobNameForChange) - Open Menu (GL active version)
|
||||||
|
eventGLReward (glId, clearTime, missionBonus, difficultyBonus, factionNumber, factionBonus, factionCredit, reward, rewardQuantity, subreward, subrewardQuantity, difficulty) - Open reward window
|
||||||
|
eventGLJoin () - Ask to join party leader's leve
|
||||||
|
|
||||||
|
|
||||||
|
--callClientFunction(player, "eventGLBoost", 0xc8, 0xb);
|
||||||
|
--callClientFunction(player, "eventGLReward", 0x2a48, 120, 123, 125, 1, 111, 0, 0xf4241, 5, 0, 0, 3);
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("aetheryte")
|
||||||
|
require ("utils")
|
||||||
|
require ("guildleve")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, aetheryte, triggerName)
|
||||||
|
|
||||||
|
if (player:GetGuildleveDirector() ~= nil) then
|
||||||
|
doGuildleveMenu(player, aetheryte);
|
||||||
|
else
|
||||||
|
doNormalMenu(player, aetheryte);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function doGuildleveMenu(player, aetheryte)
|
||||||
|
|
||||||
|
local currentGLDirector = player:GetGuildleveDirector();
|
||||||
|
local choice = callClientFunction(player, "eventGLPlay", currentGLDirector.guildleveId, true, 1, 500, 400, guardian, 8, currentGLDirector.selectedDifficulty, 2);
|
||||||
|
|
||||||
|
--Abandon
|
||||||
|
if (choice == 6) then
|
||||||
|
currentGLDirector:AbandonGuildleve();
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function doNormalMenu(player, aetheryte)
|
||||||
|
local aetheryteId = aetheryte:GetActorClassId();
|
||||||
|
local childNodes = aetheryteParentLinks[aetheryteId];
|
||||||
|
|
||||||
|
local listPosition = 1;
|
||||||
|
local activeChildNodes = {0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
if (childNodes ~= nil) then
|
||||||
|
if (player:HasAetheryteNodeUnlocked(childNodes[1])) then
|
||||||
|
activeChildNodes[listPosition] = childNodes[1];
|
||||||
|
listPosition = listPosition+1;
|
||||||
|
end
|
||||||
|
if (player:HasAetheryteNodeUnlocked(childNodes[2])) then
|
||||||
|
activeChildNodes[listPosition] = childNodes[2];
|
||||||
|
listPosition = listPosition+1;
|
||||||
|
end
|
||||||
|
if (player:HasAetheryteNodeUnlocked(childNodes[3])) then
|
||||||
|
activeChildNodes[listPosition] = childNodes[3];
|
||||||
|
listPosition = listPosition+1;
|
||||||
|
end
|
||||||
|
if (player:HasAetheryteNodeUnlocked(childNodes[4])) then
|
||||||
|
activeChildNodes[listPosition] = childNodes[4];
|
||||||
|
listPosition = listPosition+1;
|
||||||
|
end
|
||||||
|
if (player:HasAetheryteNodeUnlocked(childNodes[5])) then
|
||||||
|
activeChildNodes[listPosition] = childNodes[5];
|
||||||
|
listPosition = listPosition+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local showTeleportOptions = true;
|
||||||
|
if (listPosition == 1) then
|
||||||
|
showTeleportOptions = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
local choice = callClientFunction(player, "eventAetheryteParentSelect", showTeleportOptions, 100, activeChildNodes[1], activeChildNodes[2], activeChildNodes[3], activeChildNodes[4], activeChildNodes[5]);
|
||||||
|
|
||||||
|
if (choice ~= nil) then
|
||||||
|
--Init Leavequest
|
||||||
|
if (choice == -1) then
|
||||||
|
doLevequestInit(player, aetheryte);
|
||||||
|
--Set Homepoint
|
||||||
|
elseif (choice == -2) then
|
||||||
|
player:SetHomePoint(aetheryteId);
|
||||||
|
callClientFunction(player, "eventAetheryteParentDesion", aetheryteId);
|
||||||
|
--View Faction Standings
|
||||||
|
elseif (choice == -3) then
|
||||||
|
player:SendGameMessage(player, aetheryte, 124, 0x20);
|
||||||
|
player:SendGameMessage(player, aetheryte, 125, 0x20, 1, 15);
|
||||||
|
player:SendGameMessage(player, aetheryte, 126, 0x20, 2, 10);
|
||||||
|
player:SendGameMessage(player, aetheryte, 127, 0x20, 3, 5);
|
||||||
|
--Teleport to Gate
|
||||||
|
elseif (choice > 0) then
|
||||||
|
destination = aetheryteTeleportPositions[activeChildNodes[choice]];
|
||||||
|
if (destination ~= nil) then
|
||||||
|
randoPos = getRandomPointInBand(destination[2], destination[4], 3, 5);
|
||||||
|
rotation = getAngleFacing(randoPos.x, randoPos.y, destination[2], destination[4]);
|
||||||
|
GetWorldManager():DoZoneChange(player, destination[1], nil, 0, 2, randoPos.x, destination[3], randoPos.y, rotation);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function doLevequestInit(player, aetheryte)
|
||||||
|
local worldMaster = GetWorldMaster();
|
||||||
|
::SELECT_LOOP::
|
||||||
|
unknown, glId = callClientFunction(player, "eventGLSelect", 0x0);
|
||||||
|
if (glId ~= 0) then
|
||||||
|
::SELECT_DETAIL::
|
||||||
|
guildleveData = GetGuildleveGamedata(glId);
|
||||||
|
|
||||||
|
if (guildleveData == nil) then
|
||||||
|
player:SendMessage(0x20, "", "An error has occured... aborting.");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
unknown, begin = callClientFunction(player, "eventGLSelectDetail", glId, 0xa, 0xf4241, 1000, 0, 0, 0, true, false);
|
||||||
|
if (begin) then
|
||||||
|
::SELECT_DIFFICULTY::
|
||||||
|
player:SendGameMessage(worldMaster, 50014, 0x20); --"Please select a difficulty level. This may be lowered later."
|
||||||
|
difficulty = callClientFunction(player, "eventGLDifficulty", glId);
|
||||||
|
if (difficulty == nil) then goto SELECT_DETAIL; end
|
||||||
|
confirmResult = callClientFunction(player, "eventGLStart", glId, difficulty, 1, guildleveData.favorCount, 20, 0, 0, 0, 0);
|
||||||
|
if (confirmResult == nil) then goto SELECT_DIFFICULTY; else
|
||||||
|
|
||||||
|
player:SendGameMessage(worldMaster, 50036, 0x20, glId, player);
|
||||||
|
player:PlayAnimation(getGLStartAnimationFromSheet(guildleveData.borderId, guildleveData.plateId, true));
|
||||||
|
director = player:GetZone():CreateGuildleveDirector(glId, difficulty, player);
|
||||||
|
player:AddDirector(director);
|
||||||
|
director:StartDirector(true, glId);
|
||||||
|
|
||||||
|
end
|
||||||
|
else
|
||||||
|
goto SELECT_LOOP;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
25
Data/scripts/base/chara/npc/populace/PopulaceAchievement.lua
Normal file
25
Data/scripts/base/chara/npc/populace/PopulaceAchievement.lua
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceAchievement Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventNoGC() -
|
||||||
|
eventUnlock(sheetId) -
|
||||||
|
eventReward(?, bool, ?, bool) -
|
||||||
|
defTalk() - Blurb
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
callClientFunction(player, "defTalk");
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
159
Data/scripts/base/chara/npc/populace/PopulaceBlackMarketeer.lua
Normal file
159
Data/scripts/base/chara/npc/populace/PopulaceBlackMarketeer.lua
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceBlackMarketeer Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome(player) - Start Text
|
||||||
|
eventSellItemAsk(player, itemName, tradePrice) - Requires GC Affiliation. Trade menu for Commemorative Coin
|
||||||
|
eventAskMainMenu(player, index) - Shows menu prompt to purchase with gil or with GC seals
|
||||||
|
eventTalkBye(player) - Says bye text
|
||||||
|
eventTalkStepBreak() - Ends talk, NPC turns to face original position
|
||||||
|
|
||||||
|
eventSealShopMenuOpen() - Opens menu for purchasing with grand company seals
|
||||||
|
eventSealShopMenuAsk() - Returns two values, one that seems to always be true, and an index of purchased item
|
||||||
|
eventSealShopMenuClose() - Closes seal menu
|
||||||
|
eventGilShopMenuOpen() - Opens menu for purchasing with gil
|
||||||
|
eventGilShopMenuAsk() - Returns two values, one that seems to always be true, and an index of purchased item
|
||||||
|
eventGilShopMenuClose() - Closes gil menu
|
||||||
|
|
||||||
|
Class applies to only three NPCs
|
||||||
|
Actorclass Id - 1500293 : Momoroon, Limsa Lominsa
|
||||||
|
Actorclass Id - 1500294 : Gagaroon, Gridania
|
||||||
|
Actorclass Id - 1500295 : Lalaroon, Ul'dah
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("shop")
|
||||||
|
|
||||||
|
shopInfo = { -- [ index ] = { itemId, gilPrice, sealPrice, city, itemCategory }
|
||||||
|
[1001] = {3020202, 100, 10000, 1, 1},
|
||||||
|
[1002] = {3020509, 400, 40000, 1, 1},
|
||||||
|
[1003] = {3020510, 400, 40000, 1, 1},
|
||||||
|
[1004] = {3020504, 1000, 100000, 1, 1},
|
||||||
|
[1005] = {3020505, 1000, 100000, 1, 1},
|
||||||
|
[1101] = {9040018, 1500, 150000, 1, 2},
|
||||||
|
[1102] = {9010025, 2000, 200000, 1, 2},
|
||||||
|
[1301] = {2001014, 4000, 400000, 1, 4},
|
||||||
|
[2001] = {3020203, 100, 10000, 2, 1},
|
||||||
|
[2002] = {3020509, 400, 40000, 2, 1},
|
||||||
|
[2003] = {3020510, 400, 40000, 2, 1},
|
||||||
|
[2004] = {3020504, 1000, 100000, 2, 1},
|
||||||
|
[2005] = {3020505, 1000, 100000, 2, 1},
|
||||||
|
[2101] = {9040018, 1500, 150000, 2, 2},
|
||||||
|
[2102] = {9010025, 2000, 200000, 2, 2},
|
||||||
|
[2301] = {2001015, 4000, 400000, 2, 4},
|
||||||
|
[3001] = {3020204, 100, 10000, 3, 1},
|
||||||
|
[3002] = {3020509, 400, 40000, 3, 1},
|
||||||
|
[3003] = {3020510, 400, 40000, 3, 1},
|
||||||
|
[3004] = {3020504, 1000, 100000, 3, 1},
|
||||||
|
[3005] = {3020505, 1000, 100000, 3, 1},
|
||||||
|
[3101] = {9040018, 1500, 150000, 3, 2},
|
||||||
|
[3102] = {9010025, 2000, 200000, 3, 2},
|
||||||
|
[3301] = {2001016, 4000, 400000, 3, 4},
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
commemorativeCoin = 10011251;
|
||||||
|
commemorativeCoinValue = 25000;
|
||||||
|
gilCurrency = 1000001;
|
||||||
|
playerGC = player.gcCurrent
|
||||||
|
playerGCSeal = 1000200 + playerGC;
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkWelcome", player);
|
||||||
|
|
||||||
|
if player:GetItemPackage(INVENTORY_NORMAL):HasItem(commemorativeCoin) and playerGC > 0 then
|
||||||
|
-- Checks for player having a commemorative coin, show window trade option if so.
|
||||||
|
coinChoice = callClientFunction(player, "eventSellItemAsk", player, commemorativeCoin, commemorativeCoinValue);
|
||||||
|
if coinChoice == 1 then
|
||||||
|
currencyType = callClientFunction(player, "eventAskMainMenu", player);
|
||||||
|
elseif coinChoice == 2 then
|
||||||
|
-- You trade <itemQuantity1> <itemName1> <itemQuality1> for <itemQuantity2> <itemName2> <itemQuality2>.
|
||||||
|
player:SendGameMessage(player, GetWorldMaster(), 25071, MESSAGE_TYPE_SYSTEM, commemorativeCoin, 1, playerGCSeal, 1, 1, commemorativeCoinValue);
|
||||||
|
player:GetItemPackage(INVENTORY_NORMAL):RemoveItem(commemorativeCoin, 1);
|
||||||
|
player:GetItemPackage(INVENTORY_CURRENCY):addItem(playerGCSeal, 25000, 1)
|
||||||
|
-- TODO: Add handling for checking GC seals limit and not going over it
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- If no grand company alignment, go straight to the shop that uses gil, otherwise show gc seal option.
|
||||||
|
if playerGC == 0 then
|
||||||
|
processGilShop(player);
|
||||||
|
else
|
||||||
|
currencyType = callClientFunction(player, "eventAskMainMenu", player);
|
||||||
|
if currencyType == 1 then
|
||||||
|
processGilShop(player);
|
||||||
|
elseif currencyType == 2 then
|
||||||
|
processSealShop(player);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkBye", player);
|
||||||
|
callClientFunction(player, "eventTalkStepBreak", player);
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function processGilShop(player)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventGilShopMenuOpen", player);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
unk1, buyResult = callClientFunction(player, "eventGilShopMenuAsk", player);
|
||||||
|
printf(unk1);
|
||||||
|
if (buyResult == 0 or buyResult == -1) then
|
||||||
|
callClientFunction(player, "eventGilShopMenuClose", player);
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
if shopInfo[buyResult] == nil then
|
||||||
|
-- Prevent server crash from someone trying to buy a non-existent item via packet injection.
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
-- TODO: Add handling to check you're on the right NPC to prevent packet injecting a purchase from anything in the list
|
||||||
|
if shopInfo[buyResult][5] == 4 then
|
||||||
|
location = INVENTORY_KEYITEMS;
|
||||||
|
else
|
||||||
|
location = INVENTORY_NORMAL;
|
||||||
|
end
|
||||||
|
|
||||||
|
purchaseItem(player, location, shopInfo[buyResult][1], 1, 1, shopInfo[buyResult][3], gilCurrency);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function processSealShop(player)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventSealShopMenuOpen", player);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
unk1, buyResult = callClientFunction(player, "eventSealShopMenuAsk", player);
|
||||||
|
|
||||||
|
if (buyResult == 0 or buyResult == -1) then
|
||||||
|
callClientFunction(player, "eventSealShopMenuClose", player);
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
if shopInfo[buyResult] == nil then
|
||||||
|
-- Prevent server crash from someone trying to buy a non-existent item via packet injection.
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
-- TODO: Add handling to check you're on the right NPC to prevent packet injecting a purchase from anything in the list
|
||||||
|
if shopInfo[buyResult][5] == 4 then
|
||||||
|
location = INVENTORY_KEYITEMS;
|
||||||
|
else
|
||||||
|
location = INVENTORY_NORMAL;
|
||||||
|
end
|
||||||
|
|
||||||
|
purchaseItem(player, location, shopInfo[buyResult][1], 1, 1, shopInfo[buyResult][2], playerGCSeal);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceBountyPresenter Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventLowerLevel(player) -
|
||||||
|
eventAlreadyPresent(player) -
|
||||||
|
eventBeforePresent(player) -
|
||||||
|
eventAfterPresent(player) -
|
||||||
|
eventJail(player, bool) -
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventLowerLevel", player);
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
@ -0,0 +1,26 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceBranchVendor Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome(player) - Starts talk turn and
|
||||||
|
eventSearchItemAsk(nil, stopSearchingItemId) -
|
||||||
|
eventTalkStepBreak() - Finishes the talk turn.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkWelcome", player);
|
||||||
|
callClientFunction(player, "eventSearchItemAsk", nil, 0);
|
||||||
|
callClientFunction(player, "eventTalkStepBreak", player);
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
26
Data/scripts/base/chara/npc/populace/PopulaceCampMaster.lua
Normal file
26
Data/scripts/base/chara/npc/populace/PopulaceCampMaster.lua
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCampMaster Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
defTalk(player, favAetheryte1, favAetheryte2, favAetheryte3, playerLevel, ?) - The main and only function for this npc. If favAetheryte1 == 0, will not ask to remove others.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
favLocation = callClientFunction(player, "defTalk", player, 0, 1280004, 1280005);
|
||||||
|
|
||||||
|
--if (hasThree) then
|
||||||
|
--Remove chosen
|
||||||
|
--end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,31 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCampSubMaster Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
talkWelcome(player, level, ?) - Main npc function.
|
||||||
|
confirmUseFacility(player, gilAmount) - Confirm dialog if player uses facility.
|
||||||
|
finishTalkTurn() - Call to stop the npc staring at player.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
choice = callClientFunction(player, "talkWelcome", player, 1, false);
|
||||||
|
|
||||||
|
if (choice == 1) then
|
||||||
|
confirmed = callClientFunction(player, "confirmUseFacility", player, 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "finishTalkTurn");
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
@ -0,0 +1,41 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCaravanAdviser Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
adviserDeffault() - Not a typo. NPC dialog talking about a chocobo. Resets their sight on you, perhaps used on closing dialog?
|
||||||
|
adviserAsk() - Brings up a menu for caravan info, or purchasing gysahl greens
|
||||||
|
adviserAdvise() - NPC dialog discussing feeding chocobos
|
||||||
|
adviserSales(price) - Gysahl purchase dialog and prompt
|
||||||
|
adviserBuy() - Dialog to play after purchasing gysahl greens
|
||||||
|
adviserBuyNG() - NPC plays /shrug animation.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local gysahlPrice = 20;
|
||||||
|
local choice = callClientFunction(player, "adviserAsk");
|
||||||
|
|
||||||
|
if choice == 1 then
|
||||||
|
callClientFunction(player, "adviserAdvise");
|
||||||
|
elseif choice == 2 then
|
||||||
|
local purchaseChoice = callClientFunction(player, "adviserSales", gysahlPrice);
|
||||||
|
|
||||||
|
if purchaseChoice == 1 then
|
||||||
|
callClientFunction(player, "adviserBuy");
|
||||||
|
elseif purchaseChoice == 2 then
|
||||||
|
callClientFunction(player, "adviserBuyNG");
|
||||||
|
end
|
||||||
|
elseif choice == 3 then
|
||||||
|
callClientFunction(player, "adviserDeffault")
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,68 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCaravanGuide Script
|
||||||
|
|
||||||
|
This script handles the caravan guide class, which is for the actor who escorts the chocobos behind them during Caravan Security events.
|
||||||
|
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
caravanGuardCancel() - Menu prompt to abandon the caravan
|
||||||
|
|
||||||
|
caravanGuardReward(cargo, nil, areaName, playerGC, killCount, areaName2)
|
||||||
|
- Reward dialog for completing the caravan
|
||||||
|
- cargo = 0 (none) through 9 (all) for varying degrees of success dialog
|
||||||
|
- If playerGC doesn't match the GC of the areaName region, NPC mentions you don't need their seals.
|
||||||
|
- killCount shows an extra dialog if 40-49 enemies were slain, and a different one at 50+
|
||||||
|
|
||||||
|
caravanGuardNotReward() - Dialog stating you didn't contribute to the event at all
|
||||||
|
caravanGuardFailReward(areaName, areaName2) - Failure dialog, NPC offers free gysahl green, then offers free teleport back to aetheryte
|
||||||
|
caravanGuardThanks(name1, name2, name3) - Dialog for joining the caravan. NPC names the three chocobos. Name IDs from xtx_displayName
|
||||||
|
caravanGuardOffer(areaName, areaName2, playerGC) - Dialog for who to talk to for joining the caravan.
|
||||||
|
caravanGuardAmple(areaName, areaName2) - Dialog for NPC taking a break?
|
||||||
|
caravanGuardSuccess() - Dialog when you reached destination?
|
||||||
|
caravanGuardFailure(areaName, areaName2) - Failure dialog for mentioned area.
|
||||||
|
caravanGuardIgnore() - Resets NPC state for player? Or used for players not flagged for the event.
|
||||||
|
caravanGuardBonusReward(nil, isBonus?) - NPC says variation on a piece of dialog from the boolean passed
|
||||||
|
caravanGuardNotBonusReward() - Inventory full flavour dialog
|
||||||
|
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Functions employing areaName/areaName2 add their value together in the client's script to get the area name. Said area values are...
|
||||||
|
1 = Wineport, 2 = Quarrymill, 3 = Silver Bazaar, 4 = Aleport, 5 = Hyrstmill, 6 = Golden Bazaar
|
||||||
|
|
||||||
|
areaName will always be 1-3 for caravanGuardReward to function as expected for GC-related dialog
|
||||||
|
areaName2 will always be either 0 or 3. 0 for the lower level caravan area name, 3 for the higher level.
|
||||||
|
|
||||||
|
populaceCaravanGuide sheet:
|
||||||
|
ID Dialog Comment
|
||||||
|
6 It is time. Come, let us ride. - Caravan begins.
|
||||||
|
12 We've arrived at last! Come and speak to me when you're ready to claim your reward. - Caravan completed.
|
||||||
|
23 We're under attack! The chocobos! Protect the chocobos! - Caravan aggros monsters
|
||||||
|
27 Gods, have we already come this far? At this pace, we stand to make good time. - Says between 50% & 90% of the way to desgination? Can be said more than once per run
|
||||||
|
28 Well fought, friend. I thank the gods you're with us. Come, onward! - Cleared monsters that caravan aggro'd
|
||||||
|
|
||||||
|
TO-DO:
|
||||||
|
Document actors involved. Should be six of them.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local areaName = 1;
|
||||||
|
local areaName2 = 3;
|
||||||
|
local playerGC = 1;
|
||||||
|
local cargo = 9;
|
||||||
|
local killCount = 50;
|
||||||
|
callClientFunction(player, "caravanGuardOffer", areaName, areaName2, playerGC);
|
||||||
|
--callClientFunction(player, "caravanGuardReward", cargo, nil, areaName, playerGC, killCount, areaName2);
|
||||||
|
--player:SendGameMessageDisplayIDSender(npc, 6, MESSAGE_TYPE_SAY, npc.displayNameId);
|
||||||
|
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,49 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCaravanManager Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
caravanGuardEntry(areaGC, hasRoomForGCSeals, areaName, difficulty, playerGC, playerCountRequired, levelRequired)
|
||||||
|
- Dialog for signing up for caravan. areaGC(1-3) & areaName(0 or 3) added together to get location name.
|
||||||
|
- If difficulty => 40 on areaGC 1-3 & areaName 0, NPC mentions it's be a tougher trip
|
||||||
|
|
||||||
|
caravanGuardQuestion(areaName1, areaName2, escortMax, isSameGC?, playerGC?) - Ask about the caravan escort
|
||||||
|
caravanGuardJoinOK(areaName1, areaName2, playerGC) - Dialog for successfully joining the caravan
|
||||||
|
caravanGuardJoinNG(nil, maxEscorts, playerGC) - Dialog dictating how many escorts total filled the run.
|
||||||
|
caravanGuardAmple(nil, playerGC, playerGC) - Dialog for caravan escort being full.
|
||||||
|
caravanGuardOther(npcGC) - Dialog where NPC mentions you're not part of the given Grand Company parameter
|
||||||
|
caravanGuardSigh() - NPC does a shrug animation
|
||||||
|
caravanGuardHuh() - NPC does /huh
|
||||||
|
caravanGuardCancel(nil, playerGC) - Dialog for canceling caravan escort.
|
||||||
|
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
Some NPC dialog address you differently if your GC rank is Chief Sergeant (id 27) or higher, but only in non-English languages.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local GC = 3;
|
||||||
|
local playerGC = 1;
|
||||||
|
local areaName = 0;
|
||||||
|
local level = 25;
|
||||||
|
local playerCount = 8;
|
||||||
|
local difficulty = 41;
|
||||||
|
local hasRoomForGCSeals = false;
|
||||||
|
local isSameGC = true;
|
||||||
|
local escortMax = 8;
|
||||||
|
areaName1 = 1;
|
||||||
|
areaName2 = 3;
|
||||||
|
|
||||||
|
-- callClientFunction(player, "caravanGuardCancel", nil, 3);
|
||||||
|
|
||||||
|
callClientFunction(player, "caravanGuardEntry", GC, hasRoomForGCSeals, areaName, difficulty, playerGC, playerCount, level);
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
119
Data/scripts/base/chara/npc/populace/PopulaceChocoboLender.lua
Normal file
119
Data/scripts/base/chara/npc/populace/PopulaceChocoboLender.lua
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceChocoboLender Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome(player) - Start Text
|
||||||
|
eventAskMainMenu(player, curLevel, hasFundsForRent, isPresentChocoboIssuance, isSummonMyChocobo, isChangeBarding, currentChocoboWare) - Shows the main menu
|
||||||
|
eventTalkMyChocobo(player) - Starts the cutscene for getting a chocobo
|
||||||
|
eventSetChocoboName(true) - Opens the set name dialog
|
||||||
|
eventAfterChocoboName(player) - Called if player done naming chocobo, shows cutscene, returns state and waits to teleport outside city.
|
||||||
|
eventCancelChocoboName(player) - Called if player cancels naming chocobo, returns state.
|
||||||
|
eventTalkStepBreak(player) - Finishes talkTurn and says a goodbye
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* Rent price and time seems to be hardcoded into the client. Price is always 800gil and time is 10m.
|
||||||
|
* The func eventSetChocoboName *requires* the actor with id `1080101` to be present in the client instance or it will crash (thanks Jorge for finding that).
|
||||||
|
* Special spawn codes must be sent for getting your chocobo or renting for it to work properly.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
local rentalPrice = 800;
|
||||||
|
local rentalTime = 10;
|
||||||
|
|
||||||
|
local gcIssuances = {
|
||||||
|
[1500006] = 2001004,
|
||||||
|
[1500061] = 2001005,
|
||||||
|
[1000840] = 2001006
|
||||||
|
};
|
||||||
|
|
||||||
|
local startAppearances = {
|
||||||
|
[1500006] = CHOCOBO_LIMSA1,
|
||||||
|
[1500061] = CHOCOBO_GRIDANIA1,
|
||||||
|
[1000840] = CHOCOBO_ULDAH1
|
||||||
|
};
|
||||||
|
|
||||||
|
local cityExits = {
|
||||||
|
[1500006] = {133, -6.032, 46.356, 132.572, 3.034},
|
||||||
|
[1500061] = {150, 333.271, 5.889, -943.275, 0.794},
|
||||||
|
[1000840] = {170, -26.088, 181.846, -79.438, 2.579}
|
||||||
|
};
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local curLevel = 20; -- TODO: pull from character
|
||||||
|
local hasIssuance = player:GetItemPackage(INVENTORY_KEYITEMS):HasItem(gcIssuances[npc:GetActorClassId()]);
|
||||||
|
local hasChocobo = player.hasChocobo;
|
||||||
|
|
||||||
|
if (hasChocobo == false) then -- Let GMs auto have the issuance for debugging
|
||||||
|
hasIssuance = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
local hasFunds = (player:GetCurrentGil() >= rentalPrice);
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkWelcome", player);
|
||||||
|
|
||||||
|
local menuChoice = callClientFunction(player, "eventAskMainMenu", player, curLevel, hasFunds, hasIssuance, hasChocobo, hasChocobo, 0);
|
||||||
|
|
||||||
|
if (menuChoice == 1) then -- Issuance option
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkMyChocobo", player);
|
||||||
|
local nameResponse = callClientFunction(player, "eventSetChocoboName", true);
|
||||||
|
|
||||||
|
if (nameResponse == "") then -- Cancel Chocobo naming
|
||||||
|
callClientFunction(player, "eventCancelChocoboName", player);
|
||||||
|
callClientFunction(player, "eventTalkStepBreak", player);
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
local appearance = startAppearances[npc:GetActorClassId()];
|
||||||
|
player:IssueChocobo(appearance, nameResponse);
|
||||||
|
|
||||||
|
callClientFunction(player, "eventAfterChocoboName", player);
|
||||||
|
|
||||||
|
--Add Chocobo License and remove issuance
|
||||||
|
if (player:GetItemPackage(INVENTORY_KEYITEMS):HasItem(2001007) == false) then
|
||||||
|
player:GetItemPackage(INVENTORY_KEYITEMS):AddItem(2001007);
|
||||||
|
end
|
||||||
|
player:GetItemPackage(INVENTORY_KEYITEMS):RemoveItem(gcIssuances[npc:GetActorClassId()], 1);
|
||||||
|
|
||||||
|
--Warp with the special chocobo warp mode.
|
||||||
|
mountChocobo(player);
|
||||||
|
GetWorldManager():DoZoneChange(player, cityExits[npc:GetActorClassId()][1], nil, 0, SPAWN_CHOCOBO_GET, cityExits[npc:GetActorClassId()][2], cityExits[npc:GetActorClassId()][3], cityExits[npc:GetActorClassId()][4], cityExits[npc:GetActorClassId()][5]);
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif(menuChoice == 2) then -- Summon Bird
|
||||||
|
mountChocobo(player);
|
||||||
|
GetWorldManager():DoZoneChange(player, cityExits[npc:GetActorClassId()][1], nil, 0, SPAWN_NO_ANIM, cityExits[npc:GetActorClassId()][2], cityExits[npc:GetActorClassId()][3], cityExits[npc:GetActorClassId()][4], cityExits[npc:GetActorClassId()][5]);
|
||||||
|
elseif(menuChoice == 3) then -- Change Barding
|
||||||
|
callClientFunction(player, "eventTalkStepBreak", player);
|
||||||
|
elseif(menuChoice == 5) then -- Rent Bird
|
||||||
|
mountChocobo(player, true, 1);
|
||||||
|
GetWorldManager():DoZoneChange(player, cityExits[npc:GetActorClassId()][1], nil, 0, SPAWN_CHOCOBO_RENTAL, cityExits[npc:GetActorClassId()][2], cityExits[npc:GetActorClassId()][3], cityExits[npc:GetActorClassId()][4], cityExits[npc:GetActorClassId()][5]);
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkStepBreak", player);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
function mountChocobo(player, isRental, rentalMinutes)
|
||||||
|
if (isRental) then
|
||||||
|
player:ChangeMusic(64);
|
||||||
|
player:StartChocoboRental(rentalMinutes);
|
||||||
|
else
|
||||||
|
player:ChangeMusic(83);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:SendMountAppearance();
|
||||||
|
player:SetMountState(1);
|
||||||
|
player:ChangeSpeed(0.0, 5.0, 10.0, 10.0);
|
||||||
|
player:ChangeState(15);
|
||||||
|
end
|
@ -0,0 +1,43 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanyBuffer Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome(player, boolean) - Welcome dialog. Boolean seems to be related to rank?
|
||||||
|
eventTalkBufEffect() - Dialog for applying Sanction
|
||||||
|
eventTalkBufEffectAfter(player) - Dialog after applying Sanction
|
||||||
|
eventTalkStepBreak() - Returns to NPC's neutral state
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
local gcRep = {
|
||||||
|
[1500388] = 1, -- Maelstrom Representative
|
||||||
|
[1500389] = 2, -- Adder Representative
|
||||||
|
[1500390] = 3, -- Flame Representative
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local playerGC = player.gcCurrent;
|
||||||
|
local playerGCRanks = {player.gcRankLimsa, player.gcRankGridania, player.gcRankUldah};
|
||||||
|
|
||||||
|
local choice = callClientFunction(player, "eventTalkWelcome", player, true);
|
||||||
|
|
||||||
|
if (choice == 1 and playerGCRanks[playerGC] > 10 and playerGCRanks[playerGC] < 112) then
|
||||||
|
callClientFunction(player, "eventTalkBufEffect");
|
||||||
|
callClientFunction(player, "eventTalkBufEffectAfter", player);
|
||||||
|
-- TODO: Add Sanction buff
|
||||||
|
else
|
||||||
|
player:SendMessage(0x20, "", "Quit hex editing your memory.");
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
player:endEvent();
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,66 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanyGLPublisher Script
|
||||||
|
|
||||||
|
xtx_gcRank for GC Rank values
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
talkOutsider() - Dialog for no affiliated with GC. Seems to always read Maelstrom?
|
||||||
|
talkOfferWelcome(unk1) - Errors
|
||||||
|
askCompanyLeve() - Errors
|
||||||
|
askLeveDetail(unk1, unk2, unk3, unk4, unk5, unk6, unk7, unk8) - Errors
|
||||||
|
|
||||||
|
eventGLDifficulty() - Difficulty window, returns player choice
|
||||||
|
eventGLStart(leveName, difficulty, unk1) - leveName from xtx_guildleve
|
||||||
|
|
||||||
|
talkAfterOffer()
|
||||||
|
talkOfferLimit()
|
||||||
|
|
||||||
|
finishTalkTurn() - Resets NPC target/facing
|
||||||
|
|
||||||
|
eventGLPlay(leveName, guardianFavor, favorCost, difficulty) - Menu for active levequest
|
||||||
|
eventGLShinpu(guardianFavor, favorCost) - Menu to accept favor buff. evenGLPlay() calls it
|
||||||
|
eventGLThanks() - Errors
|
||||||
|
|
||||||
|
eventGLReward( -- Leve reward screen
|
||||||
|
guildleveId,
|
||||||
|
clearTime,
|
||||||
|
missionBonus,
|
||||||
|
difficultyBonus,
|
||||||
|
factionNumber,
|
||||||
|
factionBonus,
|
||||||
|
factionCredit,
|
||||||
|
glRewardItem,
|
||||||
|
glRewardNumber,
|
||||||
|
glRewardSubItem,
|
||||||
|
glRewardSubNumber,
|
||||||
|
difficulty
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
gcOfficer = {
|
||||||
|
[1500222] = 1, -- Storm Sergeant Hammil
|
||||||
|
[1500223] = 1, -- Storm Sergeant Sternn
|
||||||
|
[1500224] = 2, -- Serpent Sergeant Cordwyk
|
||||||
|
[1500225] = 2, -- Serpent Sergeant Lodall
|
||||||
|
[1500226] = 3, -- Flame Sergeant Byrne
|
||||||
|
[1500227] = 3, -- Flame Sergeant Dalvag
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
callClientFunction(player, "talkOutsider");
|
||||||
|
|
||||||
|
callClientFunction(player, "finishTalkTurn");
|
||||||
|
player:endEvent();
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanyGuide Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome() - Dialog for new recruits
|
||||||
|
eventTalkProvisional() - Message for when rank isn't high enough?
|
||||||
|
eventTalkExclusive() - Message for wrong GC.
|
||||||
|
eventTalkComMember(nil, npc, isFoundationDay) - Information menus for various GC related activities
|
||||||
|
eventTalkStepBreak() - Returns to NPC's neutral state
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
local gcRep = {
|
||||||
|
[1001737] = 1, -- Maelstrom Representative
|
||||||
|
[1001738] = 2, -- Adder Representative
|
||||||
|
[1001739] = 3, -- Flame Representative
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local playerGC = player.gcCurrent;
|
||||||
|
local playerGCRanks = {player.gcRankLimsa, player.gcRankGridania, player.gcRankUldah};
|
||||||
|
local npcGC = gcRep[npc:GetActorClassId()];
|
||||||
|
|
||||||
|
if (playerGC ~= npcGC and playerGCRanks[playerGC] == 127) then
|
||||||
|
callClientFunction(player, "eventTalkWelcome");
|
||||||
|
elseif (playerGC == npcGC and playerGCRanks[playerGC] == 127) then
|
||||||
|
callClientFunction(player, "eventTalkProvisional");
|
||||||
|
elseif (playerGC ~= npcGC and playerGCRanks[playerGC] ~= 127) then
|
||||||
|
callClientFunction(player, "eventTalkExclusive");
|
||||||
|
elseif (playerGC == npcGC and playerGCRanks[playerGC] > 10 and playerGCRanks[playerGC] < 112) then
|
||||||
|
callClientFunction(player, "eventTalkComMember", nil, npc, true);
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
player:endEvent();
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,77 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanyOfficer Script
|
||||||
|
|
||||||
|
xtx_gcRank for GC Rank values
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome() - Welcome dialog
|
||||||
|
eventTalkWelcomeQuest() - Same as Welcome dialog?
|
||||||
|
eventTalkPreJoin() - Dialog for starting GC rank?
|
||||||
|
eventTalkExclusive() - Dialog to play when you're not of that GC?
|
||||||
|
eventTalkJoinedOnly() - Reads like chat-end dialog for your GC.
|
||||||
|
eventTalkJoined(gcRank, gcRank, isCanAfford, isShowPromotion) - Menu to ask about/for promotion
|
||||||
|
|
||||||
|
eventDoRankUp(gcRank, gcRank) - Plays rank-up animation and opens GC window.
|
||||||
|
eventRankUpDone(???, ???) - Has your character do the GC salute? Values seem to do nothing?
|
||||||
|
eventRankCategoryUpBefore(gcRank) - 11/21/31 - Mentions which GC quest you need to clear to continue promotion
|
||||||
|
eventRankCategoryUpAfter() - Follow-up dialog after ranking up
|
||||||
|
eventTalkQuestUncomplete() - Quest prerequisite dialog for ranking up to Second Lieutenant (1.23b rank cap)
|
||||||
|
eventTalkFestival() - Foundation Day 2011 event dialog. Server needs to reward 1000 GC seals after.
|
||||||
|
eventTalkFestival2() - Foundation Day 2011 event dialog. Seems to reward more seals, unsure how many.
|
||||||
|
eventTalkFestival2012(value) - Foundation Day 2012 event dialog. Rewards amount of seals dictated by value, retail used 5000.
|
||||||
|
|
||||||
|
eventTalkStepBreak() - Resets NPC target/facing
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
gcOfficer = {
|
||||||
|
[1500199] = 1, -- Limsa Officer
|
||||||
|
[1500200] = 2, -- Grid Officer
|
||||||
|
[1500198] = 3, -- Flame Officer
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
playerGC = player.gcCurrent;
|
||||||
|
playerGCSeal = 1000200 + playerGC;
|
||||||
|
playerCurrentRank = 13;
|
||||||
|
playerRankUpCost = 1500;
|
||||||
|
playerNextRank = 15;
|
||||||
|
currentRankCap = 31; -- Second Lieutenant
|
||||||
|
npcId = npc:GetActorClassId();
|
||||||
|
|
||||||
|
if playerGC == gcOfficer[npcId] then
|
||||||
|
callClientFunction(player, "eventTalkWelcome");
|
||||||
|
if playerCurrentRank < currentRankCap then
|
||||||
|
if player:GetItemPackage(INVENTORY_CURRENCY):HasItem(playerGCSeal, playerRankUpCost) then
|
||||||
|
-- Show Promotion window, allow paying
|
||||||
|
local choice = callClientFunction(player, "eventTalkJoined", playerCurrentRank, playerNextRank, true, true);
|
||||||
|
|
||||||
|
-- If promotion accepted
|
||||||
|
if choice == 1 then
|
||||||
|
callClientFunction(player, "eventDoRankUp", playerNextRank, playerNextRank);
|
||||||
|
-- TODO: Table GC info or get it in source/sql. Handle actual upgrade of GC rank/seal cap/cost/etc.
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Show Promotion window, show dialog you can't afford promotion
|
||||||
|
callClientFunction(player, "eventTalkJoined", playerCurrentRank, playerNextRank, false, true);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkJoined", playerCurrentRank, playerNextRank);
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkJoinedOnly");
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkExclusive");
|
||||||
|
end
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
player:endEvent();
|
||||||
|
end
|
510
Data/scripts/base/chara/npc/populace/PopulaceCompanyShop.lua
Normal file
510
Data/scripts/base/chara/npc/populace/PopulaceCompanyShop.lua
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanyShop Script
|
||||||
|
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkStepCantUse() -- When player tries to buy from another GC's shop
|
||||||
|
eventTalkPreJoin() -- Dialog for the shop
|
||||||
|
eventTalkPreJoinQuest() -- Tutorial dialog for the shop?
|
||||||
|
eventTalkJoined(???) -- Dialog for the shop, they salute. Orphaned parameter?
|
||||||
|
|
||||||
|
eventTalkFestival() -- Festival Day Event Dialog
|
||||||
|
eventTalkFestival2() -- Festival Day Event Follow-up Dialog
|
||||||
|
|
||||||
|
eventTalkMainMenu(???, ???) -- Shop menu for picking GC items
|
||||||
|
eventShopMenuOpen() -- Sets up shop menu. Calls getSpecialEventWork, value 8 shows GC firework & 11 a Patriot's Choker
|
||||||
|
eventShopMenuAsk() -- Opens up the shop menu.
|
||||||
|
eventShopMenuClose()
|
||||||
|
|
||||||
|
eventGuideChocoboWhistle(???) -- Tutorial dialog after purchasing Chocobo issuance slip. Orphaned parameter?
|
||||||
|
eventGuideTownTransport(index) -- Tutorial dialog after purchasing an aetherpass. Index is item ID.
|
||||||
|
eventAskChocoboCustomize(index, price) -- Chocobo Barding purchase dialog. Index is item ID.
|
||||||
|
eventChocoboCustomize() -- Follow-up dialog if you purchase Chocobo Barding.
|
||||||
|
|
||||||
|
getGrandCompanyNumber() -- Returns GC value of the NPC
|
||||||
|
getShopItemStartIndex(index) -- Gets starting index value based on GC shop
|
||||||
|
getShopItemEndIndex(index) -- Gets ending index value based on GC shop
|
||||||
|
getShopSellingItemMax(???) --
|
||||||
|
getShopSellingItemDetail(player, ???, ???)
|
||||||
|
|
||||||
|
eventTalkStepBreak() -- Returns NPC to their starting direction
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("shop")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
gcOfficer = {
|
||||||
|
[1500202] = 1, -- Limsa Shop
|
||||||
|
[1500203] = 2, -- Grid Shop
|
||||||
|
[1500201] = 3, -- Flame Shop
|
||||||
|
}
|
||||||
|
|
||||||
|
shopInfo = { -- [index] = { itemID, itemQuality, itemQuantity, itemCost, gcRank, city, special, itemCategory }
|
||||||
|
[100001] = {3010403, 1, 10, 20, 0, 1, 0, 1},
|
||||||
|
[100002] = {3010402, 1, 10, 30, 0, 1, 0, 1},
|
||||||
|
[100003] = {3020202, 1, 1, 50, 0, 1, 0, 1},
|
||||||
|
[100004] = {3020406, 1, 20, 10, 0, 1, 0, 1},
|
||||||
|
[100005] = {3020403, 1, 10, 15, 0, 1, 0, 1},
|
||||||
|
[100006] = {3020402, 1, 5, 60, 0, 1, 0, 1},
|
||||||
|
[100007] = {3020404, 1, 5, 100, 0, 1, 0, 1},
|
||||||
|
[100008] = {3020528, 1, 5, 50, 0, 1, 0, 1},
|
||||||
|
[100009] = {3020516, 1, 5, 50, 0, 1, 0, 1},
|
||||||
|
[100010] = {3020411, 1, 1, 15, 0, 1, 0, 1},
|
||||||
|
[100011] = {3020412, 1, 1, 200, 0, 1, 0, 1},
|
||||||
|
[100012] = {3020509, 1, 1, 200, 0, 1, 0, 1},
|
||||||
|
[100013] = {3020510, 1, 1, 200, 0, 1, 0, 1},
|
||||||
|
[100014] = {10013001, 1, 20, 5, 0, 1, 0, 1},
|
||||||
|
[100015] = {10013002, 1, 20, 25, 0, 1, 0, 1},
|
||||||
|
[100016] = {10013003, 1, 20, 45, 0, 1, 0, 1},
|
||||||
|
[100017] = {10013004, 1, 20, 100, 0, 1, 0, 1},
|
||||||
|
[100018] = {10013005, 1, 20, 150, 0, 1, 0, 1},
|
||||||
|
[100019] = {3910402, 1, 99, 85, 0, 1, 0, 1},
|
||||||
|
[100020] = {3910103, 1, 99, 120, 0, 1, 0, 1},
|
||||||
|
[100021] = {3910203, 1, 99, 120, 0, 1, 0, 1},
|
||||||
|
[100022] = {3910305, 1, 99, 85, 0, 1, 0, 1},
|
||||||
|
[100023] = {3920004, 1, 999, 50, 0, 1, 0, 1},
|
||||||
|
[100024] = {3920006, 1, 999, 70, 0, 1, 0, 1},
|
||||||
|
[100025] = {3920003, 1, 999, 115, 0, 1, 0, 1},
|
||||||
|
[100026] = {3910005, 1, 99, 75, 0, 1, 0, 1},
|
||||||
|
[100027] = {3910006, 1, 99, 90, 0, 1, 0, 1},
|
||||||
|
[100028] = {3940011, 1, 20, 20, 0, 1, 0, 1},
|
||||||
|
[100029] = {3940010, 1, 20, 30, 0, 1, 0, 1},
|
||||||
|
[100030] = {3020504, 1, 1, 400, 15, 1, 0, 1},
|
||||||
|
[100031] = {3020505, 1, 1, 400, 15, 1, 0, 1},
|
||||||
|
[100032] = {3020506, 1, 1, 300, 31, 1, 0, 1},
|
||||||
|
[101001] = {4040010, 1, 1, 500, 0, 1, 0, 2},
|
||||||
|
[101002] = {4040110, 1, 1, 1000, 0, 1, 0, 2},
|
||||||
|
[101003] = {4040205, 1, 1, 1400, 0, 1, 0, 2},
|
||||||
|
[101004] = {4040305, 1, 1, 3000, 0, 1, 0, 2},
|
||||||
|
[101005] = {4040204, 1, 1, 4000, 0, 1, 0, 2},
|
||||||
|
[101006] = {4080304, 1, 1, 950, 0, 1, 0, 2},
|
||||||
|
[101007] = {4080211, 1, 1, 1000, 0, 1, 0, 2},
|
||||||
|
[101008] = {4080106, 1, 1, 2000, 0, 1, 0, 2},
|
||||||
|
[101009] = {4080303, 1, 1, 4000, 0, 1, 0, 2},
|
||||||
|
[101010] = {5020010, 1, 1, 900, 0, 1, 0, 2},
|
||||||
|
[101011] = {5020209, 1, 1, 1000, 0, 1, 0, 2},
|
||||||
|
[101012] = {5020213, 1, 1, 1600, 0, 1, 0, 2},
|
||||||
|
[101013] = {5020305, 1, 1, 4000, 0, 1, 0, 2},
|
||||||
|
[101014] = {8030350, 1, 1, 750, 0, 1, 0, 2},
|
||||||
|
[101015] = {8030447, 1, 1, 750, 0, 1, 0, 2},
|
||||||
|
[101016] = {8031223, 1, 1, 750, 0, 1, 0, 2},
|
||||||
|
[101017] = {8032008, 1, 1, 750, 0, 1, 0, 2},
|
||||||
|
[101018] = {9050029, 1, 1, 900, 0, 1, 0, 2},
|
||||||
|
[101019] = {9050044, 1, 1, 1900, 0, 1, 0, 2},
|
||||||
|
[101020] = {9040032, 1, 1, 950, 0, 1, 0, 2},
|
||||||
|
[101021] = {9040025, 1, 1, 1500, 0, 1, 0, 2},
|
||||||
|
[101022] = {8013201, 1, 1, 1000, 11, 1, 0, 2},
|
||||||
|
[101023] = {8032601, 1, 1, 1000, 11, 1, 0, 2},
|
||||||
|
[101024] = {8071301, 1, 1, 1000, 11, 1, 0, 2},
|
||||||
|
[101025] = {8081701, 1, 1, 1000, 11, 1, 0, 2},
|
||||||
|
[101026] = {8050620, 1, 1, 1200, 11, 1, 0, 2},
|
||||||
|
[101027] = {8050243, 1, 1, 1200, 11, 1, 0, 2},
|
||||||
|
[101028] = {8050344, 1, 1, 1200, 11, 1, 0, 2},
|
||||||
|
[101029] = {8050028, 1, 1, 1200, 11, 1, 0, 2},
|
||||||
|
[101030] = {8090706, 1, 1, 1200, 11, 1, 0, 2},
|
||||||
|
[101031] = {4030205, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101032] = {4020306, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101033] = {4040014, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101034] = {4080408, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101035] = {4070310, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101036] = {5030307, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101037] = {5020112, 1, 1, 2500, 13, 1, 0, 2},
|
||||||
|
[101038] = {4100205, 1, 1, 2000, 13, 1, 0, 2},
|
||||||
|
[101039] = {8011609, 1, 1, 3000, 15, 1, 0, 2},
|
||||||
|
[101040] = {8032311, 1, 1, 3000, 15, 1, 0, 2},
|
||||||
|
[101041] = {8071017, 1, 1, 3000, 15, 1, 0, 2},
|
||||||
|
[101042] = {8050132, 1, 1, 3000, 15, 1, 0, 2},
|
||||||
|
[101043] = {8081123, 1, 1, 3000, 15, 1, 0, 2},
|
||||||
|
[101044] = {4030117, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101045] = {4020210, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101046] = {4040406, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101047] = {4080107, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101048] = {4070108, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101049] = {5030111, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101050] = {5020013, 1, 1, 4500, 17, 1, 0, 2},
|
||||||
|
[101051] = {4100405, 1, 1, 4000, 17, 1, 0, 2},
|
||||||
|
[101052] = {8011610, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101053] = {8032312, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101054] = {8071018, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101055] = {8050133, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101056] = {8050769, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101057] = {8081124, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101058] = {8080565, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101059] = {8090609, 1, 1, 5000, 21, 1, 0, 2},
|
||||||
|
[101060] = {9050021, 1, 1, 1000, 21, 1, 0, 2},
|
||||||
|
[101061] = {9050022, 1, 1, 1000, 21, 1, 0, 2},
|
||||||
|
[101062] = {9010025, 1, 1, 1000, 21, 1, 0, 2},
|
||||||
|
[101063] = {4100804, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101064] = {8013614, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101065] = {8032820, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101066] = {8051516, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101067] = {8071520, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101068] = {9030060, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101069] = {9050067, 1, 1, 5500, 23, 1, 0, 2},
|
||||||
|
[101070] = {8013615, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101071] = {8013616, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101072] = {8032821, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101073] = {8071521, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101074] = {8081914, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101075] = {9040065, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101076] = {9010061, 1, 1, 6000, 25, 1, 0, 2},
|
||||||
|
[101077] = {4100805, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101078] = {4020408, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101079] = {4040508, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101080] = {4080508, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101081] = {4070408, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101082] = {5030408, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101083] = {5020408, 1, 1, 6500, 27, 1, 0, 2},
|
||||||
|
[101084] = {4030604, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101085] = {4020404, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101086] = {4040504, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101087] = {4080504, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101088] = {4070404, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101089] = {5030404, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101090] = {5020404, 1, 1, 25000, 31, 1, 0, 2},
|
||||||
|
[101091] = {8013204, 1, 1, 6000, 31, 1, 0, 2},
|
||||||
|
[101092] = {8032604, 1, 1, 6000, 31, 1, 0, 2},
|
||||||
|
[101093] = {8071304, 1, 1, 6000, 31, 1, 0, 2},
|
||||||
|
[101094] = {8081704, 1, 1, 6000, 31, 1, 0, 2},
|
||||||
|
[102001] = {3020601, 1, 20, 5, 0, 1, 8, 3},
|
||||||
|
[102002] = {9040018, 1, 1, 1000, 11, 1, 11, 3},
|
||||||
|
[103001] = {2001004, 1, 1, 3000, 11, 1, 0, 4},
|
||||||
|
[103002] = {2001014, 1, 1, 3000, 15, 1, 0, 4},
|
||||||
|
[103003] = {2001017, 1, 1, 2000, 21, 1, 0, 4},
|
||||||
|
[103004] = {2001018, 1, 1, 3000, 21, 1, 0, 4},
|
||||||
|
[103005] = {2001019, 1, 1, 4000, 21, 1, 0, 4},
|
||||||
|
[103006] = {2001026, 1, 1, 25000, 27, 1, 0, 4},
|
||||||
|
[200001] = {3010403, 1, 10, 20, 0, 2, 0, 1},
|
||||||
|
[200002] = {3010402, 1, 10, 30, 0, 2, 0, 1},
|
||||||
|
[200003] = {3020203, 1, 1, 50, 0, 2, 0, 1},
|
||||||
|
[200004] = {3020406, 1, 20, 10, 0, 2, 0, 1},
|
||||||
|
[200005] = {3020403, 1, 10, 15, 0, 2, 0, 1},
|
||||||
|
[200006] = {3020402, 1, 5, 60, 0, 2, 0, 1},
|
||||||
|
[200007] = {3020404, 1, 5, 100, 0, 2, 0, 1},
|
||||||
|
[200008] = {3020528, 1, 5, 50, 0, 2, 0, 1},
|
||||||
|
[200009] = {3020516, 1, 5, 50, 0, 2, 0, 1},
|
||||||
|
[200010] = {3020411, 1, 1, 15, 0, 2, 0, 1},
|
||||||
|
[200011] = {3020412, 1, 1, 200, 0, 2, 0, 1},
|
||||||
|
[200012] = {3020509, 1, 1, 200, 0, 2, 0, 1},
|
||||||
|
[200013] = {3020510, 1, 1, 200, 0, 2, 0, 1},
|
||||||
|
[200014] = {10013001, 1, 20, 5, 0, 2, 0, 1},
|
||||||
|
[200015] = {10013002, 1, 20, 25, 0, 2, 0, 1},
|
||||||
|
[200016] = {10013003, 1, 20, 45, 0, 2, 0, 1},
|
||||||
|
[200017] = {10013004, 1, 20, 100, 0, 2, 0, 1},
|
||||||
|
[200018] = {10013005, 1, 20, 150, 0, 2, 0, 1},
|
||||||
|
[200019] = {3910402, 1, 99, 85, 0, 2, 0, 1},
|
||||||
|
[200020] = {3910103, 1, 99, 120, 0, 2, 0, 1},
|
||||||
|
[200021] = {3910203, 1, 99, 120, 0, 2, 0, 1},
|
||||||
|
[200022] = {3910305, 1, 99, 85, 0, 2, 0, 1},
|
||||||
|
[200023] = {3920004, 1, 999, 50, 0, 2, 0, 1},
|
||||||
|
[200024] = {3920006, 1, 999, 70, 0, 2, 0, 1},
|
||||||
|
[200025] = {3920003, 1, 999, 115, 0, 2, 0, 1},
|
||||||
|
[200026] = {3910005, 1, 99, 75, 0, 2, 0, 1},
|
||||||
|
[200027] = {3910006, 1, 99, 90, 0, 2, 0, 1},
|
||||||
|
[200028] = {3940011, 1, 20, 20, 0, 2, 0, 1},
|
||||||
|
[200029] = {3940010, 1, 20, 30, 0, 2, 0, 1},
|
||||||
|
[200030] = {3020504, 1, 1, 400, 15, 2, 0, 1},
|
||||||
|
[200031] = {3020505, 1, 1, 400, 15, 2, 0, 1},
|
||||||
|
[200032] = {3020506, 1, 1, 300, 31, 2, 0, 1},
|
||||||
|
[201001] = {5030107, 1, 1, 350, 0, 2, 0, 2},
|
||||||
|
[201002] = {5030207, 1, 1, 750, 0, 2, 0, 2},
|
||||||
|
[201003] = {5030206, 1, 1, 1000, 0, 2, 0, 2},
|
||||||
|
[201004] = {5030029, 1, 1, 1500, 0, 2, 0, 2},
|
||||||
|
[201005] = {5030031, 1, 1, 2400, 0, 2, 0, 2},
|
||||||
|
[201006] = {5030209, 1, 1, 3000, 0, 2, 0, 2},
|
||||||
|
[201007] = {5030028, 1, 1, 4000, 0, 2, 0, 2},
|
||||||
|
[201008] = {4020109, 1, 1, 800, 0, 2, 0, 2},
|
||||||
|
[201009] = {4020106, 1, 1, 1000, 0, 2, 0, 2},
|
||||||
|
[201010] = {4020008, 1, 1, 2200, 0, 2, 0, 2},
|
||||||
|
[201011] = {4020305, 1, 1, 4000, 0, 2, 0, 2},
|
||||||
|
[201012] = {4100005, 1, 1, 1000, 0, 2, 0, 2},
|
||||||
|
[201013] = {4100109, 1, 1, 4000, 0, 2, 0, 2},
|
||||||
|
[201014] = {8030035, 1, 1, 750, 0, 2, 0, 2},
|
||||||
|
[201015] = {8030919, 1, 1, 750, 0, 2, 0, 2},
|
||||||
|
[201016] = {8031821, 1, 1, 750, 0, 2, 0, 2},
|
||||||
|
[201017] = {8032220, 1, 1, 750, 0, 2, 0, 2},
|
||||||
|
[201018] = {9050029, 1, 1, 900, 0, 2, 0, 2},
|
||||||
|
[201019] = {9050044, 1, 1, 1900, 0, 2, 0, 2},
|
||||||
|
[201020] = {9040035, 1, 1, 950, 0, 2, 0, 2},
|
||||||
|
[201021] = {9040025, 1, 1, 1500, 0, 2, 0, 2},
|
||||||
|
[201022] = {8013202, 1, 1, 1000, 11, 2, 0, 2},
|
||||||
|
[201023] = {8032602, 1, 1, 1000, 11, 2, 0, 2},
|
||||||
|
[201024] = {8071302, 1, 1, 1000, 11, 2, 0, 2},
|
||||||
|
[201025] = {8081702, 1, 1, 1000, 11, 2, 0, 2},
|
||||||
|
[201026] = {8050148, 1, 1, 1200, 11, 2, 0, 2},
|
||||||
|
[201027] = {8050244, 1, 1, 1200, 11, 2, 0, 2},
|
||||||
|
[201028] = {8051222, 1, 1, 1200, 11, 2, 0, 2},
|
||||||
|
[201029] = {8050029, 1, 1, 1200, 11, 2, 0, 2},
|
||||||
|
[201030] = {8090707, 1, 1, 1200, 11, 2, 0, 2},
|
||||||
|
[201031] = {4030710, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201032] = {4020211, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201033] = {4040407, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201034] = {4080213, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201035] = {4070215, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201036] = {5030113, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201037] = {5020014, 1, 1, 2500, 13, 2, 0, 2},
|
||||||
|
[201038] = {4100608, 1, 1, 2000, 13, 2, 0, 2},
|
||||||
|
[201039] = {8010566, 1, 1, 3000, 15, 2, 0, 2},
|
||||||
|
[201040] = {8030625, 1, 1, 3000, 15, 2, 0, 2},
|
||||||
|
[201041] = {8070724, 1, 1, 3000, 15, 2, 0, 2},
|
||||||
|
[201042] = {8050618, 1, 1, 3000, 15, 2, 0, 2},
|
||||||
|
[201043] = {8080715, 1, 1, 3000, 15, 2, 0, 2},
|
||||||
|
[201044] = {4030016, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201045] = {4020012, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201046] = {4040111, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201047] = {4080010, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201048] = {4070013, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201049] = {5030308, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201050] = {5020113, 1, 1, 4500, 17, 2, 0, 2},
|
||||||
|
[201051] = {4100507, 1, 1, 4000, 17, 2, 0, 2},
|
||||||
|
[201052] = {8010567, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201053] = {8030626, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201054] = {8070725, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201055] = {8050619, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201056] = {8050768, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201057] = {8080716, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201058] = {8080564, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201059] = {8090506, 1, 1, 5000, 21, 2, 0, 2},
|
||||||
|
[201060] = {9050025, 1, 1, 1000, 21, 2, 0, 2},
|
||||||
|
[201061] = {9050026, 1, 1, 1000, 21, 2, 0, 2},
|
||||||
|
[201062] = {9010025, 1, 1, 1000, 21, 2, 0, 2},
|
||||||
|
[201063] = {4100806, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201064] = {8013617, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201065] = {8032822, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201066] = {8051517, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201067] = {8071522, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201068] = {9030061, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201069] = {9050068, 1, 1, 5500, 23, 2, 0, 2},
|
||||||
|
[201070] = {8013618, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201071] = {8013619, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201072] = {8032823, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201073] = {8071523, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201074] = {8081915, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201075] = {9040066, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201076] = {9010062, 1, 1, 6000, 25, 2, 0, 2},
|
||||||
|
[201077] = {4100807, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201078] = {4020409, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201079] = {4040509, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201080] = {4080509, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201081] = {4070409, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201082] = {5030409, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201083] = {5020409, 1, 1, 6500, 27, 2, 0, 2},
|
||||||
|
[201084] = {4030605, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201085] = {4020405, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201086] = {4040505, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201087] = {4080505, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201088] = {4070405, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201089] = {5030405, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201090] = {5020405, 1, 1, 25000, 31, 2, 0, 2},
|
||||||
|
[201091] = {8013205, 1, 1, 6000, 31, 2, 0, 2},
|
||||||
|
[201092] = {8032605, 1, 1, 6000, 31, 2, 0, 2},
|
||||||
|
[201093] = {8071305, 1, 1, 6000, 31, 2, 0, 2},
|
||||||
|
[201094] = {8081705, 1, 1, 6000, 31, 2, 0, 2},
|
||||||
|
[202001] = {3020603, 1, 20, 5, 0, 2, 8, 3},
|
||||||
|
[202002] = {9040018, 1, 1, 1000, 11, 2, 11, 3},
|
||||||
|
[203001] = {2001005, 1, 1, 3000, 11, 2, 0, 4},
|
||||||
|
[203002] = {2001015, 1, 1, 3000, 15, 2, 0, 4},
|
||||||
|
[203003] = {2001020, 1, 1, 2000, 21, 2, 0, 4},
|
||||||
|
[203004] = {2001021, 1, 1, 3000, 21, 2, 0, 4},
|
||||||
|
[203005] = {2001022, 1, 1, 4000, 21, 2, 0, 4},
|
||||||
|
[203006] = {2001026, 1, 1, 25000, 27, 2, 0, 4},
|
||||||
|
[300001] = {3010403, 1, 10, 20, 0, 3, 0, 1},
|
||||||
|
[300002] = {3010402, 1, 10, 30, 0, 3, 0, 1},
|
||||||
|
[300003] = {3020204, 1, 1, 50, 0, 3, 0, 1},
|
||||||
|
[300004] = {3020406, 1, 20, 10, 0, 3, 0, 1},
|
||||||
|
[300005] = {3020403, 1, 10, 15, 0, 3, 0, 1},
|
||||||
|
[300006] = {3020402, 1, 5, 60, 0, 3, 0, 1},
|
||||||
|
[300007] = {3020404, 1, 5, 100, 0, 3, 0, 1},
|
||||||
|
[300008] = {3020528, 1, 5, 50, 0, 3, 0, 1},
|
||||||
|
[300009] = {3020516, 1, 5, 50, 0, 3, 0, 1},
|
||||||
|
[300010] = {3020411, 1, 1, 15, 0, 3, 0, 1},
|
||||||
|
[300011] = {3020412, 1, 1, 200, 0, 3, 0, 1},
|
||||||
|
[300012] = {3020509, 1, 1, 200, 0, 3, 0, 1},
|
||||||
|
[300013] = {3020510, 1, 1, 200, 0, 3, 0, 1},
|
||||||
|
[300014] = {10013001, 1, 20, 5, 0, 3, 0, 1},
|
||||||
|
[300015] = {10013002, 1, 20, 25, 0, 3, 0, 1},
|
||||||
|
[300016] = {10013003, 1, 20, 45, 0, 3, 0, 1},
|
||||||
|
[300017] = {10013004, 1, 20, 100, 0, 3, 0, 1},
|
||||||
|
[300018] = {10013005, 1, 20, 150, 0, 3, 0, 1},
|
||||||
|
[300019] = {3910402, 1, 99, 85, 0, 3, 0, 1},
|
||||||
|
[300020] = {3910103, 1, 99, 120, 0, 3, 0, 1},
|
||||||
|
[300021] = {3910203, 1, 99, 120, 0, 3, 0, 1},
|
||||||
|
[300022] = {3910305, 1, 99, 85, 0, 3, 0, 1},
|
||||||
|
[300023] = {3920004, 1, 999, 50, 0, 3, 0, 1},
|
||||||
|
[300024] = {3920006, 1, 999, 70, 0, 3, 0, 1},
|
||||||
|
[300025] = {3920003, 1, 999, 115, 0, 3, 0, 1},
|
||||||
|
[300026] = {3910005, 1, 99, 75, 0, 3, 0, 1},
|
||||||
|
[300027] = {3910006, 1, 99, 90, 0, 3, 0, 1},
|
||||||
|
[300028] = {3940011, 1, 20, 20, 0, 3, 0, 1},
|
||||||
|
[300029] = {3940010, 1, 20, 30, 0, 3, 0, 1},
|
||||||
|
[300030] = {3020504, 1, 1, 400, 15, 3, 0, 1},
|
||||||
|
[300031] = {3020505, 1, 1, 400, 15, 3, 0, 1},
|
||||||
|
[300032] = {3020506, 1, 1, 300, 31, 3, 0, 1},
|
||||||
|
[301001] = {4030006, 1, 1, 400, 0, 3, 0, 2},
|
||||||
|
[301002] = {4030015, 1, 1, 1000, 0, 3, 0, 2},
|
||||||
|
[301003] = {4030405, 1, 1, 1600, 0, 3, 0, 2},
|
||||||
|
[301004] = {4030506, 1, 1, 3200, 0, 3, 0, 2},
|
||||||
|
[301005] = {4030505, 1, 1, 4000, 0, 3, 0, 2},
|
||||||
|
[301006] = {4070011, 1, 1, 550, 0, 3, 0, 2},
|
||||||
|
[301007] = {4070105, 1, 1, 1000, 0, 3, 0, 2},
|
||||||
|
[301008] = {4070212, 1, 1, 1500, 0, 3, 0, 2},
|
||||||
|
[301009] = {4070211, 1, 1, 4000, 0, 3, 0, 2},
|
||||||
|
[301010] = {4100710, 1, 1, 450, 0, 3, 0, 2},
|
||||||
|
[301011] = {4100403, 1, 1, 1000, 0, 3, 0, 2},
|
||||||
|
[301012] = {4100404, 1, 1, 1900, 0, 3, 0, 2},
|
||||||
|
[301013] = {4100306, 1, 1, 4000, 0, 3, 0, 2},
|
||||||
|
[301014] = {8030248, 1, 1, 750, 0, 3, 0, 2},
|
||||||
|
[301015] = {8030548, 1, 1, 750, 0, 3, 0, 2},
|
||||||
|
[301016] = {8031021, 1, 1, 750, 0, 3, 0, 2},
|
||||||
|
[301017] = {8031513, 1, 1, 750, 0, 3, 0, 2},
|
||||||
|
[301018] = {9050029, 1, 1, 900, 0, 3, 0, 2},
|
||||||
|
[301019] = {9050044, 1, 1, 1900, 0, 3, 0, 2},
|
||||||
|
[301020] = {9040036, 1, 1, 950, 0, 3, 0, 2},
|
||||||
|
[301021] = {9040025, 1, 1, 1500, 0, 3, 0, 2},
|
||||||
|
[301022] = {8013203, 1, 1, 1000, 11, 3, 0, 2},
|
||||||
|
[301023] = {8032603, 1, 1, 1000, 11, 3, 0, 2},
|
||||||
|
[301024] = {8071303, 1, 1, 1000, 11, 3, 0, 2},
|
||||||
|
[301025] = {8081703, 1, 1, 1000, 11, 3, 0, 2},
|
||||||
|
[301026] = {8050520, 1, 1, 1200, 11, 3, 0, 2},
|
||||||
|
[301027] = {8051024, 1, 1, 1200, 11, 3, 0, 2},
|
||||||
|
[301028] = {8050345, 1, 1, 1200, 11, 3, 0, 2},
|
||||||
|
[301029] = {8050449, 1, 1, 1200, 11, 3, 0, 2},
|
||||||
|
[301030] = {8090708, 1, 1, 1200, 11, 3, 0, 2},
|
||||||
|
[301031] = {4030305, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301032] = {4020011, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301033] = {4040208, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301034] = {4080306, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301035] = {4070012, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301036] = {5030037, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301037] = {5020217, 1, 1, 2500, 13, 3, 0, 2},
|
||||||
|
[301038] = {4100112, 1, 1, 2000, 13, 3, 0, 2},
|
||||||
|
[301039] = {8011522, 1, 1, 3000, 15, 3, 0, 2},
|
||||||
|
[301040] = {8030744, 1, 1, 3000, 15, 3, 0, 2},
|
||||||
|
[301041] = {8070361, 1, 1, 3000, 15, 3, 0, 2},
|
||||||
|
[301042] = {8050766, 1, 1, 3000, 15, 3, 0, 2},
|
||||||
|
[301043] = {8080562, 1, 1, 3000, 15, 3, 0, 2},
|
||||||
|
[301044] = {4030408, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301045] = {4020113, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301046] = {4040306, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301047] = {4080409, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301048] = {4070311, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301049] = {5030210, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301050] = {5020307, 1, 1, 4500, 17, 3, 0, 2},
|
||||||
|
[301051] = {4100712, 1, 1, 4000, 17, 3, 0, 2},
|
||||||
|
[301052] = {8011523, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301053] = {8030745, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301054] = {8070362, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301055] = {8050811, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301056] = {8050767, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301057] = {8080015, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301058] = {8080563, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301059] = {8090709, 1, 1, 5000, 21, 3, 0, 2},
|
||||||
|
[301060] = {9050023, 1, 1, 1000, 21, 3, 0, 2},
|
||||||
|
[301061] = {9050024, 1, 1, 1000, 21, 3, 0, 2},
|
||||||
|
[301062] = {9010025, 1, 1, 1000, 21, 3, 0, 2},
|
||||||
|
[301063] = {4100808, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301064] = {8013620, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301065] = {8032824, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301066] = {8051518, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301067] = {8071524, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301068] = {9030062, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301069] = {9050069, 1, 1, 5500, 23, 3, 0, 2},
|
||||||
|
[301070] = {8013621, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301071] = {8013622, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301072] = {8032825, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301073] = {8071525, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301074] = {8081916, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301075] = {9040067, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301076] = {9010063, 1, 1, 6000, 25, 3, 0, 2},
|
||||||
|
[301077] = {4100809, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301078] = {4020410, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301079] = {4040510, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301080] = {4080510, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301081] = {4070410, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301082] = {5030410, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301083] = {5020410, 1, 1, 6500, 27, 3, 0, 2},
|
||||||
|
[301084] = {4030606, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301085] = {4020406, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301086] = {4040506, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301087] = {4080506, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301088] = {4070406, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301089] = {5030406, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301090] = {5020406, 1, 1, 25000, 31, 3, 0, 2},
|
||||||
|
[301091] = {8013206, 1, 1, 6000, 31, 3, 0, 2},
|
||||||
|
[301092] = {8032606, 1, 1, 6000, 31, 3, 0, 2},
|
||||||
|
[301093] = {8071306, 1, 1, 6000, 31, 3, 0, 2},
|
||||||
|
[301094] = {8081706, 1, 1, 6000, 31, 3, 0, 2},
|
||||||
|
[302001] = {3020602, 1, 20, 5, 0, 3, 8, 3},
|
||||||
|
[302002] = {9040018, 1, 1, 1000, 11, 3, 11, 3},
|
||||||
|
[303001] = {2001006, 1, 1, 3000, 11, 3, 0, 4},
|
||||||
|
[303002] = {2001016, 1, 1, 3000, 15, 3, 0, 4},
|
||||||
|
[303003] = {2001023, 1, 1, 2000, 21, 3, 0, 4},
|
||||||
|
[303004] = {2001024, 1, 1, 3000, 21, 3, 0, 4},
|
||||||
|
[303005] = {2001025, 1, 1, 4000, 21, 3, 0, 4},
|
||||||
|
[303006] = {2001026, 1, 1, 25000, 27, 3, 0, 4},
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
skipGCcheck = 0; -- 0 No, 1 Yes
|
||||||
|
playerGC = player.gcCurrent;
|
||||||
|
playerGCSeal = 1000200 + playerGC;
|
||||||
|
playerCurrentRank = 13;
|
||||||
|
npcId = npc:GetActorClassId();
|
||||||
|
|
||||||
|
if (playerGC == gcOfficer[npcId] or skipGCcheck == 1) then
|
||||||
|
callClientFunction(player, "eventTalkPreJoin");
|
||||||
|
--player:SendMessage(0x20, "", "[Info]: Client takes awhile to load GC shops");
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
eventTalkChoice = callClientFunction(player, "eventTalkMainMenu", 8, 11);
|
||||||
|
--player:SendMessage(0x20, "", "eventTalkMainMenu: " .. tostring(eventTalkChoice));
|
||||||
|
|
||||||
|
if (eventTalkChoice == 1) then
|
||||||
|
t1, t2, t3 = callClientFunction(player, "eventShopMenuOpen");
|
||||||
|
|
||||||
|
--player:SendMessage(0x20, "", "eventShopMenuOpen: " .. tostring(t1) .. ", ".. tostring(t2) .. ", ".. tostring(t3));
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
-- TODO: ADD RANK CHECK, CITY CHECK, AND ITEM-RANGE CHECK
|
||||||
|
|
||||||
|
buyResult, buyIndex = callClientFunction(player, "eventShopMenuAsk");
|
||||||
|
|
||||||
|
if (buyIndex == -1) then
|
||||||
|
callClientFunction(player, "eventShopMenuClose");
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
-- [index] = { itemID, itemQuality, itemQuantity, itemCost gcRank, city, special, itemCategory }
|
||||||
|
if (shopInfo[buyIndex][8] == 4) then
|
||||||
|
location = INVENTORY_KEYITEMS;
|
||||||
|
else
|
||||||
|
location = INVENTORY_NORMAL;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
purchaseItem(player, location, shopInfo[buyIndex][1], shopInfo[buyIndex][3], shopInfo[buyIndex][2], shopInfo[buyIndex][4], playerGCSeal);
|
||||||
|
end
|
||||||
|
|
||||||
|
--player:SendMessage(0x20, "", "Player picked an item at gcSealShopIndex " .. tostring(buyResult) .. ", ".. tostring(buyIndex));
|
||||||
|
|
||||||
|
elseif (eventTalkChoice == -1) then
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkStepCantUse");
|
||||||
|
end
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
player:endEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
464
Data/scripts/base/chara/npc/populace/PopulaceCompanySupply.lua
Normal file
464
Data/scripts/base/chara/npc/populace/PopulaceCompanySupply.lua
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanySupply Script
|
||||||
|
|
||||||
|
This class handles the menus for player's delivering specific items in exchange for grand company seals.
|
||||||
|
The supply/provision schedule runs on a weekly rotation, which resets Monday at 12AM JST, with eight rotations total to cycle through.
|
||||||
|
Each desired item has a server-wide max that it can be turned in, and when that is fulfilled, it moves to the next item in that week's list to work on.
|
||||||
|
|
||||||
|
NPCs involved in the script use the Noc001 script for dialog and menu interactions.
|
||||||
|
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkPreJoin() - Dialog when you're not affiliated
|
||||||
|
eventTalkExclusive() - Dialog when you're part of a GC but not the one of the actor?
|
||||||
|
eventTalkJoined() - Salutes then softlocks the client due to removed dialog strings. Obsolete function.
|
||||||
|
|
||||||
|
eventQuestItemMenuOpen(itemId, itemPrice, itemPriceHq, supplyType) - supplyType: 1 = Supply, 2 = Provisioning, 3 = Totorak, 4 = Dzmael, 5 = Primal, 6 = NM drops
|
||||||
|
eventQuestItemMenuSelect(quantity, quality, unk) - Brings up the shop-style menu for viewing item detail and confirming item delivery. Args appear to do nothing on client?
|
||||||
|
eventQuestItemMenuClose() - Closes menu
|
||||||
|
|
||||||
|
eventQuestSupplyItemActor(unk1) -- Client calls this automatically for setting up Expeditionary window in some manner
|
||||||
|
eventQuestSupplyItemID(unk1, unk2) -- eventQuestSupplyItemActor() calls this to sets item ranges based on category
|
||||||
|
|
||||||
|
getEventQuestSupplyMode() - Returns current supply mode set by eventQuestItemMenuOpen()
|
||||||
|
eventTalkStepBreak() - Resets actor engage state
|
||||||
|
|
||||||
|
|
||||||
|
Noc001 Functions:
|
||||||
|
|
||||||
|
pENPCAskSupplyWelcome(npcGC) -- Welcome dialog
|
||||||
|
pENPCAskSupply(npcGC) -- Brings up the delivery selection menu
|
||||||
|
eventQuestAskExWelcome(npcGC) -- Dialog when you pick Expeditionary
|
||||||
|
eventQuestAskExArea(npcGC) -- Brings up the Expeditionary selection menu
|
||||||
|
pENPCAskNowTalk(npcGC) -- Dialog for picking Delivery Status from pENPCAskSupply()
|
||||||
|
|
||||||
|
nowSup(itemId1, current1, max1, itemId2, current2, max2, itemId3, current3, max3) -- Says current 3 items and current amount delivered vs. max it'll take
|
||||||
|
nowSupAddItem(itemId, current, max) -- Lists bonus item
|
||||||
|
pItem(itemId1, unk1, itemId2, unk2, itemId3, unk3, itemId4, unk4) -- Lists which item(s) you want to delivery. Fourth item is the bonus, set 0 for hidden.
|
||||||
|
|
||||||
|
showSupplyLimit(minutes, seconds, current, required) -- Shows time remaining to finish delivery, shows current/required amount
|
||||||
|
eventShowPrizeMessage(npcGC) -- Reward dialog for handing something in?
|
||||||
|
|
||||||
|
pELimitErr() -- Error msg for GC no longer accepting items.
|
||||||
|
pETradeErr() -- Transaction error. Inventory error?
|
||||||
|
pETradeErrLimit(minutes, seconds, current, required) -- Transaction error. Shows time remaining and current/required amount
|
||||||
|
pESuppylMaxErrKeyWait(isShowLimit, minutes, seconds, current, required) -- Error msg for delivery quota already filled. Optional timer/amount display
|
||||||
|
pESuppylSealMaxErr() -- Error msg for capped on GC seals, transaction incomplete
|
||||||
|
|
||||||
|
eventQuestCantEx(npcGC) -- Dialog explaining you need to be Private Second Class to do Expeditionary missions
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("shop")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
local gcRep = {
|
||||||
|
[1500210] = 1, -- Maelstrom Representative
|
||||||
|
[1500211] = 2, -- Adder Representative
|
||||||
|
[1500212] = 3, -- Flame Representative
|
||||||
|
}
|
||||||
|
|
||||||
|
local gcItems = { -- Debug purposes. Static item list with seal value and max turn-in.
|
||||||
|
[111] = {id = 10002015, seals = 8, cap = 1900},
|
||||||
|
[112] = {id = 8031419, seals = 68, cap = 300},
|
||||||
|
[113] = {id = 3010011, seals = 3, cap = 5000},
|
||||||
|
[114] = {id = 8011108, seals = 89, cap = 400},
|
||||||
|
|
||||||
|
[115] = {id = 10004001, seals = 5, cap = 3000},
|
||||||
|
[116] = {id = 10008109, seals = 3, cap = 5000},
|
||||||
|
[117] = {id = 12000180, seals = 5, cap = 3000},
|
||||||
|
[118] = {id = 10004026, seals = 9, cap = 3400},
|
||||||
|
|
||||||
|
[121] = {id = 10008211, seals = 5, cap = 3000},
|
||||||
|
[122] = {id = 3020407, seals = 5, cap = 2500},
|
||||||
|
[123] = {id = 8030220, seals = 92, cap = 200},
|
||||||
|
[124] = {id = 8030922, seals = 99, cap = 400},
|
||||||
|
|
||||||
|
[125] = {id = 10001014, seals = 3, cap = 5000},
|
||||||
|
[126] = {id = 10008007, seals = 5, cap = 3000},
|
||||||
|
[127] = {id = 3011217, seals = 3, cap = 5000},
|
||||||
|
[128] = {id = 3011207, seals = 3, cap = 6000},
|
||||||
|
|
||||||
|
[131] = {id = 4030204, seals = 69, cap = 300},
|
||||||
|
[132] = {id = 10004103, seals = 9, cap = 1700},
|
||||||
|
[133] = {id = 10009208, seals = 6, cap = 3000},
|
||||||
|
[134] = {id = 1, seals = 1, cap = 1}, -- Unknown
|
||||||
|
|
||||||
|
[135] = {id = 10004008, seals = 9, cap = 1700},
|
||||||
|
[136] = {id = 10008007, seals = 5, cap = 3000},
|
||||||
|
[137] = {id = 3011201, seals = 5, cap = 3000},
|
||||||
|
[138] = {id = 10009401, seals = 6, cap = 6000},
|
||||||
|
|
||||||
|
[211] = {id = 10002012, seals = 5, cap = 3000},
|
||||||
|
[212] = {id = 4100007, seals = 51, cap = 300},
|
||||||
|
[213] = {id = 3010108, seals = 2, cap = 3000},
|
||||||
|
[214] = {id = 8080825, seals = 42, cap = 800},
|
||||||
|
|
||||||
|
[215] = {id = 10004003, seals = 5, cap = 3000},
|
||||||
|
[216] = {id = 10002012, seals = 3, cap = 5000},
|
||||||
|
[217] = {id = 3011104, seals = 2, cap = 3000},
|
||||||
|
[218] = {id = 3011107, seals = 3, cap = 6000},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local gcWeek = { -- Debug purposes. Static weekly item lists. [week] = { [city] = {[category] = { info } } }
|
||||||
|
[1] = {
|
||||||
|
[1] = { -- Limsa
|
||||||
|
[1] = { -- Supply
|
||||||
|
gcItems[111],
|
||||||
|
gcItems[112],
|
||||||
|
gcItems[113],
|
||||||
|
gcItems[114],
|
||||||
|
},
|
||||||
|
[2] = { -- Provision
|
||||||
|
gcItems[115],
|
||||||
|
gcItems[116],
|
||||||
|
gcItems[117],
|
||||||
|
gcItems[118],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[2] = { -- Gridania
|
||||||
|
[1] = { -- Supply
|
||||||
|
gcItems[121],
|
||||||
|
gcItems[122],
|
||||||
|
gcItems[123],
|
||||||
|
gcItems[124],
|
||||||
|
},
|
||||||
|
[2] = { -- Provision
|
||||||
|
gcItems[125],
|
||||||
|
gcItems[126],
|
||||||
|
gcItems[127],
|
||||||
|
gcItems[128],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[3] = { -- Ul'dah
|
||||||
|
[1] = { -- Supply
|
||||||
|
gcItems[131],
|
||||||
|
gcItems[132],
|
||||||
|
gcItems[133],
|
||||||
|
gcItems[134],
|
||||||
|
},
|
||||||
|
[2] = { -- Provision
|
||||||
|
gcItems[135],
|
||||||
|
gcItems[136],
|
||||||
|
gcItems[137],
|
||||||
|
gcItems[138],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
[2] = {
|
||||||
|
[1] = { -- Limsa
|
||||||
|
[1] = { -- Supply
|
||||||
|
gcItems[211],
|
||||||
|
gcItems[212],
|
||||||
|
gcItems[213],
|
||||||
|
gcItems[214],
|
||||||
|
},
|
||||||
|
[2] = { -- Provision
|
||||||
|
gcItems[215],
|
||||||
|
gcItems[216],
|
||||||
|
gcItems[217],
|
||||||
|
gcItems[218],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
local gcDelivery = { -- Debug purposes. Holds values for current turned in amount and 4th item bonus status.
|
||||||
|
week = 1,
|
||||||
|
currentCount = {
|
||||||
|
{
|
||||||
|
{49, 81, 5000, 5}, {2402, 4779, 589, 2} -- Limsa Supply/Provision
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{1, 2, 3, 4}, {5, 6, 7, 8} -- Gridania Supply/Provision
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{10, 32, 9, 18}, {23, 49, 9, 300} -- Ul'dah Supply/Provision
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bonus = { {1, 1}, {0,1}, {0,1} }; -- City -> {Supply, Provision}
|
||||||
|
timeRemainingMinutes = 99,
|
||||||
|
timeRemainingSeconds = 59,
|
||||||
|
}
|
||||||
|
|
||||||
|
local supplyQuest = GetStaticActor("Noc001");
|
||||||
|
local skipGCcheck = false; -- Debug
|
||||||
|
local skipRankCheck = false; -- Debug
|
||||||
|
local gcCheckProceed = false; -- Debug
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local playerGC = player.gcCurrent;
|
||||||
|
local limsaRank = player.gcRankLimsa;
|
||||||
|
local gridaniaRank = player.gcRankGridania;
|
||||||
|
local uldahRank = player.gcRankUldah;
|
||||||
|
local playerGCSeal = 1000200 + playerGC;
|
||||||
|
|
||||||
|
local npcId = npc:GetActorClassId();
|
||||||
|
local npcGC = gcRep[npcId];
|
||||||
|
|
||||||
|
if (skipGCcheck == true) then
|
||||||
|
gcCheckProceed = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if ((playerGC ~= npcGC) and skipGCcheck == false) then
|
||||||
|
if (playerGC == 0) then
|
||||||
|
callClientFunction(player, "eventTalkPreJoin");
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkExclusive");
|
||||||
|
end
|
||||||
|
else
|
||||||
|
gcCheckProceed = true;
|
||||||
|
end
|
||||||
|
|
||||||
|
if gcCheckProceed then
|
||||||
|
callClientFunction(player, "delegateEvent", player, supplyQuest, "pENPCAskSupplyWelcome", gcRep[npcId]);
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
local choice = callClientFunction(player, "delegateEvent", player, supplyQuest, "pENPCAskSupply", gcRep[npcId]);
|
||||||
|
|
||||||
|
if (choice == 2) then -- Supply
|
||||||
|
deliveryMenuInfo(player, npcGC, 1);
|
||||||
|
|
||||||
|
elseif (choice == 3) then -- Provision
|
||||||
|
deliveryMenuInfo(player, npcGC, 2);
|
||||||
|
|
||||||
|
elseif (choice == 4) then -- Expeditionary
|
||||||
|
local proceed = false;
|
||||||
|
|
||||||
|
if (skipRankCheck == true) then
|
||||||
|
proceed = true;
|
||||||
|
else
|
||||||
|
if (playerGC == 1 and limsaRank >= 13 and limsaRank <= 111)
|
||||||
|
or (playerGC == 2 and gridaniaRank >= 13 and gridaniaRank <= 111)
|
||||||
|
or (playerGC == 3 and uldahRank >= 13 and uldahRank <= 111) then
|
||||||
|
proceed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if proceed == true then
|
||||||
|
callClientFunction(player, "delegateEvent", player, supplyQuest, "eventQuestAskExWelcome", gcRep[npcId]);
|
||||||
|
while (true) do
|
||||||
|
local exChoice = callClientFunction(player, "delegateEvent", player, supplyQuest, "eventQuestAskExArea", gcRep[npcId]);
|
||||||
|
|
||||||
|
if (exChoice >= 3) then
|
||||||
|
deliveryMenuOpen(player, npc, 0,0,0, exChoice);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
callClientFunction(player, "delegateEvent", player, supplyQuest, "eventQuestCantEx",gcRep[npcId]);
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (choice == 5) then -- Requested item
|
||||||
|
deliveryStatus(player, npcGC);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
|
||||||
|
wait(1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
player:endEvent()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function deliveryMenuInfo(player, city, category)
|
||||||
|
|
||||||
|
local gcContents = getWeeklyItems(city, category);
|
||||||
|
local gcCurrent = getCurrentCount(city, category);
|
||||||
|
local supplyChoice = 0;
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
if gcDelivery.bonus[city][category] == 1 then -- Show fourth item if condition is met, otherwise show three.
|
||||||
|
|
||||||
|
supplyChoice = callClientFunction
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
"delegateEvent",
|
||||||
|
player,
|
||||||
|
supplyQuest,
|
||||||
|
"pItem",
|
||||||
|
gcContents[1].id,
|
||||||
|
1,
|
||||||
|
gcContents[2].id,
|
||||||
|
1,
|
||||||
|
gcContents[3].id,
|
||||||
|
1,
|
||||||
|
gcContents[4].id,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
else
|
||||||
|
supplyChoice = callClientFunction
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
"delegateEvent",
|
||||||
|
player,
|
||||||
|
supplyQuest,
|
||||||
|
"pItem",
|
||||||
|
gcContents[1].id,
|
||||||
|
1,
|
||||||
|
gcContents[2].id,
|
||||||
|
1,
|
||||||
|
gcContents[3].id,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
end
|
||||||
|
|
||||||
|
if supplyChoice >= 2 then
|
||||||
|
|
||||||
|
if gcCurrent[supplyChoice-1] < gcContents[supplyChoice-1].cap then
|
||||||
|
local hqPrice = math.ceil(gcContents[supplyChoice-1].seals * 1.5);
|
||||||
|
|
||||||
|
deliveryMenuOpen
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
npc,
|
||||||
|
gcContents[supplyChoice-1].id,
|
||||||
|
gcContents[supplyChoice-1].seals,
|
||||||
|
hqPrice,
|
||||||
|
category
|
||||||
|
);
|
||||||
|
|
||||||
|
else
|
||||||
|
callClientFunction(player, "delegateEvent", player, supplyQuest, "pESuppylMaxErrKeyWait");
|
||||||
|
end
|
||||||
|
elseif supplyChoice == 1 then
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
wait(1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function deliveryMenuOpen(player, npc, itemId, price, hqPrice, supplyType)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventQuestItemMenuOpen", itemId, price, hqPrice, supplyType);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
local choice, quantity, quality, itemSlot, Type7Param = callClientFunction(player, "eventQuestItemMenuSelect");
|
||||||
|
|
||||||
|
if choice == false then
|
||||||
|
callClientFunction(player, "eventQuestItemMenuClose");
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
player:SendMessage(0x20, "", "Choice: " .. tostring(choice));
|
||||||
|
player:SendMessage(0x20, "", "Quantity: " .. tostring(quantity));
|
||||||
|
player:SendMessage(0x20, "", "Quality: " .. tostring(quality));
|
||||||
|
player:SendMessage(0x20, "", "Slot: " .. tostring(itemSlot)); -- Broke at some point, always return 0, investigate sometime
|
||||||
|
player:SendMessage(0x20, "", "Type7Param: " .. tostring(Type7Param.slot));
|
||||||
|
--]]
|
||||||
|
|
||||||
|
pickedItem = GetItemGamedata(player:GetItemPackage(INVENTORY_NORMAL):GetItemAtSlot(Type7Param.slot).itemId).name;
|
||||||
|
player:SendMessage(0x20, "", "Player tried to deliver " .. quantity .. " " .. pickedItem);
|
||||||
|
|
||||||
|
-- TODO: Add error handling for capped seals, no-long-available-to-deliver, etc
|
||||||
|
wait(1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function deliveryStatus(player, city)
|
||||||
|
local gcContents = getWeeklyItems(city, 1);
|
||||||
|
local gcCurrent = getCurrentCount(city, 1);
|
||||||
|
|
||||||
|
callClientFunction(player, "delegateEvent", player, supplyQuest, "pENPCAskNowTalk", gcRep[npcId]);
|
||||||
|
callClientFunction
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
"delegateEvent",
|
||||||
|
player,
|
||||||
|
supplyQuest,
|
||||||
|
"nowSup",
|
||||||
|
gcContents[1].id,
|
||||||
|
gcCurrent[1],
|
||||||
|
gcContents[1].cap,
|
||||||
|
gcContents[2].id,
|
||||||
|
gcCurrent[2],
|
||||||
|
gcContents[2].cap,
|
||||||
|
gcContents[3].id,
|
||||||
|
gcCurrent[3],
|
||||||
|
gcContents[3].cap
|
||||||
|
);
|
||||||
|
if gcDelivery.bonus[city][1] == 1 then
|
||||||
|
callClientFunction
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
"delegateEvent",
|
||||||
|
player,
|
||||||
|
supplyQuest,
|
||||||
|
"nowSupAddItem",
|
||||||
|
gcContents[4].id,
|
||||||
|
gcCurrent[4],
|
||||||
|
gcContents[4].cap
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
gcContents = getWeeklyItems(city, 2);
|
||||||
|
gcCurrent = getCurrentCount(city, 2);
|
||||||
|
|
||||||
|
callClientFunction
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
"delegateEvent",
|
||||||
|
player,
|
||||||
|
supplyQuest,
|
||||||
|
"nowSup",
|
||||||
|
gcContents[1].id,
|
||||||
|
gcCurrent[1],
|
||||||
|
gcContents[1].cap,
|
||||||
|
gcContents[2].id,
|
||||||
|
gcCurrent[2],
|
||||||
|
gcContents[2].cap,
|
||||||
|
gcContents[3].id,
|
||||||
|
gcCurrent[3],
|
||||||
|
gcContents[3].cap
|
||||||
|
);
|
||||||
|
if gcDelivery.bonus[city][2] == 1 then
|
||||||
|
callClientFunction
|
||||||
|
(
|
||||||
|
player,
|
||||||
|
"delegateEvent",
|
||||||
|
player,
|
||||||
|
supplyQuest,
|
||||||
|
"nowSupAddItem",
|
||||||
|
gcContents[4].id,
|
||||||
|
gcCurrent[4],
|
||||||
|
gcContents[4].cap
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
callClientFunction(player, "delegateEvent", player, supplyQuest, "showSupplyLimit", gcDelivery.timeRemainingMinutes, gcDelivery.timeRemainingSeconds, 2, 8);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function getWeeklyItems(city, category)
|
||||||
|
return gcWeek[gcDelivery.week][city][category]
|
||||||
|
end
|
||||||
|
|
||||||
|
function getCurrentCount(city, category)
|
||||||
|
return gcDelivery.currentCount[city][category];
|
||||||
|
end
|
||||||
|
|
120
Data/scripts/base/chara/npc/populace/PopulaceCompanyWarp.lua
Normal file
120
Data/scripts/base/chara/npc/populace/PopulaceCompanyWarp.lua
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceCompanyWarp Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkWelcome(player) - Start Text
|
||||||
|
eventAskMainMenu(player, index) - Shows teleport menu, hides the teleport location at index value to prevent warping to the spot you're at
|
||||||
|
eventAfterWarpOtherZone(player) - Fades out for warp
|
||||||
|
eventTalkStepBreak() - Ends talk
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
warpNpc =
|
||||||
|
{ --[actorId] = {warpIndex, cityId} -- ()s around name indicate missing NPC + Aethernet
|
||||||
|
[1500321] = {1, 1}, -- (Storm Private Gardner)
|
||||||
|
[1500331] = {2, 1}, -- (Storm Private Rich)
|
||||||
|
[1500323] = {3, 1}, -- (Storm Private Potter)
|
||||||
|
[1500330] = {4, 1}, -- (Storm Private Hunt)
|
||||||
|
[1500322] = {5, 1}, -- (Storm Private Abel)
|
||||||
|
[1500332] = {6, 1}, -- (Storm Private Stone)
|
||||||
|
[1500339] = {7, 1}, -- (Storm Private Holt)
|
||||||
|
[1500324] = {1, 2}, -- serpent_private_white
|
||||||
|
[1500334] = {2, 2}, -- serpent_private_hill
|
||||||
|
[1500326] = {3, 2}, -- serpent_private_carver
|
||||||
|
[1500333] = {4, 2}, -- serpent_private_stone
|
||||||
|
[1500325] = {5, 2}, -- serpent_private_holmes
|
||||||
|
[1500335] = {6, 2}, -- serpent_private_kirk
|
||||||
|
[1500327] = {1, 3}, -- flame_private_newton
|
||||||
|
[1500337] = {2, 3}, -- (Flame Private Tanner)
|
||||||
|
[1500329] = {3, 3}, -- (Flame Private Morning)
|
||||||
|
[1500336] = {4, 3}, -- (Flame Private Covey)
|
||||||
|
[1500328] = {5, 3}, -- flame_private_allen
|
||||||
|
[1500338] = {6, 3}, -- (Flame Private Yar)
|
||||||
|
}
|
||||||
|
|
||||||
|
aethernet =
|
||||||
|
{
|
||||||
|
{ -- 1: Limsa
|
||||||
|
{zone = 230, x = -424.140, y = 42.000, z = 371.988, r = -2.472}, -- 1 - Aetheryte Plaza
|
||||||
|
{zone = 133, x = -439.744, y = 40.000, z = 234.376, r = 0.287}, -- 2 - Drowning Wench
|
||||||
|
{zone = 230, x = -498.131, y = 43.622, z = 60.818, r = 0.254}, -- 3 - The Bismarck
|
||||||
|
{zone = 230, x = -759.331, y = 12.000, z = 239.413, r = -0.869}, -- 4 - Ferry Docks
|
||||||
|
{zone = 230, x = -623.582, y = 4.000, z = 369.318, r = 1.736}, -- 5 - Fisherman's Bottom
|
||||||
|
{zone = 230, x = -525.536, y = 18.000, z = 173.735, r = 3.082}, -- 6 - The Octant
|
||||||
|
{zone = 133, x = -231.711, y = 12.000, z = 193.573, r = -0.786}, -- 7 - Procession of Terns
|
||||||
|
{zone = 128, x = -20.783, y = 42.214, z = 146.946, r = 2.046}, -- 8 - Zephyr Gate
|
||||||
|
},
|
||||||
|
{ -- 2: Gridania
|
||||||
|
{zone = 206, x = -107.878, y = 17.524, z = -1343.871, r = 0.657}, -- 1 - Aetheryte Plaza
|
||||||
|
{zone = 155, x = 96.868, y = 3.480, z = -1211.040, r = 2.582}, -- 2 - Carline Canopy
|
||||||
|
{zone = 206, x = 86.942, y = 19.789, z = -1420.891, r = 2.965}, -- 3 - Atelier Fen-Yil
|
||||||
|
{zone = 206, x = -84.621, y = 19.061, z = -1502.665, r = 0.756}, -- 4 - Whistling Miller
|
||||||
|
{zone = 206, x = 205.101, y = 9.526, z = -1245.405, r = -1.749}, -- 5 - Quiver's Hold
|
||||||
|
{zone = 206, x = 160.578, y = 25.061, z = -1556.662, r = 1.896}, -- 6 - Wailing Barracks
|
||||||
|
{zone = 150, x = 318.838, y = 4.036, z = -992.071, r = -0.307}, -- 7 - Mistalle Bridges
|
||||||
|
{zone = 206, x = -192.167, y = 4.466, z = -1061.777, r = -0.026}, -- 8 - Berlends Bridges
|
||||||
|
},
|
||||||
|
{ -- 3: Ul'dah
|
||||||
|
{zone = 175, x = -190.574, y = 190.000, z = 18.086, r = 2.190}, -- 1 - Aetheryte Plaza
|
||||||
|
{zone = 175, x = -36.513, y = 192.000, z = 37.130, r = -0.490}, -- 2 - Quicksand
|
||||||
|
{zone = 209, x = -192.971, y = 230.000, z = 209.348, r = 2.860}, -- 3 - Frondale's Phrontistery
|
||||||
|
{zone = 209, x = -60.243, y = 200.000, z = 257.718, r = -1.276}, -- 4 - Onyx Lane
|
||||||
|
{zone = 209, x = -147.633, y = 198.000, z = 160.064, r = -1.600}, -- 5 - Gold Court
|
||||||
|
{zone = 209, x = -263.776, y = 202.000, z = 206.699, r = -3.135}, -- 6 - Arrzaneth Ossuary
|
||||||
|
{zone = 170, x = -29.721, y = 182.635, z = -76.313, r = 2.625}, -- 7 - Gate of Nald
|
||||||
|
{zone = 170, x = 129.957, y = 183.862, z = 220.719, r = 1.515}, -- 8 - Gate of Thal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local passLimsa = 2001014;
|
||||||
|
local passGrid = 2001015;
|
||||||
|
local passUldah = 2001016;
|
||||||
|
passCheck = 1; -- 0 = Check player for Aetherpass keyitem. 1 = Ignore it.
|
||||||
|
|
||||||
|
npcId = npc:GetActorClassId();
|
||||||
|
city = warpNpc[npcId][2];
|
||||||
|
|
||||||
|
|
||||||
|
if city == 1 then
|
||||||
|
if player:GetItemPackage(INVENTORY_KEYITEMS):HasItem(passLimsa) then
|
||||||
|
passCheck = 1;
|
||||||
|
else
|
||||||
|
if passCheck == 0 then callClientFunction(player, "eventTalkWelcome", player); end
|
||||||
|
end;
|
||||||
|
elseif city == 2 then
|
||||||
|
if player:GetItemPackage(INVENTORY_KEYITEMS):HasItem(passGrid) then
|
||||||
|
passCheck = 1;
|
||||||
|
else
|
||||||
|
if passCheck == 0 then callClientFunction(player, "eventTalkWelcome", player); end
|
||||||
|
end;
|
||||||
|
elseif city == 3 then
|
||||||
|
if player:GetItemPackage(INVENTORY_KEYITEMS):HasItem(passUldah) then
|
||||||
|
passCheck = 1;
|
||||||
|
else
|
||||||
|
if passCheck == 0 then callClientFunction(player, "eventTalkWelcome", player); end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if passCheck == 1 then
|
||||||
|
choice = callClientFunction(player, "eventAskMainMenu", player, warpNpc[npcId][1]);
|
||||||
|
|
||||||
|
if choice == 0 then
|
||||||
|
--callClientFunction(player, "playereventTalkStepBreak");
|
||||||
|
player:EndEvent();
|
||||||
|
else
|
||||||
|
-- callClientFunction(player, "eventAfterWarpOtherZone", player); -- Commented out for now to prevent double fade-to-black for warp
|
||||||
|
player:EndEvent();
|
||||||
|
GetWorldManager():DoZoneChange(player, aethernet[city][choice].zone, nil, 0, 15, aethernet[city][choice].x, aethernet[city][choice].y, aethernet[city][choice].z, aethernet[city][choice].r);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,3 @@
|
|||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
24
Data/scripts/base/chara/npc/populace/PopulaceFlyingShip.lua
Normal file
24
Data/scripts/base/chara/npc/populace/PopulaceFlyingShip.lua
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceFlyingShip Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventIn(player, hasTicket, nil?, travelPrice) - If hasTicket == nil, say no money text.
|
||||||
|
eventOut(isAborting) - Set isAborting to 30010 if player didn't "use" the airship. Shows no refund warning.
|
||||||
|
eventNG(player) - Message said when player is talking to the wrong npc.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventIn", player, false, nil, 5);
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,95 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceGuildlevePublisher Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkType(level (changes factionLeves), sayIntro, brokenBladePoints, shieldsPoints, hornhandPoints, showTutorialLeves, doOmen (!=0), menuId (to Jump), leveAllowances, ?, ?, ?)
|
||||||
|
eventTalkPack(startGuildlevePack, endGuildlevePack)
|
||||||
|
eventTalkCard(card1,card2,card3,card4,card5,card6,card7,card8)
|
||||||
|
eventTalkDetail(guildLeveId, factionEvaluating, rewardType1, rewardQuantity1, rewardType2, rewardQuantity2, boostPoint, previouslyCompleted, completionBonus)
|
||||||
|
eventTalkAfterOffer()
|
||||||
|
eventHistoryleveExist(guildLeveId)
|
||||||
|
eventHistoryleveCannot()
|
||||||
|
eventGLChangeDetail(?, guildLeveId, boostPoint, rewardType1, rewardQuantity1, rewardType2, rewardQuantity2, factionEvaluating, previouslyCompleted)
|
||||||
|
eventTalkChangeOne(skipQuestion)
|
||||||
|
talkOfferMaxOver()
|
||||||
|
askRetryRegionalleve(guildLeveId, leveAllowances);
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc)
|
||||||
|
|
||||||
|
::MENU_LOOP::
|
||||||
|
menuChoice = callClientFunction(player, "eventTalkType", 0x30, true, 0x02CE, 0x356, 0x367, true, 0, nil, 0x29, 0,0,0);
|
||||||
|
--Battlecraft
|
||||||
|
if (menuChoice == 1) then
|
||||||
|
resultGLPack = callClientFunction(player, "eventTalkPack", 201, 207);
|
||||||
|
|
||||||
|
if (resultGLPack == nil) then
|
||||||
|
goto MENU_LOOP;
|
||||||
|
else
|
||||||
|
|
||||||
|
::CARDS_LOOP::
|
||||||
|
cards = {0x30C3, 0x30C4, 0x30C1, 0x30C5, 0x30C6, 0x30C7, 0x30C8, 0x30C9};
|
||||||
|
|
||||||
|
chosenGLCard = callClientFunction(player, "eventTalkCard", cards[1], cards[2], cards[3], cards[4], cards[5], cards[6], cards[7], cards[8]);
|
||||||
|
|
||||||
|
if (chosenGLCard == -1) then
|
||||||
|
goto MENU_LOOP;
|
||||||
|
else
|
||||||
|
wasAccepted = callClientFunction(player, "eventTalkDetail", cards[chosenGLCard], 0, 0xF4242, 0xD, 0xF4242, 0, 0, true, 0);
|
||||||
|
|
||||||
|
if (wasAccepted == true) then
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
goto CARDS_LOOP;
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--FieldCraft Miner
|
||||||
|
elseif (menuChoice == 0x15) then
|
||||||
|
--FieldCraft Botanist
|
||||||
|
elseif (menuChoice == 0x16) then
|
||||||
|
--FieldCraft Fisher
|
||||||
|
elseif (menuChoice == 0x17) then
|
||||||
|
--FieldCraft Quit
|
||||||
|
elseif (menuChoice == 0x18) then
|
||||||
|
--Faction Broken Blade
|
||||||
|
elseif (menuChoice == 0x29) then
|
||||||
|
--Faction Shields
|
||||||
|
elseif (menuChoice == 0x2A) then
|
||||||
|
--Faction Horn and Hand
|
||||||
|
elseif (menuChoice == 0x2B) then
|
||||||
|
--Leve Evaluation
|
||||||
|
elseif (menuChoice == 5) then
|
||||||
|
--Tutorial
|
||||||
|
elseif (menuChoice == 6) then
|
||||||
|
--End of Info
|
||||||
|
elseif (menuChoice == 7) then
|
||||||
|
--Quit
|
||||||
|
elseif (menuChoice == 8) then
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventUpdate(player, npc, step, menuOptionSelected)
|
||||||
|
--player:RunEventFunction("eventTalkType", 0x32, true, 0x02CE, 0x356, 0x367, false, 2, nil, 0x29, 0,0,0);
|
||||||
|
player:RunEventFunction("eventTalkPack", 201, 207);
|
||||||
|
--player:RunEventFunction("eventTalkCard", 0x30C3, 0x30C4, 0x30C1, 0x30C5, 0x30C6, 0x30C7, 0x30C8, 0x30C9);
|
||||||
|
--
|
||||||
|
--player:RunEventFunction("eventGLChangeDetail", 0xDEAD, 0x30C4, 0xFF, 0xF4242, 0xD, 0xF4242, 0, 2, true);
|
||||||
|
|
||||||
|
end
|
@ -0,0 +1,51 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceItemRepairer Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
talkWelcome(player, sayWelcomeText, currentLevel?, changes 1500243 from "welcome" to "well met") - Opens the main menu
|
||||||
|
selectItem(nil, pageNumber, ?, condition1, condition2, condition3, condition4, condition5) - Select item slot.
|
||||||
|
confirmRepairItem(player, price, itemId, hq grade) - Shows the confirm box for item repair.
|
||||||
|
confirmUseFacility(player, price) - Shows confirm box for using facility. Default price is 11k?
|
||||||
|
finishTalkTurn() - Call at end to stop npc from staring at the player (eeeek)
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
result = callClientFunction(player, "talkWelcome", player, true, 20, false);
|
||||||
|
|
||||||
|
if (result == 1) then
|
||||||
|
local currentPage = 1;
|
||||||
|
local slotToRepair = nil;
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
slot, page, listIndx = callClientFunction(player, "selectItem", nil, currentPage, 4, 2, 55, 55, 55, 55);
|
||||||
|
|
||||||
|
if (slot == nil and page ~= nil) then
|
||||||
|
currentPage = page;
|
||||||
|
else
|
||||||
|
slotToRepair = slot;
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (slotToRepair ~= nil) then
|
||||||
|
callClientFunction(player, "confirmRepairItem", player, 100, 8032827, 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (result == 2) then
|
||||||
|
callClientFunction(player, "confirmUseFacility", player);
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "finishTalkTurn");
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,72 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceLinkshellManager Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkStep1(noLinkshellActive) - Says intro. If noLinkshellActive = true, say newbie stuff.
|
||||||
|
eventTalkStep2(noLinkshellActive) - Shows menu, if noLinkshellActive = true, only give ability to make linkshell.
|
||||||
|
eventTalkStepMakeupDone() - Confirm when creating LS
|
||||||
|
eventTalkStepModifyDone() - Confirm when modding LS
|
||||||
|
eventTalkStepBreakDone() - Confirm when deleting LS
|
||||||
|
|
||||||
|
Text IDs:
|
||||||
|
|
||||||
|
25121 - That [@SWITCH($E8(1),linkshell,company)] name is already being used.
|
||||||
|
25122 - That [@SWITCH($E8(1),linkshell,company)] name cannot be used.
|
||||||
|
25123 - The [@SWITCH($E8(1),linkshell,company)] “[@STRING($EA(2))]” has been [@SWITCH($E8(1),created,founded)].
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function createLinkshell(player, name, crest)
|
||||||
|
GetWorldManager():RequestWorldLinkshellCreate(player, name, crest);
|
||||||
|
return waitForSignal("ls_result");
|
||||||
|
end
|
||||||
|
|
||||||
|
function modifyLinkshell(player, name, crest)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function disbandLinkshell(player, name, crest)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
local hasNoActiveLS = false;
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkStep1", hasNoActiveLS);
|
||||||
|
local command, lsName, crestId = callClientFunction(player, "eventTalkStep2", hasNoActiveLS);
|
||||||
|
|
||||||
|
--Create
|
||||||
|
if (command == 3) then
|
||||||
|
local result = createLinkshell(player, lsName, crestId);
|
||||||
|
if (result == 0) then
|
||||||
|
callClientFunction(player, "eventTalkStepMakeupDone");
|
||||||
|
elseif (result == 1) then
|
||||||
|
player:SendGameMessage(player, GetWorldMaster(), 25121, 0x20); --LS already exists
|
||||||
|
callClientFunction(player, "eventTalkStepBreakDone");
|
||||||
|
elseif (result == 2) then
|
||||||
|
player:SendGameMessage(player, GetWorldMaster(), 25122, 0x20); --Cannot use this name (reserved/banned)
|
||||||
|
callClientFunction(player, "eventTalkStepBreakDone");
|
||||||
|
elseif (result == 3) then
|
||||||
|
end
|
||||||
|
--Modify
|
||||||
|
elseif (command == 4) then
|
||||||
|
modifyLinkshell(player, lsName, crestId);
|
||||||
|
callClientFunction(player, "eventTalkStepModifyDone");
|
||||||
|
--Disband
|
||||||
|
elseif (command == 5) then
|
||||||
|
disbandLinkshell(player, lsName, crestId);
|
||||||
|
callClientFunction(player, "eventTalkStepBreakDone");
|
||||||
|
end
|
||||||
|
|
||||||
|
player:endEvent();
|
||||||
|
|
||||||
|
end
|
24
Data/scripts/base/chara/npc/populace/PopulaceNMReward.lua
Normal file
24
Data/scripts/base/chara/npc/populace/PopulaceNMReward.lua
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceNMReward Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkStep0(player, ?, ?) - Opens the main menu
|
||||||
|
eventTalkStep0_1(player) - "Ain't running a charity here", message said when you have insufficent funds
|
||||||
|
eventTalkStep0_2(player, hasItems) - Relic Quest dialog.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
callClientFunction(player, "eventTalkStep0", player, 0);
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
@ -0,0 +1,38 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulacePassiveGLPublisher Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
askOfferPack() - Show Classes
|
||||||
|
askOfferRank() - Show Ranks
|
||||||
|
askOfferQuest(player)
|
||||||
|
confirmOffer(nil, questId)
|
||||||
|
confirmMaxOffer()
|
||||||
|
talkOfferWelcome(actor, leveAllowances)
|
||||||
|
talkOfferDecide()
|
||||||
|
talkOfferMaxOver()
|
||||||
|
selectDiscardGuildleve(player)
|
||||||
|
confirmJournal()
|
||||||
|
askDiscardGuildleve()
|
||||||
|
confirmDiscardGuildleve(nil, questId)
|
||||||
|
askRetryRegionalleve(questId, leveAllowances)
|
||||||
|
finishTalkTurn()
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc)
|
||||||
|
callClientFunction(player, "talkOfferWelcome", player, 1);
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventUpdate(player, npc, step, menuOptionSelected, lsName, lsCrest)
|
||||||
|
--callClientFunction(player, "askOfferQuest", player, 1000);
|
||||||
|
|
||||||
|
end
|
@ -0,0 +1,28 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceItemRepairer Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
INIT: speechType, townType
|
||||||
|
|
||||||
|
talkWelcome(player, bool, number, bool) - Opens the main menu
|
||||||
|
selectItem(nil, pageNumber, ?, condition1, condition2, condition3, condition4, condition5) - "Ain't running a charity here", message said when you have insufficent funds
|
||||||
|
confirmRepairItem(player, price, itemId, hq grade) - Shows the confirm box for item repair.
|
||||||
|
confirmUseFacility(player, price) - Shows confirm box for using facility. Default price is 11k?
|
||||||
|
finishTalkTurn() - Call at end to stop npc from staring at the player (eeeek)
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
result = callClientFunction(player, "eventTalkStep14");
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
145
Data/scripts/base/chara/npc/populace/PopulaceRetainerManager.lua
Normal file
145
Data/scripts/base/chara/npc/populace/PopulaceRetainerManager.lua
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceRetainerManager Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkStep1(true) - Intro tutorial if no retainer
|
||||||
|
newEventTalkStep1(sayIntro) - Seems to be a post-Tanaka version of the intro????
|
||||||
|
eventTalkStep2() - Choose retainer yourself (go to race select) or let npc do it
|
||||||
|
eventTaklSelectCutSeane(cutsceneName, actorClassId1, actorClassId2, actorClassId3, actorClassId4, actorClassId5) - Starts the advance cutscene to choose a retainer. 5 retainer actorClassId's are given.
|
||||||
|
eventTalkStep4(actorClassId) - Opens up the retainer naming dialog
|
||||||
|
eventTalkStepFinalAnswer(actorClassId) - Confirm Dialog
|
||||||
|
eventTalkStepError(errorCode) - Error dialog, 1: No Extra Retainers, 2: Server Busy.
|
||||||
|
eventTalkStepFinish()
|
||||||
|
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
local npcActorClass = npc:GetActorClassId()
|
||||||
|
local retainerIndex = 3001100;
|
||||||
|
local cutscene = "rtn0l010" -- Defaulting to Limsa for now for testing
|
||||||
|
|
||||||
|
if npcActorClass == 1000166 then
|
||||||
|
cutscene = "rtn0l010";
|
||||||
|
retainerIndex = 3001101;
|
||||||
|
elseif npcActorClass == 1000865 then
|
||||||
|
cutscene = "rtn0u010";
|
||||||
|
retainerIndex = 3002101;
|
||||||
|
elseif npcActorClass == 1001184 then
|
||||||
|
cutscene = "rtn0g010";
|
||||||
|
retainerIndex = 3003101;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
introChoice = callClientFunction(player, "newEventTalkStep1", false);
|
||||||
|
|
||||||
|
if (introChoice == 1) then
|
||||||
|
|
||||||
|
-- Choose Retainer or Random
|
||||||
|
raceChoice = callClientFunction(player, "eventTalkStep2");
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
|
||||||
|
if (retainerChoice == 0) then
|
||||||
|
raceChoice = callClientFunction(player, "eventTalkStep22");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if (raceChoice == 0) then
|
||||||
|
--Choose random actorId from a valid set for the city
|
||||||
|
|
||||||
|
math.randomseed(os.time());
|
||||||
|
local randomRetainer = math.random(retainerIndex, (retainerIndex+74));
|
||||||
|
|
||||||
|
retainerName = callClientFunction(player, "eventTalkStep4", randomRetainer);
|
||||||
|
|
||||||
|
if (retainerName ~= "") then
|
||||||
|
confirmChoice = callClientFunction(player, "eventTalkStepFinalAnswer", randomRetainer);
|
||||||
|
|
||||||
|
if (confirmChoice == 1) then
|
||||||
|
callClientFunction(player, "eventTalkStepFinish");
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
elseif (confirmChoice == 3) then
|
||||||
|
raceChoice = 0;
|
||||||
|
else
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
raceChoice = -1;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
elseif (raceChoice > 0) and (raceChoice < 16) then
|
||||||
|
--Choose 5 random but correct actor ids for the city and race/tribe
|
||||||
|
|
||||||
|
local retainerRace = ((retainerIndex) + (5*(raceChoice-1)));
|
||||||
|
local retainerRaceChoices = {retainerRace, retainerRace+1, retainerRace+2, retainerRace+3, retainerRace+4};
|
||||||
|
|
||||||
|
-- Randomize the appearance order of the available five
|
||||||
|
shuffle(retainerRaceChoices);
|
||||||
|
|
||||||
|
retainerChoice = callClientFunction(player, "eventTaklSelectCutSeane", cutscene, retainerRaceChoices[1], retainerRaceChoices[2], retainerRaceChoices[3], retainerRaceChoices[4], retainerRaceChoices[5]);
|
||||||
|
|
||||||
|
if (retainerChoice == -1) then
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
elseif (retainerChoice > 0) then
|
||||||
|
--Retainer chosen, choose name
|
||||||
|
retainerName = callClientFunction(player, "eventTalkStep4", retainerRaceChoices[retainerChoice]);
|
||||||
|
|
||||||
|
if (retainerName ~= "") then
|
||||||
|
confirmChoice = callClientFunction(player, "eventTalkStepFinalAnswer", retainerRaceChoices[retainerChoice]);
|
||||||
|
|
||||||
|
if (confirmChoice == 1) then
|
||||||
|
callClientFunction(player, "eventTalkStepFinish");
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
elseif (confirmChoice == 3) then
|
||||||
|
retainerChoice = 0;
|
||||||
|
else
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkStepBreak");
|
||||||
|
raceChoice = -1;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function shuffle(tbl)
|
||||||
|
for i = #tbl, 2, -1 do
|
||||||
|
local j = math.random(i)
|
||||||
|
tbl[i], tbl[j] = tbl[j], tbl[i]
|
||||||
|
end
|
||||||
|
return tbl
|
||||||
|
end
|
@ -0,0 +1,84 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceSpecialEventCryer Script
|
||||||
|
|
||||||
|
Actor Class script to handle the 6 NPCs (technically 3, the actors were duped) involved in the Foundation Day 2011 & 2012 events.
|
||||||
|
In 2011 they appear to be used for recruitment information for their respective Grand Company.
|
||||||
|
In 2012, they were used for exchanging Over-aspected Crystals/Clusters for GC seals as part of the ongoing Atomos event.
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
For 2011.
|
||||||
|
eventTalkStep0(joined) - NPC dialog about joining their cause to fight back Imperials. joined = 0 or 1. Function has hardcoded actor IDs, won't work with 2012 versions
|
||||||
|
eventTalkNotGCmenber(npcGC) - NPC dialog when you're not part of their grand company.
|
||||||
|
|
||||||
|
For 2012.
|
||||||
|
eventTalkCrystalExchange(player, npcGC, hasCrystal) - NPC dialog explaining they want over-aspected crystals. Brings up crystal exchange prompt if hasCrystal = 1.
|
||||||
|
eventTalkCsOverflow(player, npcGC) - Error message that you can't hold the seals being offered.
|
||||||
|
eventTalkCrystalExchange2(player, npcGC) - NPC dialog for accepting exchange of crystals for seals
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local gcRep = {
|
||||||
|
[1001619] = 1, -- Maelstrom Representative 2011
|
||||||
|
[1002105] = 1, -- Maelstrom Representative 2012
|
||||||
|
[1001623] = 2, -- Adder Representative 2011
|
||||||
|
[1002109] = 2, -- Adder Representative 2012
|
||||||
|
[1001627] = 3, -- Flame Representative 2011
|
||||||
|
[1002113] = 3, -- Flame Representative 2012
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
local playerGC = player.gcCurrent;
|
||||||
|
local npcId = npc:GetActorClassId();
|
||||||
|
local npcGC = gcRep[npcId];
|
||||||
|
local npcGCSeal = 1000200 + npcGC;
|
||||||
|
local hasCrystal = 1;
|
||||||
|
local crystal = 3020537;
|
||||||
|
local cluster = 3020413;
|
||||||
|
local eventMode = 2012;
|
||||||
|
|
||||||
|
|
||||||
|
if eventMode == 2011 then
|
||||||
|
if playerGC == 0 then
|
||||||
|
callClientFunction(player, "eventTalkStep0", 0);
|
||||||
|
elseif playerGC == npcGC then
|
||||||
|
callClientFunction(player, "eventTalkStep0", 1);
|
||||||
|
else
|
||||||
|
callClientFunction(player, "eventTalkNotGCmenber", npcGC);
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif eventMode == 2012 then
|
||||||
|
choice = callClientFunction(player, "eventTalkCrystalExchange", player, npcGC, hasCrystal);
|
||||||
|
|
||||||
|
if choice == 1 then
|
||||||
|
--callClientFunction(player, "eventTalkCsOverflow", player, npcGC);
|
||||||
|
player:SendMessage(0x20, "", "You pretend to hand over four over-aspected crystals.");
|
||||||
|
callClientFunction(player, "eventTalkCrystalExchange2", player, npcGC);
|
||||||
|
|
||||||
|
local invCheck = player:GetItemPackage(INVENTORY_CURRENCY):AddItem(npcGCSeal, 1000, 1);
|
||||||
|
if invCheck == INV_ERROR_SUCCESS then
|
||||||
|
player:SendGameMessage(player, GetWorldMaster(), 25071, MESSAGE_TYPE_SYSTEM, crystal, 1, npcGCSeal, 1, 4, 1000);
|
||||||
|
end
|
||||||
|
elseif choice == 2 then
|
||||||
|
player:SendMessage(0x20, "", "You pretend to hand over an over-aspected cluster.");
|
||||||
|
--callClientFunction(player, "eventTalkCsOverflow", player, npcGC);
|
||||||
|
callClientFunction(player, "eventTalkCrystalExchange2", player, npcGC);
|
||||||
|
|
||||||
|
local invCheck = player:GetItemPackage(INVENTORY_CURRENCY):AddItem(npcGCSeal, 3000, 1);
|
||||||
|
if invCheck == INV_ERROR_SUCCESS then
|
||||||
|
player:SendGameMessage(player, GetWorldMaster(), 25071, MESSAGE_TYPE_SYSTEM, cluster, 1, npcGCSeal, 1, 1, 3000);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
13
Data/scripts/base/chara/npc/populace/PopulaceStandard.lua
Normal file
13
Data/scripts/base/chara/npc/populace/PopulaceStandard.lua
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc)
|
||||||
|
player:SendMessage(0x20, "", "This PopulaceStandard actor has no event set. Actor Class Id: " .. tostring(npc:GetActorClassId()));
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventUpdate(player, npc, blah, menuSelect)
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
107
Data/scripts/base/chara/npc/populace/shop/PopulaceGuildShop.lua
Normal file
107
Data/scripts/base/chara/npc/populace/shop/PopulaceGuildShop.lua
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceGuildShop Script
|
||||||
|
|
||||||
|
In 1.20, the devs removed Guild Marks as acquirable. In 1.21, this class was set up to allow exchanging them for
|
||||||
|
a variety of materia/crystals/gil, as well as refunding traits purchased with marks. Traits used to be purchased
|
||||||
|
to slot in, where-as with late-XIV they are just automatically unlocked once the appropriate level is met.
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
cashbackTalkCommand(arg1 through arg10) -- Dialog for refunding purchased skills prior to Job update. Args are xtx_command values for command names.
|
||||||
|
cashbackTalk(nil, refundAmount, arg3 through arg10) -- Dialog for refunding treaties to guild marks. Arg3 through 10 use xtx_itemName values.
|
||||||
|
selectMode(nil, npcId, isShowExchange, guildCurrency, unk) -- Menus for exchanging leftover marks, undoing class points, and learning about guild. Unk seems related to point resetting
|
||||||
|
|
||||||
|
maskShopListIndex(shopPack?, isSomething) -- Presumably hides an item in the shop list. Needs to be called after openShopBuy or errors client.
|
||||||
|
guildExplain(npcId, player) -- Guild Mark tutorial dialog. selectMode calls this on its own
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("shop")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
guildShopInfo = { -- [actor id] = { saySheetId, guildmarkCurrency }
|
||||||
|
[1000157] = {9, 1000103}, -- Marauder, S'raemha
|
||||||
|
[1000158] = {24, 1000120}, -- Culinarian, Noline
|
||||||
|
[1000162] = {18, 1000114}, -- Blacksmith, Qhas Chalahko
|
||||||
|
[1000164] = {16, 1000123}, -- Fishermen, Faucillien
|
||||||
|
[1000459] = {21, 1000117}, -- Leatherworker, Gallia
|
||||||
|
[1000460] = {13, 1000111}, -- Conjurer, Hetzkin
|
||||||
|
[1000461] = {15, 1000122}, -- Botanist, Kipopo
|
||||||
|
[1000462] = {11, 1000107}, -- Lancer, Clarembald
|
||||||
|
[1000464] = {10, 1000106}, -- Archer, Cassandra
|
||||||
|
[1000466] = {17, 1000113}, -- Carpenter, Frances
|
||||||
|
[1000631] = {8, 1000102}, -- Gladiator, Coynach
|
||||||
|
[1000632] = {7, 1000101}, -- Pugilist, Moruith
|
||||||
|
[1000633] = {12, 1000110}, -- Thaumaturge, Nyunoeya
|
||||||
|
[1000634] = {23, 1000119}, -- Alchemist, Kylene
|
||||||
|
[1000635] = {20, 1000116}, -- Goldsmith, Hnaufrid
|
||||||
|
[1000636] = {22, 1000118}, -- Weaver, Lafla Morfla
|
||||||
|
[1000637] = {14, 1000121}, -- Miner, Shilgen
|
||||||
|
[1001461] = {19, 1000115}, -- Armorer, Notrelchamps
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function onEventStarted(player, npc)
|
||||||
|
|
||||||
|
local npcId = npc:GetActorClassId();
|
||||||
|
local saySheetId = guildShopInfo[npcId][1];
|
||||||
|
local shopCurrency = guildShopInfo[npcId][2];
|
||||||
|
local gilCurrency = 1000001;
|
||||||
|
local keepersHymn = 3020410;
|
||||||
|
local shopPack = 0;
|
||||||
|
|
||||||
|
callClientFunction(player, "welcomeTalk", nil, saySheetId, player);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
local choice = callClientFunction(player, "selectMode", nil, npcId, true, shopCurrency, 100);
|
||||||
|
|
||||||
|
if (choice == 3) then -- Undo Point Allotment
|
||||||
|
-- TODO: Add point reset handling
|
||||||
|
elseif (choice == 4) then -- Leave menu selected
|
||||||
|
player:EndEvent();
|
||||||
|
break;
|
||||||
|
elseif (choice == nil) then -- Escape key hit to leave menu
|
||||||
|
player:EndEvent();
|
||||||
|
break
|
||||||
|
elseif (choice >= 102 and choice <= 120) then -- Exchange marks for Materia
|
||||||
|
shopPack = choice + 18; -- Index offset
|
||||||
|
if (choice == 119) then
|
||||||
|
shopPack = shopPack + 1;
|
||||||
|
elseif (choice == 120) then -- Exchange marks for Crystals
|
||||||
|
shopPack = 144;
|
||||||
|
end;
|
||||||
|
processGuildShop(player, shopPack, shopCurrency);
|
||||||
|
elseif (choice == 121) then -- Exchange marks for Gil. 1 mark = 4 gil
|
||||||
|
local markAmount = player:GetItemPackage(INVENTORY_CURRENCY):GetItemQuantity(shopCurrency);
|
||||||
|
purchaseItem(player, INVENTORY_CURRENCY, gilCurrency, markAmount*4, 1, markAmount, shopCurrency);
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function processGuildShop(player, choice, currency)
|
||||||
|
|
||||||
|
callClientFunction(player, "openShopBuy", player, choice, currency);
|
||||||
|
--callClientFunction(player, "maskShopListIndex", 137, true);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
buyResult, quantity = callClientFunction(player, "selectShopBuy", player);
|
||||||
|
|
||||||
|
if (buyResult == 0) then
|
||||||
|
callClientFunction(player, "closeShopBuy", player);
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
player:SendMessage(0x20, "", string.format("Player purchased %s item(s) at index %s in shopPack %s.", quantity, buyResult, choice));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,655 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
PopulaceShopSalesman Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
welcomeTalk(sheetId, player) - Start Message
|
||||||
|
selectMode(askMode) - Shows buy/sell modes. If askmode > 0 show guild tutorial. If askmode == -7/-8/-9 show nothing. Else show affinity/condition tutorials.
|
||||||
|
selectModeOfClassVendor() - Opens categories for class weapons and gear
|
||||||
|
selectModeOfMultiWeaponVendor(consumptionmenuId) - Opens categories for weapons/tools (war/magic/land/hand). Arg consumptionmenuId appends location of item repair person. -1: Ul'dah, -2: Gridania, -3: Limsa
|
||||||
|
selectModeOfMultiArmorVendor(consumptionmenuId) - Opens categories for armor in different slots. Arg consumptionmenuId appends location of item repair person. -1: Ul'dah, -2: Gridania, -3: Limsa
|
||||||
|
|
||||||
|
openShopBuy(player, shopPack, CurrencyItemId) - ShopPack: Items to appear in window. CurrencyItemId: What is being used to buy these items.
|
||||||
|
selectShopBuy(player) - Call after openShopBuy() to open widget
|
||||||
|
closeShopBuy(player) - Closes the buy window
|
||||||
|
|
||||||
|
openShopSell(player) - Call this to open sell window
|
||||||
|
selectShopSell(player) - Call after openShopSell()
|
||||||
|
closeShopSell(player) - Closes the sell window
|
||||||
|
|
||||||
|
confirmSellingItem(itemId, quality, quantity, gil) - Simple Sell confirmation window
|
||||||
|
|
||||||
|
selectFacility(?, sheetId, 3) - Opens the facility chooser.
|
||||||
|
confirmUseFacility(player, cost) - Facility cost confirm
|
||||||
|
|
||||||
|
informSellPrice(1, chosenItem, price) - Shows sell confirm window. ChosenItem must be correct.
|
||||||
|
|
||||||
|
startTutorial(nil, menuId) - Opens up a tutorial menu for each guild type based on menuId
|
||||||
|
|
||||||
|
finishTalkTurn() - Done at the end.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("shop")
|
||||||
|
|
||||||
|
shopInfo = {
|
||||||
|
--[[
|
||||||
|
[actorclass id] =
|
||||||
|
{
|
||||||
|
welcomeText - Dialog for the NPC to speak when interacting
|
||||||
|
menuId, - Displays certain menu/dialog. 29-36 = DoH Facilities menus. -1 Ul'dah, -2 Gridania, -3 Limsa. -7/-8/-9/nil show nothing
|
||||||
|
shopMode, - Type of shop. 0 = Single shop pack, 1 = Class vendor, 2 = Weapon vendor, 3 = Armor vendor, 4 = Hamlet vendor
|
||||||
|
shopPack{s}, - The item table index to send the client containing the list of items to display, shopmode 2/3 have a static list
|
||||||
|
}
|
||||||
|
--]]
|
||||||
|
[1000159] = {34, 36, 0, 1016},
|
||||||
|
[1000163] = {49, 31, 0, 1017},
|
||||||
|
[1000165] = {74, -8, 0, 1019},
|
||||||
|
[1001458] = {44, 30, 0, 1018},
|
||||||
|
[1500142] = {266, -1, 0, 5001},
|
||||||
|
[1500143] = {267, -1, 0, 5002},
|
||||||
|
[1500144] = {268, -1, 0, 5003},
|
||||||
|
[1500145] = {269, -1, 0, 5004},
|
||||||
|
[1500146] = {269, -1, 0, 5005},
|
||||||
|
[1500147] = {270, -1, 0, 5006},
|
||||||
|
[1500150] = {266, -8, 0, 5001},
|
||||||
|
[1500151] = {267, -8, 0, 5002},
|
||||||
|
[1500152] = {268, -8, 0, 5003},
|
||||||
|
[1500153] = {269, -8, 0, 5004},
|
||||||
|
[1500154] = {269, -8, 0, 5005},
|
||||||
|
[1500155] = {270, -8, 0, 5006},
|
||||||
|
[1500158] = {266, -8, 0, 5001},
|
||||||
|
[1500159] = {267, -8, 0, 5002},
|
||||||
|
[1500160] = {268, -8, 0, 5003},
|
||||||
|
[1500161] = {269, -8, 0, 5004},
|
||||||
|
[1500162] = {269, -8, 0, 5005},
|
||||||
|
[1500163] = {270, -8, 0, 5006},
|
||||||
|
[1500401] = {317, -8, 0, 1013},
|
||||||
|
[1500405] = {320, -8, 0, 1013},
|
||||||
|
[1500407] = {321, -8, 0, 1012},
|
||||||
|
[1500411] = {322, -8, 0, 2017},
|
||||||
|
[1500414] = {324, -8, 0, 1012},
|
||||||
|
[1500419] = {327, -8, 0, 1012},
|
||||||
|
[1500422] = {332, -8, 0, 1013},
|
||||||
|
[1500423] = {331, -8, 0, 2017},
|
||||||
|
[1500429] = {328, -8, 0, 2017},
|
||||||
|
[1500430] = {281, -8, 4, 5122},
|
||||||
|
[1500431] = {281, -8, 4, 5118},
|
||||||
|
[1500432] = {281, -8, 4, 5120},
|
||||||
|
[1600001] = {6, -8, 0, 1006},
|
||||||
|
[1600002] = {7, -8, 0, 1007},
|
||||||
|
[1600003] = {8, -8, 0, 1008},
|
||||||
|
[1600004] = {9, -8, 0, 1009},
|
||||||
|
[1600005] = {10, -8, 0, 1010},
|
||||||
|
[1600006] = {11, -8, 0, 1011},
|
||||||
|
[1600007] = {12, -8, 0, 1012},
|
||||||
|
[1600008] = {13, -8, 0, 1013},
|
||||||
|
[1600009] = {14, -8, 0, 1014},
|
||||||
|
[1600010] = {15, -8, 0, 1015},
|
||||||
|
[1600011] = {1, -8, 0, 1001},
|
||||||
|
[1600012] = {2, -8, 0, 1002},
|
||||||
|
[1600013] = {3, -8, 0, 1003},
|
||||||
|
[1600014] = {4, -8, 0, 1004},
|
||||||
|
[1600016] = {5, -8, 0, 1005},
|
||||||
|
[1600017] = {39, 29, 0, 2020},
|
||||||
|
[1600018] = {59, 33, 0, 2021},
|
||||||
|
[1600019] = {75, -8, 0, 2022},
|
||||||
|
[1600020] = {77, -8, 0, 2010},
|
||||||
|
[1600021] = {78, -8, 0, 2011},
|
||||||
|
[1600022] = {79, -8, 0, 2012},
|
||||||
|
[1600023] = {80, -8, 0, 2013},
|
||||||
|
[1600024] = {81, -8, 0, 2014},
|
||||||
|
[1600025] = {82, -8, 0, 2015},
|
||||||
|
[1600026] = {83, -8, 0, 2016},
|
||||||
|
[1600027] = {84, -8, 0, 2017},
|
||||||
|
[1600028] = {85, -8, 0, 2018},
|
||||||
|
[1600029] = {86, -8, 0, 2019},
|
||||||
|
[1600030] = {87, -8, 0, 2001},
|
||||||
|
[1600031] = {88, -8, 0, 2003},
|
||||||
|
[1600032] = {89, -8, 0, 2002},
|
||||||
|
[1600033] = {90, -8, 0, 2004},
|
||||||
|
[1600034] = {91, -8, 0, 2005},
|
||||||
|
[1600035] = {92, -8, 0, 2006},
|
||||||
|
[1600036] = {93, -8, 0, 2007},
|
||||||
|
[1600037] = {94, -8, 0, 2008},
|
||||||
|
[1600039] = {69, 35, 0, 3020},
|
||||||
|
[1600040] = {54, 32, 0, 3019},
|
||||||
|
[1600041] = {64, 34, 0, 3021},
|
||||||
|
[1600042] = {76, -8, 0, 3022},
|
||||||
|
[1600043] = {96, -8, 0, 3009},
|
||||||
|
[1600044] = {97, -8, 0, 3010},
|
||||||
|
[1600045] = {98, -8, 0, 3011},
|
||||||
|
[1600046] = {99, -8, 0, 3012},
|
||||||
|
[1600047] = {100, -8, 0, 3013},
|
||||||
|
[1600048] = {101, -8, 0, 3014},
|
||||||
|
[1600049] = {102, -8, 0, 3016},
|
||||||
|
[1600050] = {103, -8, 0, 3015},
|
||||||
|
[1600051] = {104, -8, 0, 3017},
|
||||||
|
[1600052] = {105, -8, 0, 3004},
|
||||||
|
[1600053] = {106, -8, 0, 3007},
|
||||||
|
[1600054] = {107, -8, 0, 3018},
|
||||||
|
[1600055] = {108, -8, 0, 3006},
|
||||||
|
[1600056] = {109, -8, 0, 3005},
|
||||||
|
[1600057] = {110, -8, 0, 3002},
|
||||||
|
[1600058] = {111, -8, 0, 3003},
|
||||||
|
[1600059] = {112, -8, 0, 3001},
|
||||||
|
[1600061] = {95, -8, 0, 2009},
|
||||||
|
[1600062] = {113, -8, 0, 3008},
|
||||||
|
[1600063] = {114, -8, 0, 4001},
|
||||||
|
[1600064] = {235, -8, 0, 2023},
|
||||||
|
[1600065] = {236, -8, 0, 1020},
|
||||||
|
[1600066] = {237, -8, 0, 3023},
|
||||||
|
[1600067] = {238, -8, 0, 5007},
|
||||||
|
[1600068] = {239, -8, 0, 5007},
|
||||||
|
[1600069] = {240, -1, 0, 5007},
|
||||||
|
[1600070] = {241, -8, 0, 5008},
|
||||||
|
[1600071] = {242, -8, 0, 5008},
|
||||||
|
[1600072] = {243, -8, 0, 5008},
|
||||||
|
[1600073] = {244, -8, 1, 5009},
|
||||||
|
[1600074] = {245, -8, 1, 5015},
|
||||||
|
[1600075] = {246, -8, 1, 5021},
|
||||||
|
[1600076] = {247, -8, 1, 5027},
|
||||||
|
[1600077] = {248, -8, 1, 5033},
|
||||||
|
[1600078] = {249, -8, 1, 5039},
|
||||||
|
[1600079] = {250, -8, 1, 5045},
|
||||||
|
[1600080] = {251, -8, 1, 5051},
|
||||||
|
[1600081] = {252, -8, 1, 5057},
|
||||||
|
[1600082] = {253, -8, 1, 5063},
|
||||||
|
[1600083] = {254, -8, 1, 5069},
|
||||||
|
[1600084] = {255, -8, 1, 5075},
|
||||||
|
[1600085] = {256, -8, 1, 5081},
|
||||||
|
[1600086] = {257, -8, 1, 5087},
|
||||||
|
[1600087] = {258, -8, 1, 5093},
|
||||||
|
[1600088] = {259, -8, 1, 5099},
|
||||||
|
[1600089] = {260, -8, 1, 5105},
|
||||||
|
[1600090] = {261, -8, 1, 5111},
|
||||||
|
[1600092] = {263, -8, 0, 2024},
|
||||||
|
[1600093] = {264, -8, 0, 1021},
|
||||||
|
[1600094] = {265, -8, 0, 3024},
|
||||||
|
[1600095] = {281, -8, 0, 1005},
|
||||||
|
[1600096] = {281, -8, 0, 2009},
|
||||||
|
[1600097] = {281, -8, 0, 4001},
|
||||||
|
[1600098] = {281, -8, 0, 4002},
|
||||||
|
[1600099] = {281, -8, 0, 2009},
|
||||||
|
[1600100] = {281, -2, 2, 0},
|
||||||
|
[1600101] = {281, -8, 0, 2009},
|
||||||
|
[1600103] = {281, -8, 0, 3008},
|
||||||
|
[1600104] = {281, -8, 0, 3008},
|
||||||
|
[1600107] = {281, -8, 3, 0},
|
||||||
|
[1600108] = {281, -8, 0, 3008},
|
||||||
|
[1600109] = {281, -3, 2, 0},
|
||||||
|
[1600110] = {281, -8, 0, 4001},
|
||||||
|
[1600111] = {281, -8, 0, 2009},
|
||||||
|
[1600112] = {281, -8, 0, 4002},
|
||||||
|
[1600113] = {281, -8, 0, 4001},
|
||||||
|
[1600117] = {281, -8, 0, 2009},
|
||||||
|
[1600119] = {281, -2, 3, 0},
|
||||||
|
[1600120] = {281, -8, 0, 3008},
|
||||||
|
[1600121] = {281, -8, 0, 2009},
|
||||||
|
[1600122] = {281, -8, 0, 3008},
|
||||||
|
[1600125] = {281, -8, 0, 1005},
|
||||||
|
[1600126] = {281, -8, 0, 3008},
|
||||||
|
[1600129] = {281, -1, 3, 0},
|
||||||
|
[1600130] = {281, -8, 0, 4001},
|
||||||
|
[1600133] = {281, -1, 2, 0},
|
||||||
|
[1600137] = {281, -8, 0, 1005},
|
||||||
|
[1600142] = {281, -8, 0, 1005},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
shopRange = { --shopRangeStart, shopRangeEnd
|
||||||
|
[101] = {101001, 101010};
|
||||||
|
[102] = {102001, 102010};
|
||||||
|
[103] = {103001, 103010};
|
||||||
|
[104] = {104001, 104010};
|
||||||
|
[105] = {105001, 105010};
|
||||||
|
[106] = {106001, 106010};
|
||||||
|
[107] = {107001, 107010};
|
||||||
|
[108] = {108001, 108017};
|
||||||
|
[109] = {109001, 109015};
|
||||||
|
[110] = {110001, 110018};
|
||||||
|
[111] = {111001, 111018};
|
||||||
|
[112] = {112001, 112018};
|
||||||
|
[113] = {113001, 113019};
|
||||||
|
[114] = {114001, 114015};
|
||||||
|
[115] = {115001, 115015};
|
||||||
|
[116] = {116001, 116010};
|
||||||
|
[117] = {117001, 117010};
|
||||||
|
[118] = {118001, 118010};
|
||||||
|
[120] = {120001, 120012};
|
||||||
|
[121] = {121001, 121012};
|
||||||
|
[122] = {122001, 122012};
|
||||||
|
[123] = {123001, 123012};
|
||||||
|
[124] = {124001, 124012};
|
||||||
|
[125] = {125001, 125012};
|
||||||
|
[126] = {126001, 126012};
|
||||||
|
[127] = {127001, 127012};
|
||||||
|
[128] = {128001, 128012};
|
||||||
|
[129] = {129001, 129016};
|
||||||
|
[130] = {130001, 130012};
|
||||||
|
[131] = {131001, 131012};
|
||||||
|
[132] = {132001, 132012};
|
||||||
|
[133] = {133001, 133012};
|
||||||
|
[134] = {134001, 134016};
|
||||||
|
[135] = {135001, 135012};
|
||||||
|
[136] = {136001, 136012};
|
||||||
|
[137] = {137001, 137012};
|
||||||
|
[138] = {138001, 138012};
|
||||||
|
[139] = {139001, 139012};
|
||||||
|
[140] = {140001, 140012};
|
||||||
|
[141] = {141001, 141012};
|
||||||
|
[142] = {142001, 142012};
|
||||||
|
[143] = {143001, 143016};
|
||||||
|
[144] = {144001, 144018};
|
||||||
|
[145] = {1071001, 1071002};
|
||||||
|
[146] = {1072001, 1072006};
|
||||||
|
[1001] = {1001001, 1001008};
|
||||||
|
[1002] = {1002001, 1002008};
|
||||||
|
[1003] = {1003001, 1003007};
|
||||||
|
[1004] = {1004001, 1004002};
|
||||||
|
[1005] = {1005001, 1005017};
|
||||||
|
[1006] = {1006001, 1006006};
|
||||||
|
[1007] = {1007001, 1007010};
|
||||||
|
[1008] = {1008001, 1008009};
|
||||||
|
[1009] = {1009001, 1009012};
|
||||||
|
[1010] = {1010001, 1010014};
|
||||||
|
[1011] = {1011001, 1011010};
|
||||||
|
[1012] = {1012001, 1012007};
|
||||||
|
[1013] = {1013001, 1013011};
|
||||||
|
[1014] = {1014001, 1014006};
|
||||||
|
[1015] = {1015001, 1015007};
|
||||||
|
[1016] = {1016001, 1016016};
|
||||||
|
[1017] = {1018001, 1018010};
|
||||||
|
[1018] = {1017001, 1017013};
|
||||||
|
[1019] = {1019001, 1019005};
|
||||||
|
[1020] = {1066001, 1066004};
|
||||||
|
[1021] = {1069001, 1069005};
|
||||||
|
[2001] = {1020001, 1020008};
|
||||||
|
[2002] = {1021001, 1021006};
|
||||||
|
[2003] = {1022001, 1022007};
|
||||||
|
[2004] = {1023001, 1023008};
|
||||||
|
[2005] = {1024001, 1024003};
|
||||||
|
[2006] = {1025001, 1025008};
|
||||||
|
[2007] = {1026001, 1026006};
|
||||||
|
[2008] = {1027001, 1027004};
|
||||||
|
[2009] = {1028001, 1028016};
|
||||||
|
[2010] = {1029001, 1029009};
|
||||||
|
[2011] = {1030001, 1030008};
|
||||||
|
[2012] = {1031001, 1031010};
|
||||||
|
[2013] = {1032001, 1032010};
|
||||||
|
[2014] = {1033001, 1033012};
|
||||||
|
[2015] = {1034001, 1034015};
|
||||||
|
[2016] = {1035001, 1035013};
|
||||||
|
[2017] = {1036001, 1036006};
|
||||||
|
[2018] = {1037001, 1037006};
|
||||||
|
[2019] = {1038001, 1038008};
|
||||||
|
[2020] = {1039001, 1039009};
|
||||||
|
[2021] = {1040001, 1040010};
|
||||||
|
[2022] = {1041001, 1041005};
|
||||||
|
[2023] = {1065001, 1065006};
|
||||||
|
[2024] = {1068001, 1068006};
|
||||||
|
[3001] = {1042001, 1042008};
|
||||||
|
[3002] = {1043001, 1043008};
|
||||||
|
[3003] = {1044001, 1044008};
|
||||||
|
[3004] = {1045001, 1045008};
|
||||||
|
[3005] = {1046001, 1046010};
|
||||||
|
[3006] = {1047001, 1047008};
|
||||||
|
[3007] = {1048001, 1048006};
|
||||||
|
[3008] = {1049001, 1049016};
|
||||||
|
[3009] = {1050001, 1050013};
|
||||||
|
[3010] = {1051001, 1051008};
|
||||||
|
[3011] = {1052001, 1052009};
|
||||||
|
[3012] = {1053001, 1053010};
|
||||||
|
[3013] = {1054001, 1054006};
|
||||||
|
[3014] = {1055001, 1055013};
|
||||||
|
[3015] = {1056001, 1056005};
|
||||||
|
[3016] = {1057001, 1057008};
|
||||||
|
[3017] = {1058001, 1058011};
|
||||||
|
[3018] = {1059001, 1059007};
|
||||||
|
[3019] = {1060001, 1060011};
|
||||||
|
[3020] = {1061001, 1061014};
|
||||||
|
[3021] = {1062001, 1062016};
|
||||||
|
[3022] = {1063001, 1063004};
|
||||||
|
[3023] = {1067001, 1067008};
|
||||||
|
[3024] = {1070001, 1070004};
|
||||||
|
[4001] = {1064001, 1064011};
|
||||||
|
[4002] = {1064001, 1064011};
|
||||||
|
[5001] = {2001001, 2001018};
|
||||||
|
[5002] = {2002001, 2002006};
|
||||||
|
[5003] = {2003001, 2003010};
|
||||||
|
[5004] = {2004001, 2004009};
|
||||||
|
[5005] = {2005001, 2005010};
|
||||||
|
[5006] = {2006001, 2006012};
|
||||||
|
[5007] = {2007001, 2007010};
|
||||||
|
[5008] = {2008001, 2008016};
|
||||||
|
[5009] = {2009001, 2009007};
|
||||||
|
[5010] = {2009101, 2009104};
|
||||||
|
[5011] = {2009201, 2009204};
|
||||||
|
[5012] = {2009301, 2009304};
|
||||||
|
[5013] = {2009401, 2009404};
|
||||||
|
[5014] = {2009501, 2009504};
|
||||||
|
[5015] = {2010001, 2010004};
|
||||||
|
[5016] = {2010101, 2010104};
|
||||||
|
[5017] = {2010201, 2010204};
|
||||||
|
[5018] = {2010301, 2010304};
|
||||||
|
[5019] = {2010401, 2010404};
|
||||||
|
[5020] = {2010501, 2010504};
|
||||||
|
[5021] = {2011001, 2011004};
|
||||||
|
[5022] = {2011101, 2011104};
|
||||||
|
[5023] = {2011201, 2011204};
|
||||||
|
[5024] = {2011301, 2011304};
|
||||||
|
[5025] = {2011401, 2011404};
|
||||||
|
[5026] = {2011501, 2011504};
|
||||||
|
[5027] = {2012001, 2012007};
|
||||||
|
[5028] = {2012101, 2012104};
|
||||||
|
[5029] = {2012201, 2012204};
|
||||||
|
[5030] = {2012301, 2012304};
|
||||||
|
[5031] = {2012401, 2012404};
|
||||||
|
[5032] = {2012501, 2012504};
|
||||||
|
[5033] = {2013001, 2013004};
|
||||||
|
[5034] = {2013101, 2013104};
|
||||||
|
[5035] = {2013201, 2013204};
|
||||||
|
[5036] = {2013301, 2013304};
|
||||||
|
[5037] = {2013401, 2013404};
|
||||||
|
[5038] = {2013501, 2013504};
|
||||||
|
[5039] = {2014001, 2014007};
|
||||||
|
[5040] = {2014101, 2014104};
|
||||||
|
[5041] = {2014201, 2014204};
|
||||||
|
[5042] = {2014301, 2014304};
|
||||||
|
[5043] = {2014401, 2014404};
|
||||||
|
[5044] = {2014501, 2014504};
|
||||||
|
[5045] = {2015001, 2015007};
|
||||||
|
[5046] = {2015101, 2015104};
|
||||||
|
[5047] = {2015201, 2015204};
|
||||||
|
[5048] = {2015301, 2015304};
|
||||||
|
[5049] = {2015401, 2015404};
|
||||||
|
[5050] = {2015501, 2015504};
|
||||||
|
[5051] = {2016001, 2016006};
|
||||||
|
[5052] = {2016101, 2016104};
|
||||||
|
[5053] = {2016201, 2016204};
|
||||||
|
[5054] = {2016301, 2016304};
|
||||||
|
[5055] = {2016401, 2016404};
|
||||||
|
[5056] = {2016501, 2016504};
|
||||||
|
[5057] = {2017001, 2017006};
|
||||||
|
[5058] = {2017101, 2017104};
|
||||||
|
[5059] = {2017201, 2017204};
|
||||||
|
[5060] = {2017301, 2017304};
|
||||||
|
[5061] = {2017401, 2017404};
|
||||||
|
[5062] = {2017501, 2017504};
|
||||||
|
[5063] = {2018001, 2018006};
|
||||||
|
[5064] = {2018101, 2018104};
|
||||||
|
[5065] = {2018201, 2018204};
|
||||||
|
[5066] = {2018301, 2018304};
|
||||||
|
[5067] = {2018401, 2018404};
|
||||||
|
[5068] = {2018501, 2018504};
|
||||||
|
[5069] = {2019001, 2019006};
|
||||||
|
[5070] = {2019101, 2019104};
|
||||||
|
[5071] = {2019201, 2019204};
|
||||||
|
[5072] = {2019301, 2019304};
|
||||||
|
[5073] = {2019401, 2019404};
|
||||||
|
[5074] = {2019501, 2019504};
|
||||||
|
[5075] = {2020001, 2020006};
|
||||||
|
[5076] = {2020101, 2020104};
|
||||||
|
[5077] = {2020201, 2020204};
|
||||||
|
[5078] = {2020301, 2020304};
|
||||||
|
[5079] = {2020401, 2020404};
|
||||||
|
[5080] = {2020501, 2020504};
|
||||||
|
[5081] = {2021001, 2021006};
|
||||||
|
[5082] = {2021101, 2021104};
|
||||||
|
[5083] = {2021201, 2021204};
|
||||||
|
[5084] = {2021301, 2021304};
|
||||||
|
[5085] = {2021401, 2021404};
|
||||||
|
[5086] = {2021501, 2021504};
|
||||||
|
[5087] = {2022001, 2022006};
|
||||||
|
[5088] = {2022101, 2022104};
|
||||||
|
[5089] = {2022201, 2022204};
|
||||||
|
[5090] = {2022301, 2022304};
|
||||||
|
[5091] = {2022401, 2022404};
|
||||||
|
[5092] = {2022501, 2022504};
|
||||||
|
[5093] = {2023001, 2023006};
|
||||||
|
[5094] = {2023101, 2023104};
|
||||||
|
[5095] = {2023201, 2023204};
|
||||||
|
[5096] = {2023301, 2023304};
|
||||||
|
[5097] = {2023401, 2023404};
|
||||||
|
[5098] = {2023501, 2023504};
|
||||||
|
[5099] = {2024001, 2024006};
|
||||||
|
[5100] = {2024101, 2024104};
|
||||||
|
[5101] = {2024201, 2024204};
|
||||||
|
[5102] = {2024301, 2024304};
|
||||||
|
[5103] = {2024401, 2024404};
|
||||||
|
[5104] = {2024501, 2024504};
|
||||||
|
[5105] = {2025001, 2025006};
|
||||||
|
[5106] = {2025101, 2025104};
|
||||||
|
[5107] = {2025201, 2025204};
|
||||||
|
[5108] = {2025301, 2025304};
|
||||||
|
[5109] = {2025401, 2025404};
|
||||||
|
[5110] = {2025501, 2025504};
|
||||||
|
[5111] = {2026001, 2026006};
|
||||||
|
[5112] = {2026101, 2026104};
|
||||||
|
[5113] = {2026201, 2026204};
|
||||||
|
[5114] = {2026301, 2026304};
|
||||||
|
[5115] = {2026401, 2026404};
|
||||||
|
[5116] = {2026501, 2026504};
|
||||||
|
[5117] = {2026601, 2026606};
|
||||||
|
[5118] = {2026701, 2026708};
|
||||||
|
[5119] = {2026801, 2026808};
|
||||||
|
[5120] = {2026901, 2026908};
|
||||||
|
[5121] = {2027001, 2027008};
|
||||||
|
[5122] = {2027101, 2027110};
|
||||||
|
[5123] = {2027201, 2027211};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, npc, triggerName)
|
||||||
|
|
||||||
|
npcId = npc:GetActorClassId();
|
||||||
|
|
||||||
|
if shopInfo[npcId] == nil then
|
||||||
|
errorMsg = string.format("This PopulaceShopSalesman actor has no shop set. Actor Class Id: %s", npcId);
|
||||||
|
player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", errorMsg );
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
end;
|
||||||
|
|
||||||
|
local shopCurrency = 1000001;
|
||||||
|
local welcomeText = 1;
|
||||||
|
local menuId = shopInfo[npcId][2];
|
||||||
|
local shopCategory = shopInfo[npcId][3];
|
||||||
|
|
||||||
|
local itemShop = 0;
|
||||||
|
local classShop = 1;
|
||||||
|
local weaponShop = 2;
|
||||||
|
local armorShop = 3;
|
||||||
|
local hamletShop = 4;
|
||||||
|
|
||||||
|
local weaponShopPack = {5001,5002,5007,5008};
|
||||||
|
local armorShopPack = {5004,5005,5006,5003};
|
||||||
|
|
||||||
|
local menuBuy = 1;
|
||||||
|
local menuBuyCount = 1; -- For Shops with multiple buying categories
|
||||||
|
local menuSell = 2;
|
||||||
|
local menuFacility = 3;
|
||||||
|
local menuTutorial = 4;
|
||||||
|
local menuClose = -3;
|
||||||
|
local menuHasFacility = false;
|
||||||
|
local menuHasTutorial = false;
|
||||||
|
|
||||||
|
local shopPack = shopInfo[npcId][4]; -- Starting value for the shopPack of the current NPC Actor
|
||||||
|
local chosenShopPackage = 0; -- Var to send to openShopMenu() once desired shopPack is determined
|
||||||
|
local choice;
|
||||||
|
|
||||||
|
callClientFunction(player, "welcomeTalk", shopInfo[npcId][welcomeText], player);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
|
||||||
|
if (shopCategory == itemShop) then
|
||||||
|
choice = callClientFunction(player, "selectMode", menuId);
|
||||||
|
menuHasFacility = true;
|
||||||
|
menuHasTutorial = true;
|
||||||
|
elseif (shopCategory == classShop) then
|
||||||
|
choice = callClientFunction(player, "selectModeOfClassVendor");
|
||||||
|
menuBuyCount = 6;
|
||||||
|
menuSell = 0;
|
||||||
|
elseif (shopCategory == weaponShop) then
|
||||||
|
choice = callClientFunction(player, "selectModeOfMultiWeaponVendor", menuId);
|
||||||
|
menuBuyCount = 4;
|
||||||
|
menuSell = 0;
|
||||||
|
elseif (shopCategory == armorShop) then
|
||||||
|
choice = callClientFunction(player, "selectModeOfMultiArmorVendor", menuId);
|
||||||
|
menuBuyCount = 4;
|
||||||
|
menuSell = 0;
|
||||||
|
elseif (shopCategory == hamletShop) then
|
||||||
|
choice = callClientFunction(player, "selectMode", menuId);
|
||||||
|
|
||||||
|
local hamletRegion = shopPack;
|
||||||
|
local hamletPackAleport = {5117, 5122, 5123};
|
||||||
|
local hamletPackHyrstmill = {5117, 5118, 5119};
|
||||||
|
local hamletPackGoldenBazaar = {5117, 5120, 5121};
|
||||||
|
local hamletLevel = 3; -- Defaulting to highest value for now
|
||||||
|
|
||||||
|
if hamletRegion == 5122 then -- Aleport
|
||||||
|
-- hamletLevel = GetHamletStatus(idAleport);
|
||||||
|
shopPack = hamletPackAleport[hamletLevel] or 5117;
|
||||||
|
elseif hamletRegion == 5118 then -- Hyrstmill
|
||||||
|
-- hamletLevel = GetHamletStatus(idHyrstmill);
|
||||||
|
shopPack = hamletPackHyrstmill[hamletLevel] or 5117;
|
||||||
|
elseif hamletRegion == 5120 then -- The Golden Bazaar
|
||||||
|
-- hamletLevel = GetHamletStatus(idGoldenBazaar);
|
||||||
|
shopPack = hamletPackGoldenBazaar[hamletLevel] or 5117;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if choice and (choice >= menuBuy and choice <= menuBuyCount) then
|
||||||
|
--player:SendMessage(0x20,"", "Menu option: "..choice);
|
||||||
|
|
||||||
|
if (shopCategory == weaponShop) then
|
||||||
|
chosenShopPackage = weaponShopPack[choice];
|
||||||
|
elseif (shopCategory == armorShop) then
|
||||||
|
chosenShopPackage = armorShopPack[choice];
|
||||||
|
else
|
||||||
|
chosenShopPackage = ((shopPack-1) + choice);
|
||||||
|
end
|
||||||
|
|
||||||
|
openShopMenu(
|
||||||
|
player,
|
||||||
|
menuId,
|
||||||
|
chosenShopPackage,
|
||||||
|
shopRange[chosenShopPackage][1],
|
||||||
|
shopRange[chosenShopPackage][2],
|
||||||
|
shopCurrency
|
||||||
|
);
|
||||||
|
|
||||||
|
elseif (choice == menuSell) then
|
||||||
|
openSellMenu(player);
|
||||||
|
|
||||||
|
elseif (choice == menuFacility) and (menuHasFacility == true) then
|
||||||
|
if menuId > 0 then
|
||||||
|
local classFacility = (shopInfo[npcId][1] + 1) or 35;
|
||||||
|
facilityChoice = callClientFunction(player, "selectFacility", nil, classFacility, 3);
|
||||||
|
|
||||||
|
if facilityChoice == 1 then
|
||||||
|
callClientFunction(player, "confirmUseFacility", player, 200);
|
||||||
|
elseif facilityChoice == 2 then
|
||||||
|
callClientFunction(player, "confirmUseFacility", player, 400);
|
||||||
|
elseif facilityChoice == 3 then
|
||||||
|
callClientFunction(player, "confirmUseFacility", player, 1000);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif (choice == menuTutorial) and (menuHasTutorial == true) then
|
||||||
|
callClientFunction(player, "startTutorial", nil, menuId);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (choice == menuClose or choice == nil) then
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "finishTalkTurn", player);
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function openShopMenu(player, menuId, shopPack, itemRangeStart, itemRangeEnd, shopCurrency)
|
||||||
|
|
||||||
|
callClientFunction(player, "openShopBuy", player, shopPack, shopCurrency);
|
||||||
|
|
||||||
|
player:SendMessage(0x20, "", "shopPack: "..shopPack.." Range: "..itemRangeStart.."-"..itemRangeEnd);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
buyResult, quantity = callClientFunction(player, "selectShopBuy", player);
|
||||||
|
|
||||||
|
if (buyResult == 0) then
|
||||||
|
callClientFunction(player, "closeShopBuy", player);
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
if itemRangeStart and itemRangeEnd then
|
||||||
|
itemChosen = (itemRangeStart - 1) + buyResult;
|
||||||
|
|
||||||
|
if (((itemRangeStart-1) + itemChosen) < itemRangeStart) or (itemChosen > itemRangeEnd) then
|
||||||
|
player:SendMessage(0x20, "", "[ERROR] Client selected item exceeds the valid range.");
|
||||||
|
callClientFunction(player, "finishTalkTurn", player);
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
player:SendMessage(0x20, "", "Item chosen: " .. itemChosen .. " Quantity: ".. quantity);
|
||||||
|
|
||||||
|
--[[
|
||||||
|
TO-DO: Request item information from server table and throw result to purchaseItem()
|
||||||
|
|
||||||
|
requestItem = GetItemShopInfoThing(itemChosen);
|
||||||
|
purchaseItem(player, INVENTORY_NORMAL, requestItem.id, quantity, requestItem.quality, requestItem.price, shopCurrency);
|
||||||
|
--]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function openSellMenu(player)
|
||||||
|
callClientFunction(player, "openShopSell", player);
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
sellResult, sellQuantity, sellState, unknown, sellItemSlot = callClientFunction(player, "selectShopSell", player);
|
||||||
|
|
||||||
|
if (sellResult == nil) then
|
||||||
|
callClientFunction(player, "closeShopSell", player);
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
if sellState == 1 then
|
||||||
|
itemToSell = player:GetItemPackage(INVENTORY_NORMAL):GetItemAtSlot(sellItemSlot-1);
|
||||||
|
gItemSellId = itemToSell.itemId;
|
||||||
|
gItemQuality = itemToSell.quality;
|
||||||
|
gItemPrice = GetItemGamedata(gItemSellId);
|
||||||
|
gItemPrice = gItemPrice.sellPrice;
|
||||||
|
|
||||||
|
|
||||||
|
if gItemQuality == 2 then -- +1
|
||||||
|
gItemPrice = (math.floor(gItemPrice * 1.10));
|
||||||
|
elseif gItemQuality == 3 then -- +2
|
||||||
|
gItemPrice = (math.floor(gItemPrice * 1.25));
|
||||||
|
elseif gItemQuality == 4 then -- +3
|
||||||
|
gItemPrice = (math.floor(gItemPrice * 1.50));
|
||||||
|
end
|
||||||
|
|
||||||
|
callClientFunction(player, "informSellPrice", 1, sellItemSlot, gItemPrice);
|
||||||
|
|
||||||
|
elseif sellState == nil then
|
||||||
|
sellItem(player, gItemSellId, sellQuantity, gItemQuality, gItemPrice, sellItemSlot-1, shopCurrency);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
46
Data/scripts/base/chara/npc/retainer/OrdinaryRetainer.lua
Normal file
46
Data/scripts/base/chara/npc/retainer/OrdinaryRetainer.lua
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
OrdinaryRetainer Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
eventTalkRetainerOther() -
|
||||||
|
eventTalkRetainerMenu(mode, hasPossessions) - Opens the main menu. If mode == 2, hide dismiss option.
|
||||||
|
eventTalkRetainerDismissal(hasPossessions) - Show dismiss confirmation.
|
||||||
|
eventTalkRetainerMannequin(0:enable/1:disable confirm) - Show bazaar modeling confirmation.
|
||||||
|
eventTalkRetainerItemTrade(operationCode) - Operate RetainerTradeWidget. Codes: 1 - Open, 2 - Select Mode, 3 - Close.
|
||||||
|
eventTalkRetainerItemList(operationCode) - Operate Bazaar Widget. Codes: 1 - Open, 2 - Select Mode, 3 - Close.
|
||||||
|
eventReturnResult(resultCode, ?) - Redraws the RetainerTrade UI.
|
||||||
|
sayToPlayer(actorClassId, messageType, argument) - Makes the retainer say a phrase to the player.
|
||||||
|
eventTalkFinish() - Stops npc from looking at player.
|
||||||
|
eventPlayerTurn(angle) - Turns player to angle.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
require ("retainer")
|
||||||
|
|
||||||
|
function init(npc)
|
||||||
|
return false, false, 0, 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
function onEventStarted(player, retainer, triggerName)
|
||||||
|
|
||||||
|
while (true) do
|
||||||
|
choice = callClientFunction(player, "eventTalkRetainerMenu", 1);
|
||||||
|
if (choice == 1) then
|
||||||
|
doItemTrade(player, retainer);
|
||||||
|
elseif (choice == 2) then
|
||||||
|
doBazaar(player, retainer);
|
||||||
|
elseif (choice == 7) then
|
||||||
|
callClientFunction(player, "eventTalkRetainerMannequin", 0);
|
||||||
|
elseif (choice == 5) then
|
||||||
|
player:DespawnMyRetainer();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
175
Data/scripts/battlenpc.lua
Normal file
175
Data/scripts/battlenpc.lua
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
local initClassItems, initRaceItems;
|
||||||
|
|
||||||
|
function onBeginLogin(player)
|
||||||
|
--New character, set the initial quest
|
||||||
|
if (player:GetPlayTime(false) == 0) then
|
||||||
|
initialTown = player:GetInitialTown();
|
||||||
|
|
||||||
|
if (initialTown == 1 and player:HasQuest(110001) == false) then
|
||||||
|
player:AddQuest(110001);
|
||||||
|
player:SetHomePoint(1280001);
|
||||||
|
elseif (initialTown == 2 and player:HasQuest(110005) == false) then
|
||||||
|
player:AddQuest(110005);
|
||||||
|
player:SetHomePoint(1280061);
|
||||||
|
elseif (initialTown == 3 and player:HasQuest(110009) == false) then
|
||||||
|
player:AddQuest(110009);
|
||||||
|
player:SetHomePoint(1280031);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--For Opening. Set Director and reset position incase d/c
|
||||||
|
if (player:HasQuest(110001) == true and player:GetZoneID() == 193) then
|
||||||
|
director = player:GetZone():CreateDirector("OpeningDirector", false);
|
||||||
|
player:AddDirector(director);
|
||||||
|
director:StartDirector(true);
|
||||||
|
player:SetLoginDirector(director);
|
||||||
|
player:KickEvent(director, "noticeEvent", true);
|
||||||
|
|
||||||
|
player.positionX = 0.016;
|
||||||
|
player.positionY = 10.35;
|
||||||
|
player.positionZ = -36.91;
|
||||||
|
player.rotation = 0.025;
|
||||||
|
player:GetQuest(110001):ClearQuestData();
|
||||||
|
player:GetQuest(110001):ClearQuestFlags();
|
||||||
|
elseif (player:HasQuest(110005) == true and player:GetZoneID() == 166) then
|
||||||
|
director = player:GetZone():CreateDirector("OpeningDirector", false);
|
||||||
|
player:AddDirector(director);
|
||||||
|
director:StartDirector(false);
|
||||||
|
player:SetLoginDirector(director);
|
||||||
|
player:KickEvent(director, "noticeEvent", true);
|
||||||
|
|
||||||
|
player.positionX = 369.5434;
|
||||||
|
player.positionY = 4.21;
|
||||||
|
player.positionZ = -706.1074;
|
||||||
|
player.rotation = -1.26721;
|
||||||
|
player:GetQuest(110005):ClearQuestData();
|
||||||
|
player:GetQuest(110005):ClearQuestFlags();
|
||||||
|
elseif (player:HasQuest(110009) == true and player:GetZoneID() == 184) then
|
||||||
|
--director = player:GetZone():CreateDirector("OpeningDirector", false);
|
||||||
|
--player:AddDirector(director);
|
||||||
|
--director:StartDirector(false);
|
||||||
|
--player:SetLoginDirector(director);
|
||||||
|
--player:KickEvent(director, "noticeEvent", true);
|
||||||
|
--
|
||||||
|
player.positionX = 5.364327;
|
||||||
|
player.positionY = 196.0;
|
||||||
|
player.positionZ = 133.6561;
|
||||||
|
player.rotation = -2.849384;
|
||||||
|
player:GetQuest(110009):ClearQuestData();
|
||||||
|
player:GetQuest(110009):ClearQuestFlags();
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function onLogin(player)
|
||||||
|
|
||||||
|
if (player:GetPlayTime(false) == 0) then
|
||||||
|
player:SendMessage(0x1D,"",">PlayTime == 0, new player!");
|
||||||
|
|
||||||
|
initClassItems(player);
|
||||||
|
initRaceItems(player);
|
||||||
|
|
||||||
|
player:SavePlayTime();
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function initClassItems(player)
|
||||||
|
|
||||||
|
local slotTable;
|
||||||
|
local invSlotTable;
|
||||||
|
|
||||||
|
--DoW
|
||||||
|
if (player.charaWork.parameterSave.state_mainSkill[0] == 2) then --PUG
|
||||||
|
player:GetItemPackage(0):AddItem({4020001, 8030701, 8050728, 8080601, 8090307});
|
||||||
|
player:GetEquipment():SetEquipment({0, 10, 12, 14, 15},{0, 1, 2, 3, 4});
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 3) then --GLA
|
||||||
|
player:GetItemPackage(0):AddItem({4030010, 8031120, 8050245, 8080601, 8090307});
|
||||||
|
player:GetEquipment():SetEquipment({0, 10, 12, 14, 15},{0, 1, 2, 3, 4});
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 4) then --MRD
|
||||||
|
player:GetItemPackage(0):AddItem({4040001, 8011001, 8050621, 8070346, 8090307});
|
||||||
|
player:GetEquipment():SetEquipment({0, 8, 12, 13, 15},{0, 1, 2, 3, 4});
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 7) then --ARC
|
||||||
|
player:GetItemPackage(0):AddItem({4070001, 8030601, 8050622, 8080601, 8090307});
|
||||||
|
player:GetEquipment():SetEquipment({0, 10, 12, 14, 15},{0, 1, 2, 3, 4});
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 8) then --LNC
|
||||||
|
player:GetItemPackage(0):AddItem({4080201, 8030801, 8051015, 8080501, 8090307});
|
||||||
|
player:GetEquipment():SetEquipment({0, 10, 12, 14, 15},{0, 1, 2, 3, 4});
|
||||||
|
--DoM
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 22) then --THM
|
||||||
|
player:GetItemPackage(0):AddItem({5020001, 8030245, 8050346, 8080346, 8090208});
|
||||||
|
player:GetEquipment():SetEquipment({0, 10, 12, 14, 15},{0, 1, 2, 3, 4});
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 23) then --CNJ
|
||||||
|
player:GetItemPackage(0):AddItem({5030101, 8030445, 8050031, 8080246, 8090208});
|
||||||
|
player:GetEquipment():SetEquipment({0, 10, 12, 14, 15},{0, 1, 2, 3, 4});
|
||||||
|
|
||||||
|
--DoH
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 29) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 30) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 31) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 32) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 33) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 34) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 35) then --
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 36) then --
|
||||||
|
|
||||||
|
--DoL
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 39) then --MIN
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 40) then --BTN
|
||||||
|
elseif (player.charaWork.parameterSave.state_mainSkill[0] == 41) then --FSH
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function initRaceItems(player)
|
||||||
|
|
||||||
|
if (player.playerWork.tribe == 1) then --Hyur Midlander Male
|
||||||
|
player:GetItemPackage(0):AddItem(8040001);
|
||||||
|
player:GetItemPackage(0):AddItem(8060001);
|
||||||
|
elseif (player.playerWork.tribe == 2) then --Hyur Midlander Female
|
||||||
|
player:GetItemPackage(0):AddItem(8040002);
|
||||||
|
player:GetItemPackage(0):AddItem(8060002);
|
||||||
|
elseif (player.playerWork.tribe == 3) then --Hyur Highlander Male
|
||||||
|
player:GetItemPackage(0):AddItem(8040003);
|
||||||
|
player:GetItemPackage(0):AddItem(8060003);
|
||||||
|
elseif (player.playerWork.tribe == 4) then --Elezen Wildwood Male
|
||||||
|
player:GetItemPackage(0):AddItem(8040004);
|
||||||
|
player:GetItemPackage(0):AddItem(8060004);
|
||||||
|
elseif (player.playerWork.tribe == 5) then --Elezen Wildwood Female
|
||||||
|
player:GetItemPackage(0):AddItem(8040006);
|
||||||
|
player:GetItemPackage(0):AddItem(8060006);
|
||||||
|
elseif (player.playerWork.tribe == 6) then --Elezen Duskwight Male
|
||||||
|
player:GetItemPackage(0):AddItem(8040005);
|
||||||
|
player:GetItemPackage(0):AddItem(8060005);
|
||||||
|
elseif (player.playerWork.tribe == 7) then --Elezen Duskwight Female
|
||||||
|
player:GetItemPackage(0):AddItem(8040007);
|
||||||
|
player:GetItemPackage(0):AddItem(8060007);
|
||||||
|
elseif (player.playerWork.tribe == 8) then --Lalafell Plainsfolk Male
|
||||||
|
player:GetItemPackage(0):AddItem(8040008);
|
||||||
|
player:GetItemPackage(0):AddItem(8060008);
|
||||||
|
elseif (player.playerWork.tribe == 9) then --Lalafell Plainsfolk Female
|
||||||
|
player:GetItemPackage(0):AddItem(8040010);
|
||||||
|
player:GetItemPackage(0):AddItem(8060010);
|
||||||
|
elseif (player.playerWork.tribe == 10) then --Lalafell Dunesfolk Male
|
||||||
|
player:GetItemPackage(0):AddItem(8040009);
|
||||||
|
player:GetItemPackage(0):AddItem(8060009);
|
||||||
|
elseif (player.playerWork.tribe == 11) then --Lalafell Dunesfolk Female
|
||||||
|
player:GetItemPackage(0):AddItem(8040011);
|
||||||
|
player:GetItemPackage(0):AddItem(8060011);
|
||||||
|
elseif (player.playerWork.tribe == 12) then --Miqo'te Seekers of the Sun
|
||||||
|
player:GetItemPackage(0):AddItem(8040012);
|
||||||
|
player:GetItemPackage(0):AddItem(8060012);
|
||||||
|
elseif (player.playerWork.tribe == 13) then --Miqo'te Seekers of the Moon
|
||||||
|
player:GetItemPackage(0):AddItem(8040013);
|
||||||
|
player:GetItemPackage(0):AddItem(8060013);
|
||||||
|
elseif (player.playerWork.tribe == 14) then --Roegadyn Sea Wolf
|
||||||
|
player:GetItemPackage(0):AddItem(8040014);
|
||||||
|
player:GetItemPackage(0):AddItem(8060014);
|
||||||
|
elseif (player.playerWork.tribe == 15) then --Roegadyn Hellsguard
|
||||||
|
player:GetItemPackage(0):AddItem(8040015);
|
||||||
|
player:GetItemPackage(0):AddItem(8060015);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:GetEquipment():SetEquipment({9, 11},{5,6});
|
||||||
|
|
||||||
|
end
|
107
Data/scripts/battleutils.lua
Normal file
107
Data/scripts/battleutils.lua
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
CommandType =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
AutoAttack = 1,
|
||||||
|
Weaponskill = 2,
|
||||||
|
Ability = 3,
|
||||||
|
Spell = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionType =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Physical = 1,
|
||||||
|
Magic = 2,
|
||||||
|
Heal = 3,
|
||||||
|
Status = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionProperty =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Physical = 1,
|
||||||
|
Magic = 2,
|
||||||
|
Heal = 4,
|
||||||
|
Status = 8,
|
||||||
|
Ranged = 16
|
||||||
|
}
|
||||||
|
|
||||||
|
DamageTakenType =
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Attack,
|
||||||
|
Magic,
|
||||||
|
Weaponskill,
|
||||||
|
Ability
|
||||||
|
}
|
||||||
|
|
||||||
|
HitDirection =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Front = 1,
|
||||||
|
Right = 2,
|
||||||
|
Rear = 4,
|
||||||
|
Left = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
HitType =
|
||||||
|
{
|
||||||
|
Miss = 0,
|
||||||
|
Evade = 1,
|
||||||
|
Parry = 2,
|
||||||
|
Block = 3,
|
||||||
|
Resist = 4,
|
||||||
|
Hit = 5,
|
||||||
|
Crit = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetFindAOEType =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Circle = 1,
|
||||||
|
Cone = 2,
|
||||||
|
Box = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusEffectFlags =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
--Loss flags - Do we need loseonattacking/caststart? Could just be done with activate flags
|
||||||
|
LoseOnDeath = bit32.lshift(1, 0), -- effects removed on death
|
||||||
|
LoseOnZoning = bit32.lshift(1, 1), -- effects removed on zoning
|
||||||
|
LoseOnEsuna = bit32.lshift(1, 2), -- effects which can be removed with esuna (debuffs)
|
||||||
|
LoseOnDispel = bit32.lshift(1, 3), -- some buffs which player might be able to dispel from mob
|
||||||
|
LoseOnLogout = bit32.lshift(1, 4), -- effects removed on logging out
|
||||||
|
LoseOnAttacking = bit32.lshift(1, 5), -- effects removed when owner attacks another entity
|
||||||
|
LoseOnCastStart = bit32.lshift(1, 6), -- effects removed when owner starts casting
|
||||||
|
LoseOnAggro = bit32.lshift(1, 7), -- effects removed when owner gains enmity (swiftsong)
|
||||||
|
LoseOnClassChange = bit32.lshift(1, 8), --Effect falls off whhen changing class
|
||||||
|
|
||||||
|
--Activate flags
|
||||||
|
ActivateOnCastStart = bit32.lshift(1, 9), --Activates when a cast starts.
|
||||||
|
ActivateOnCommandStart = bit32.lshift(1, 10), --Activates when a command is used, before iterating over targets. Used for things like power surge, excruciate.
|
||||||
|
ActivateOnCommandFinish = bit32.lshift(1, 11), --Activates when the command is finished, after all targets have been iterated over. Used for things like Excruciate and Resonance falling off.
|
||||||
|
ActivateOnPreactionTarget = bit32.lshift(1, 12), --Activates after initial rates are calculated for an action against owner
|
||||||
|
ActivateOnPreactionCaster = bit32.lshift(1, 13), --Activates after initial rates are calculated for an action by owner
|
||||||
|
ActivateOnDamageTaken = bit32.lshift(1, 14),
|
||||||
|
ActivateOnHealed = bit32.lshift(1, 15),
|
||||||
|
|
||||||
|
--Should these be rolled into DamageTaken?
|
||||||
|
ActivateOnMiss = bit32.lshift(1, 16), --Activates when owner misses
|
||||||
|
ActivateOnEvade = bit32.lshift(1, 17), --Activates when owner evades
|
||||||
|
ActivateOnParry = bit32.lshift(1, 18), --Activates when owner parries
|
||||||
|
ActivateOnBlock = bit32.lshift(1, 19), --Activates when owner evades
|
||||||
|
ActivateOnHit = bit32.lshift(1, 20), --Activates when owner hits
|
||||||
|
ActivateOnCrit = bit32.lshift(1, 21), --Activates when owner crits
|
||||||
|
|
||||||
|
--Prevent flags. Sleep/stun/petrify/etc combine these
|
||||||
|
PreventSpell = bit32.lshift(1, 22), -- effects which prevent using spells, such as silence
|
||||||
|
PreventWeaponSkill = bit32.lshift(1, 23), -- effects which prevent using weaponskills, such as pacification
|
||||||
|
PreventAbility = bit32.lshift(1, 24), -- effects which prevent using abilities, such as amnesia
|
||||||
|
PreventAttack = bit32.lshift(1, 25), -- effects which prevent basic attacks
|
||||||
|
PreventMovement = bit32.lshift(1, 26), -- effects which prevent movement such as bind, still allows turning in place
|
||||||
|
PreventTurn = bit32.lshift(1, 27), -- effects which prevent turning, such as stun
|
||||||
|
PreventUntarget = bit32.lshift(1, 28), -- effects which prevent changing targets, such as fixation
|
||||||
|
Stance = bit32.lshift(1, 29) -- effects that do not have a timer
|
||||||
|
}
|
19
Data/scripts/commands/Ability.lua
Normal file
19
Data/scripts/commands/Ability.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require ("global")
|
||||||
|
require ("utils")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
AttackWeaponSkill Script
|
||||||
|
|
||||||
|
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local attackMagicHandlers = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||||
|
player.Ability(command.actorId, targetActor);
|
||||||
|
player:endEvent();
|
||||||
|
end
|
5
Data/scripts/commands/AbilityCure.lua
Normal file
5
Data/scripts/commands/AbilityCure.lua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require("global")
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||||
|
|
||||||
|
end
|
20
Data/scripts/commands/ActivateCommand.lua
Normal file
20
Data/scripts/commands/ActivateCommand.lua
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
ActivateCommand Script
|
||||||
|
|
||||||
|
Switches between active and passive mode states
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName)
|
||||||
|
|
||||||
|
if (player.currentMainState == 0x0000) then
|
||||||
|
player.Engage(0, 0x0002);
|
||||||
|
elseif (player.currentMainState == 0x0002) then
|
||||||
|
player.Disengage(0x0000);
|
||||||
|
end
|
||||||
|
player:endEvent();
|
||||||
|
sendSignal("playerActive");
|
||||||
|
end;
|
20
Data/scripts/commands/AttackAbility.lua
Normal file
20
Data/scripts/commands/AttackAbility.lua
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
require ("global")
|
||||||
|
require ("utils")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
AttackWeaponSkill Script
|
||||||
|
|
||||||
|
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local attackMagicHandlers = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||||
|
player.Ability(command.actorId, targetActor);
|
||||||
|
player:endEvent();
|
||||||
|
|
||||||
|
end
|
19
Data/scripts/commands/AttackMagic.lua
Normal file
19
Data/scripts/commands/AttackMagic.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require ("global")
|
||||||
|
require ("utils")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
AttackWeaponSkill Script
|
||||||
|
|
||||||
|
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local attackMagicHandlers = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||||
|
player.Cast(command.actorId, targetActor);
|
||||||
|
player:endEvent();
|
||||||
|
end;
|
26
Data/scripts/commands/AttackWeaponSkill.lua
Normal file
26
Data/scripts/commands/AttackWeaponSkill.lua
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
require ("global")
|
||||||
|
require ("utils")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
AttackWeaponSkill Script
|
||||||
|
|
||||||
|
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName, arg1, arg2, arg3, arg4, targetActor, arg5, arg6, arg7, arg8)
|
||||||
|
|
||||||
|
--Are they in active mode?
|
||||||
|
if (player:GetState() != 2) then
|
||||||
|
player:SendGameMessage(GetWorldMaster(), 32503, 0x20);
|
||||||
|
player:endEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
if not player.aiContainer.IsEngaged() then
|
||||||
|
player.Engage(targetActor);
|
||||||
|
end;
|
||||||
|
player.WeaponSkill(command.actorId, targetActor);
|
||||||
|
player:endEvent();
|
||||||
|
end;
|
30
Data/scripts/commands/BazaarCheckCommand.lua
Normal file
30
Data/scripts/commands/BazaarCheckCommand.lua
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
BazaarCheckCommand Script
|
||||||
|
|
||||||
|
Handles what happens when you examine a player's bazaar
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function onEventStarted(player, actor, triggerName, name, arg1, arg2, arg3, bazaarActorId)
|
||||||
|
|
||||||
|
local bazaarActor = nil;
|
||||||
|
|
||||||
|
if (name ~= nil) then
|
||||||
|
bazaarActor = player:GetZone():FindPCInZone(name);
|
||||||
|
elseif (bazaarActorId ~= nil) then
|
||||||
|
bazaarActor = player:GetZone():FindActorInArea(bazaarActorId);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (bazaarActor ~= nil) then
|
||||||
|
player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", "Currently disabled due to freezing characters.");
|
||||||
|
--callClientFunction(player, "delegateCommand", GetStaticActor("BazaarCheckCommand"), "processChackBazaar");
|
||||||
|
else
|
||||||
|
--Show error
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
58
Data/scripts/commands/BazaarDealCommand.lua
Normal file
58
Data/scripts/commands/BazaarDealCommand.lua
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
BazaarDealCommand Script
|
||||||
|
|
||||||
|
Handles various bazaar transfer options
|
||||||
|
|
||||||
|
All bazaar args have a Reward (The item the person who fufills the request gets) and a Seek (The item the player wants, either gil or an item).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
|
||||||
|
rewardItem: Item reference to what will be given to the buyer. If it's gil the itemID will be given instead. If offering an item to seek; reward/seek are combined and put here.
|
||||||
|
seekItem: Item reference to what the buyer will give us. If it's gil the itemID will be given instead,
|
||||||
|
bazaarMode: The tag value to set in the bazaar item's data.
|
||||||
|
arg1: Always nil
|
||||||
|
bazaarActor: The actor who owns this bazaar
|
||||||
|
rewardAmount: The amount of rewardItem the buyer will get.
|
||||||
|
seekAmount: The amount of seekItem we want.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function onEventStarted(player, actor, triggerName, rewardItem, seekItem, bazaarMode, arg1, bazaarActor, rewardAmount, seekAmount, arg2, arg3, type9ItemIds)
|
||||||
|
|
||||||
|
local rewarding = nil;
|
||||||
|
local seeking = nil;
|
||||||
|
|
||||||
|
--Handle special case for offering an item.
|
||||||
|
if (seekItem == nil) then
|
||||||
|
rewarding = player:GetItemPackage(rewardItem.offerPackageId):GetItemAtSlot(rewardItem.offerSlot);
|
||||||
|
seeking = player:GetItemPackage(rewardItem.seekPackageId):GetItemAtSlot(rewardItem.seekSlot);
|
||||||
|
end
|
||||||
|
|
||||||
|
--Handle Reward
|
||||||
|
if (rewarding == nil) then
|
||||||
|
if (type(rewardItem) == "number") then
|
||||||
|
rewarding = player:GetItemPackage(INVENTORY_CURRENCY):GetItemByCatelogId(rewardItem);
|
||||||
|
else
|
||||||
|
rewarding = player:GetItem(rewardItem);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--Handle Seek
|
||||||
|
if (seeking == nil) then
|
||||||
|
if (type(seekItem) == "number") then
|
||||||
|
seeking = player:GetItemPackage(INVENTORY_CURRENCY):GetItemByCatelogId(seekItem);
|
||||||
|
else
|
||||||
|
seeking = player:GetItem(seekItem);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result = GetWorldManager():AddToBazaar(player, rewarding, seeking, rewardAmount, seekAmount, bazaarMode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
55
Data/scripts/commands/BazaarTradeCommand.lua
Normal file
55
Data/scripts/commands/BazaarTradeCommand.lua
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
BazaarTradeCommand Script
|
||||||
|
|
||||||
|
Handles bazaar trade
|
||||||
|
|
||||||
|
All bazaar args have a Reward (The item the person who fufills the request gets) and a Seek (The item the player wants, either gil or an item).
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--TODO REFACTOR
|
||||||
|
|
||||||
|
function onEventStarted(player, actor, triggerName, rewardItem, seekItemOrCost, seekAmount, arg1, bazaarActorId, rewardAmount, rewardItemId, nameIndex, arg2, type9ItemIds)
|
||||||
|
|
||||||
|
local originalReward = nil;
|
||||||
|
local originalSeek = nil;
|
||||||
|
local bazaarActor = nil;
|
||||||
|
|
||||||
|
--Get the bazaar actor
|
||||||
|
if (bazaarActorId ~= nil) then
|
||||||
|
bazaarActor = player:GetZone():FindActorInArea(bazaarActorId);
|
||||||
|
end
|
||||||
|
|
||||||
|
--Abort if no actor
|
||||||
|
if (bazaarActor == nil) then
|
||||||
|
player:SendGameMessage(player, worldMaster, 25111, 0x20);
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
--If seekItem is a number, we are buying an item (ExecuteBazaarBuy)
|
||||||
|
if (type(seekItemOrCost) == "number") then
|
||||||
|
if (player:GetCurrentGil() >= seekItemOrCost) then
|
||||||
|
if (GetWorldManager():BazaarBuyOperation(bazaarActor, player, bazaarActor:GetItem(rewardItem), rewardAmount, seekItemOrCost)) then
|
||||||
|
else
|
||||||
|
player:SendGameMessage(player, worldMaster, 25111, 0x20);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
player:SendGameMessage(player, worldMaster, 40252, 0x20);
|
||||||
|
end
|
||||||
|
else --Else we are fufilling a sought out item (ExecuteBazaarSell)
|
||||||
|
local rewardItem = bazaarActor:GetItem(rewardItem);
|
||||||
|
local seekItem = player:GetItem(seekItemOrCost);
|
||||||
|
if (rewardItem ~= nil and seekItem ~= nil) then
|
||||||
|
if (GetWorldManager():BazaarSellOperation(bazaarActor, player, rewardItem, rewardAmount, seekItem, seekAmount)) then
|
||||||
|
else
|
||||||
|
player:SendGameMessage(player, worldMaster, 25111, 0x20);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
22
Data/scripts/commands/BazaarUndealCommand.lua
Normal file
22
Data/scripts/commands/BazaarUndealCommand.lua
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
BazaarUndealCommand Script
|
||||||
|
|
||||||
|
Handles canceling bazaar items
|
||||||
|
|
||||||
|
25107 - Your bazaar is either full or already contains that unique item.
|
||||||
|
25111 - Unable to complete transaction.
|
||||||
|
25112 - You are unable to remove the item from your bazaar. You cannot hold any more items.
|
||||||
|
25113 - Offered and sought items cannot be identical.
|
||||||
|
25114 - Items in less than mint condition cannot be offered.
|
||||||
|
25115 - Items in less than mint condition cannot be placed in your bazaar.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function onEventStarted(player, actor, triggerName, rewardItem, seekItem, bazaarType, narg, bazaarActor, rewardAmount, seekAmount, narg, narg, type9ItemIds)
|
||||||
|
|
||||||
|
GetWorldManager():RemoveFromBazaar(player, player:GetItem(rewardItem));
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
23
Data/scripts/commands/BonusPointCommand.lua
Normal file
23
Data/scripts/commands/BonusPointCommand.lua
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
BonusPointCommand Script
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
operateUI(pointsAvailable, pointsLimit, str, vit, dex, int, min, pie)
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
require ("global")
|
||||||
|
|
||||||
|
function onEventStarted(player, actor, triggerName)
|
||||||
|
--local points = player:GetAttributePoints();
|
||||||
|
--player:RunEventFunction("delegateCommand", actor, "operateUI", points.available, points.limit, points.inSTR, points.inVIT, points.inDEX, points.inINT, points.inMIN, points.inPIT);
|
||||||
|
result = callClientFunction(player, "delegateCommand", actor, "operateUI", 100, 100, 10, 10, 10, 10, 10, 10);
|
||||||
|
|
||||||
|
--Do Save
|
||||||
|
if (result == true) then
|
||||||
|
end
|
||||||
|
|
||||||
|
player:endEvent();
|
||||||
|
end
|
6
Data/scripts/commands/ChangeJobCommand.lua
Normal file
6
Data/scripts/commands/ChangeJobCommand.lua
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
function onEventStarted(player, caller, commandRequest, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
|
||||||
|
|
||||||
|
player:SetCurrentJob(17);
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
end
|
19
Data/scripts/commands/CheckCommand.lua
Normal file
19
Data/scripts/commands/CheckCommand.lua
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
CheckCommand Script
|
||||||
|
|
||||||
|
Handles player examining someone
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function onEventStarted(player, commandactor, triggerName, arg1, arg2, arg3, arg4, checkedActorId)
|
||||||
|
|
||||||
|
actor = player:GetActorInInstance(checkedActorId);
|
||||||
|
|
||||||
|
if (actor ~= nil) then
|
||||||
|
player:examinePlayer(actor);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
49
Data/scripts/commands/ChocoboRideCommand.lua
Normal file
49
Data/scripts/commands/ChocoboRideCommand.lua
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
ChocoboRideCommand Script
|
||||||
|
|
||||||
|
Handles mounting and dismounting the Chocobo and Goobbue
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function onEventStarted(player, actor, triggerName, isGoobbue)
|
||||||
|
|
||||||
|
if (player:GetState() == 0) then
|
||||||
|
|
||||||
|
worldMaster = GetWorldMaster();
|
||||||
|
|
||||||
|
if (isGoobbue ~= true) then
|
||||||
|
player:ChangeMusic(83);
|
||||||
|
player:SendGameMessage(player, worldMaster, 26001, 0x20);
|
||||||
|
player:SetMountState(1);
|
||||||
|
else
|
||||||
|
player:ChangeMusic(98);
|
||||||
|
player:SendGameMessage(player, worldMaster, 26019, 0x20);
|
||||||
|
player:SetMountState(2);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:ChangeSpeed(0.0, 5.0, 10.0, 10.0);
|
||||||
|
player:ChangeState(15);
|
||||||
|
else
|
||||||
|
player:ChangeMusic(player:GetZone().bgmDay);
|
||||||
|
|
||||||
|
worldMaster = GetWorldMaster();
|
||||||
|
|
||||||
|
if (player.rentalExpireTime != 0) then
|
||||||
|
player:SendGameMessage(player, worldMaster, 26004, 0x20); --You dismount.
|
||||||
|
else
|
||||||
|
if (player:GetMountState() == 1) then
|
||||||
|
player:SendGameMessage(player, worldMaster, 26003, 0x20); --You dismount X.
|
||||||
|
else
|
||||||
|
player:SendGameMessage(player, worldMaster, 26021, 0x20); --You dismount your Gobbue.
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
player:SetMountState(0);
|
||||||
|
player:ChangeSpeed(0.0, 2.0, 5.0, 5.0)
|
||||||
|
player:ChangeState(0);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:EndEvent();
|
||||||
|
|
||||||
|
end
|
144
Data/scripts/commands/CmnAttackWeaponSkill.lua
Normal file
144
Data/scripts/commands/CmnAttackWeaponSkill.lua
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
require ("global")
|
||||||
|
|
||||||
|
--[[
|
||||||
|
|
||||||
|
CmnAttackWeaponSkill Script
|
||||||
|
|
||||||
|
Finds the correct weaponskill subscript to fire when a weaponskill actor is activated.
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local function handleTEST(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
local weaponskillHandlers = {
|
||||||
|
[0xA0F067F4] = nil,
|
||||||
|
[0xA0F067F5] = nil,
|
||||||
|
[0xA0F067F7] = nil,
|
||||||
|
[0xA0F067F8] = nil,
|
||||||
|
[0xA0F067FA] = nil,
|
||||||
|
[0xA0F067FB] = nil,
|
||||||
|
[0xA0F067FD] = nil,
|
||||||
|
[0xA0F067FE] = nil,
|
||||||
|
[0xA0F06800] = nil,
|
||||||
|
[0xA0F06801] = nil,
|
||||||
|
[0xA0F06802] = nil,
|
||||||
|
[0xA0F06804] = nil,
|
||||||
|
[0xA0F06805] = nil,
|
||||||
|
[0xA0F06806] = nil,
|
||||||
|
[0xA0F06808] = nil,
|
||||||
|
[0xA0F0680A] = nil,
|
||||||
|
[0xA0F0680B] = nil,
|
||||||
|
[0xA0F0680D] = nil,
|
||||||
|
[0xA0F0680E] = nil,
|
||||||
|
[0xA0F06810] = nil,
|
||||||
|
[0xA0F06812] = nil,
|
||||||
|
[0xA0F06814] = nil,
|
||||||
|
[0xA0F068A8] = nil,
|
||||||
|
[0xA0F068A9] = nil,
|
||||||
|
[0xA0F068AB] = nil,
|
||||||
|
[0xA0F068AC] = nil,
|
||||||
|
[0xA0F068AE] = nil,
|
||||||
|
[0xA0F068AF] = nil,
|
||||||
|
[0xA0F068B2] = nil,
|
||||||
|
[0xA0F068B3] = nil,
|
||||||
|
[0xA0F068B5] = nil,
|
||||||
|
[0xA0F068B7] = nil,
|
||||||
|
[0xA0F068B8] = nil,
|
||||||
|
[0xA0F068B9] = nil,
|
||||||
|
[0xA0F068BB] = nil,
|
||||||
|
[0xA0F068BC] = nil,
|
||||||
|
[0xA0F068BE] = nil,
|
||||||
|
[0xA0F068BF] = nil,
|
||||||
|
[0xA0F068C1] = nil,
|
||||||
|
[0xA0F068C3] = nil,
|
||||||
|
[0xA0F068C5] = nil,
|
||||||
|
[0xA0F0695C] = nil,
|
||||||
|
[0xA0F0695D] = nil,
|
||||||
|
[0xA0F0695E] = nil,
|
||||||
|
[0xA0F06960] = nil,
|
||||||
|
[0xA0F06961] = nil,
|
||||||
|
[0xA0F06963] = nil,
|
||||||
|
[0xA0F06964] = nil,
|
||||||
|
[0xA0F06966] = nil,
|
||||||
|
[0xA0F06967] = nil,
|
||||||
|
[0xA0F06968] = nil,
|
||||||
|
[0xA0F0696A] = nil,
|
||||||
|
[0xA0F0696B] = nil,
|
||||||
|
[0xA0F0696D] = nil,
|
||||||
|
[0xA0F0696E] = nil,
|
||||||
|
[0xA0F06970] = nil,
|
||||||
|
[0xA0F06971] = nil,
|
||||||
|
[0xA0F06973] = nil,
|
||||||
|
[0xA0F06974] = nil,
|
||||||
|
[0xA0F06976] = nil,
|
||||||
|
[0xA0F06978] = nil,
|
||||||
|
[0xA0F06B78] = nil,
|
||||||
|
[0xA0F06B79] = nil,
|
||||||
|
[0xA0F06B7B] = nil,
|
||||||
|
[0xA0F06B7C] = nil,
|
||||||
|
[0xA0F06B7E] = nil,
|
||||||
|
[0xA0F06B7F] = nil,
|
||||||
|
[0xA0F06B81] = nil,
|
||||||
|
[0xA0F06B82] = nil,
|
||||||
|
[0xA0F06B84] = nil,
|
||||||
|
[0xA0F06B85] = nil,
|
||||||
|
[0xA0F06B8A] = nil,
|
||||||
|
[0xA0F06B8C] = nil,
|
||||||
|
[0xA0F06B8E] = nil,
|
||||||
|
[0xA0F06B90] = nil,
|
||||||
|
[0xA0F06B91] = nil,
|
||||||
|
[0xA0F06B93] = nil,
|
||||||
|
[0xA0F06B95] = nil,
|
||||||
|
[0xA0F06B97] = nil,
|
||||||
|
[0xA0F06C2C] = nil,
|
||||||
|
[0xA0F06C2D] = nil,
|
||||||
|
[0xA0F06C2F] = nil,
|
||||||
|
[0xA0F06C31] = nil,
|
||||||
|
[0xA0F06C32] = nil,
|
||||||
|
[0xA0F06C34] = nil,
|
||||||
|
[0xA0F06C35] = nil,
|
||||||
|
[0xA0F06C36] = nil,
|
||||||
|
[0xA0F06C38] = nil,
|
||||||
|
[0xA0F06C39] = nil,
|
||||||
|
[0xA0F06C3B] = nil,
|
||||||
|
[0xA0F06C3C] = nil,
|
||||||
|
[0xA0F06C3E] = nil,
|
||||||
|
[0xA0F06C3F] = nil,
|
||||||
|
[0xA0F06C41] = nil,
|
||||||
|
[0xA0F06C43] = nil,
|
||||||
|
[0xA0F06C45] = nil,
|
||||||
|
[0xA0F06C47] = nil,
|
||||||
|
[0xA0F06C49] = nil,
|
||||||
|
[0xA0F06C4B] = nil,
|
||||||
|
[0xA0F06D94] = nil,
|
||||||
|
[0xA0F06D95] = nil,
|
||||||
|
[0xA0F06D96] = nil,
|
||||||
|
[0xA0F06F92] = nil,
|
||||||
|
[0xA0F06F93] = nil,
|
||||||
|
[0xA0F06F95] = nil,
|
||||||
|
[0xA0F06F96] = nil,
|
||||||
|
[0xA0F070E6] = nil,
|
||||||
|
[0xA0F070E7] = nil,
|
||||||
|
[0xA0F070E9] = nil,
|
||||||
|
[0xA0F070EA] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEventStarted(player, command, triggerName)
|
||||||
|
|
||||||
|
--Are they in active mode?
|
||||||
|
if (player:GetState() != 2) then
|
||||||
|
player:SendGameMessage(GetWorldMaster(), 32503, 0x20);
|
||||||
|
player:endEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (weaponskillHandlers[command.actorId] ~= nil) then
|
||||||
|
weaponskillHandlers[command.actorId](player);
|
||||||
|
else
|
||||||
|
player:SendMessage(0x20, "", "That weaponskill is not implemented yet.");
|
||||||
|
end
|
||||||
|
|
||||||
|
player:endEvent();
|
||||||
|
|
||||||
|
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user