open-tibia-tools 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +29 -0
  2. package/effectFramesGenerator.html +42 -0
  3. package/effectFramesGenerator.ts +95 -0
  4. package/itemImageFramesGenerator.html +45 -0
  5. package/itemImageFramesGenerator.ts +140 -0
  6. package/itemImageGenerator.html +40 -0
  7. package/itemImageGenerator.ts +161 -0
  8. package/missileFramesGenerator.html +42 -0
  9. package/missileFramesGenerator.ts +95 -0
  10. package/otbEditor.html +21 -0
  11. package/otbEditor.ts +106 -0
  12. package/outfitImageGenerator.html +38 -0
  13. package/outfitImageGenerator.ts +109 -0
  14. package/outfitImagePhpGeneratorCode.ts +19 -0
  15. package/package.json +28 -0
  16. package/tests.html +29 -0
  17. package/tests.ts +218 -0
  18. package/tools/colored-outfit-images-generator/README.md +7 -0
  19. package/tools/colored-outfit-images-generator/abuse_warning.png +0 -0
  20. package/tools/colored-outfit-images-generator/animoutfit.php +103 -0
  21. package/tools/colored-outfit-images-generator/cacheGenerator.php +40 -0
  22. package/tools/colored-outfit-images-generator/config.php +25 -0
  23. package/tools/colored-outfit-images-generator/filesAsJson.php +22 -0
  24. package/tools/colored-outfit-images-generator/index.php +21 -0
  25. package/tools/colored-outfit-images-generator/libs/gifCreator.php +343 -0
  26. package/tools/colored-outfit-images-generator/libs/outfitter.php +312 -0
  27. package/tools/colored-outfit-images-generator/outfit.php +77 -0
  28. package/tools/colored-outfit-images-generator/release.php +40 -0
  29. package/tools/item-image-frames-to-animated-gif-converter/1-10/1.gif +0 -0
  30. package/tools/item-image-frames-to-animated-gif-converter/1-10/1.png +0 -0
  31. package/tools/item-image-frames-to-animated-gif-converter/1-10/10.gif +0 -0
  32. package/tools/item-image-frames-to-animated-gif-converter/1-10/10.png +0 -0
  33. package/tools/item-image-frames-to-animated-gif-converter/1-10/2.gif +0 -0
  34. package/tools/item-image-frames-to-animated-gif-converter/1-10/2.png +0 -0
  35. package/tools/item-image-frames-to-animated-gif-converter/1-10/3.gif +0 -0
  36. package/tools/item-image-frames-to-animated-gif-converter/1-10/3.png +0 -0
  37. package/tools/item-image-frames-to-animated-gif-converter/1-10/4.gif +0 -0
  38. package/tools/item-image-frames-to-animated-gif-converter/1-10/4.png +0 -0
  39. package/tools/item-image-frames-to-animated-gif-converter/1-10/5.gif +0 -0
  40. package/tools/item-image-frames-to-animated-gif-converter/1-10/5.png +0 -0
  41. package/tools/item-image-frames-to-animated-gif-converter/1-10/6.gif +0 -0
  42. package/tools/item-image-frames-to-animated-gif-converter/1-10/6.png +0 -0
  43. package/tools/item-image-frames-to-animated-gif-converter/1-10/7.gif +0 -0
  44. package/tools/item-image-frames-to-animated-gif-converter/1-10/7.png +0 -0
  45. package/tools/item-image-frames-to-animated-gif-converter/1-10/8.gif +0 -0
  46. package/tools/item-image-frames-to-animated-gif-converter/1-10/8.png +0 -0
  47. package/tools/item-image-frames-to-animated-gif-converter/1-10/9.gif +0 -0
  48. package/tools/item-image-frames-to-animated-gif-converter/1-10/9.png +0 -0
  49. package/tools/item-image-frames-to-animated-gif-converter/README.md +20 -0
  50. package/tools/item-image-frames-to-animated-gif-converter/cli_convert.php +42 -0
  51. package/tools/item-image-frames-to-animated-gif-converter/generated-zip-archives/.gitignore +3 -0
  52. package/tools/item-image-frames-to-animated-gif-converter/generated-zip-archives/index.html +1 -0
  53. package/tools/item-image-frames-to-animated-gif-converter/index.php +97 -0
  54. package/tools/item-image-frames-to-animated-gif-converter/lib/abstractPngConverterAnimation.php +87 -0
  55. package/tools/item-image-frames-to-animated-gif-converter/lib/apngCreator.php +247 -0
  56. package/tools/item-image-frames-to-animated-gif-converter/lib/converterPngToApngAnimation.php +93 -0
  57. package/tools/item-image-frames-to-animated-gif-converter/lib/converterPngToGifAnimation.php +90 -0
  58. package/tools/item-image-frames-to-animated-gif-converter/lib/gifCreator.php +339 -0
  59. package/tsconfig.json +12 -0
  60. package/webpack.config.js +53 -0
  61. package/websiteImageGeneratorBase.ts +156 -0
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Open Tibia Tools
2
+
3
+ Browser tools for viewing and converting Tibia/OTS DAT, SPR and OTB files.
4
+
5
+ Uses [@gesior/open-tibia-library](https://www.npmjs.com/package/@gesior/open-tibia-library) for parsing. File pickers and downloads stay in this project.
6
+
7
+ ## Setup
8
+
9
+ ```
10
+ npm install
11
+ npm run build
12
+ ```
13
+
14
+ Then open an HTML file in a browser (Chrome), for example `itemImageFramesGenerator.html`.
15
+
16
+ ## Tools
17
+
18
+ - `itemImageGenerator.html` — item images (PNG/GIF ZIP)
19
+ - `itemImageFramesGenerator.html` — item animation frames for the PHP GIF/APNG converter
20
+ - `outfitImageGenerator.html` — outfit frames plus PHP outfit host files
21
+ - `effectFramesGenerator.html` — magic effect frames
22
+ - `missileFramesGenerator.html` — missile frames
23
+ - `otbEditor.html` — example `items.otb` editor
24
+ - `tests.html` — playground
25
+
26
+ PHP helpers:
27
+
28
+ - `tools/item-image-frames-to-animated-gif-converter/` — PNG frames to GIF/APNG
29
+ - `tools/colored-outfit-images-generator/` — colored outfit images from exported frames
@@ -0,0 +1,42 @@
1
+ <html>
2
+ <head>
3
+ <title>Effect Frames Generator - OpenTibiaLibrary</title>
4
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
5
+ </head>
6
+ <body>
7
+ <h2>Effect frames generator (for animated effects PHP script)</h2>
8
+ <blockquote>
9
+ How to use:<br/><br/>
10
+ 1. Type version of Tibia client.<br/>
11
+ 2. Select SPR and DAT files.<br/>
12
+ 3. Click "LOAD FILES", watch "Progress".<br/>
13
+ 4. Click "GENERATE IMAGES", wait for ZIP file download.<br/>
14
+ 5. Convert generated PNG images into animations using:<br/>
15
+ <a href="https://item-images.ots.me/png-to-gif-converter/">https://item-images.ots.me/png-to-gif-converter/</a><br/>
16
+ You can also download <a href="https://github.com/gesior/open-tibia-tools">https://github.com/gesior/open-tibia-tools</a>
17
+ and use command line PHP script <b>"tools/item-image-frames-to-animated-gif-converter/cli_convert.php"</b>
18
+ to convert it to animations on your PC<br/>
19
+ <br/>
20
+ <b>FILES ARE NOT SEND TO SERVER! EVERYTHING IS GENERATED ON YOUR COMPUTER.</b><br/>
21
+ <br/>
22
+ (Enable Developer console in webbrowser to get more information about problems/progress)
23
+ </blockquote>
24
+ Client Version: <input type="number" id="clientversion" value="860"/> (format 860, NOT 8.60, clients: 740 - 1099, type <b>1099</b> for latest .dat+.spr version [ex. from 12+])<br/>
25
+ Sprite file: <input type="file" id="spr"/><br/>
26
+ Dat file: <input type="file" id="dat"/><br/>
27
+ Force enable extended sprites: <input type="checkbox" id="forceEnableExtendedSprites"/> (OTC feature 'GameSpritesU32')<br/>
28
+ Enable transparency: <input type="checkbox" id="enableTransparency"/> (OTC feature 'GameSpritesAlphaChannel')<br/>
29
+ Enable improved animations: <input type="checkbox" id="enableEnhancedAnimations"/> (OTC feature 'GameEnhancedAnimations')<br/>
30
+ Enable frame groups: <input type="checkbox" id="enableIdleAnimations"/> (OTC feature 'GameIdleAnimations')<br/>
31
+ <br/>
32
+ <button id="loadFiles">LOAD FILES</button>
33
+ <br/>
34
+ <br/>
35
+ <button id="generateImages">GENERATE IMAGES</button>
36
+ <br/>
37
+ <br/>
38
+ <b>Progress:</b> <span id="progressBar">Not running</span><br/>
39
+ <script src="js/vendor.js"></script>
40
+ <script src="js/effectFramesGenerator.js"></script>
41
+ </body>
42
+ </html>
@@ -0,0 +1,95 @@
1
+ import {DatManager, DatThingCategory, GameFeature, ImageGenerator, OtbManager, SpriteManager} from "@gesior/open-tibia-library";
2
+ import {WebsiteImageGeneratorBase} from "./websiteImageGeneratorBase";
3
+
4
+ class EffectFramesGenerator extends WebsiteImageGeneratorBase {
5
+ private forceEnableExtendedSpritesCheckbox: HTMLInputElement;
6
+ private enableTransparencyCheckbox: HTMLInputElement;
7
+ private enableEnhancedAnimationsCheckbox: HTMLInputElement;
8
+ private enableIdleAnimationsCheckbox: HTMLInputElement;
9
+
10
+ init() {
11
+ this.otbRequired = false;
12
+ super.init();
13
+ this.forceEnableExtendedSpritesCheckbox = <HTMLInputElement>document.getElementById('forceEnableExtendedSprites');
14
+ this.enableTransparencyCheckbox = <HTMLInputElement>document.getElementById('enableTransparency');
15
+ this.enableEnhancedAnimationsCheckbox = <HTMLInputElement>document.getElementById('enableEnhancedAnimations');
16
+ this.enableIdleAnimationsCheckbox = <HTMLInputElement>document.getElementById('enableIdleAnimations');
17
+ }
18
+
19
+ afterSetClientVersion() {
20
+ if (this.forceEnableExtendedSpritesCheckbox.checked) {
21
+ this.client.enableFeature(GameFeature.GameSpritesU32);
22
+ }
23
+ if (this.enableTransparencyCheckbox.checked) {
24
+ this.client.enableFeature(GameFeature.GameSpritesAlphaChannel);
25
+ }
26
+ if (this.enableEnhancedAnimationsCheckbox.checked) {
27
+ this.client.enableFeature(GameFeature.GameEnhancedAnimations);
28
+ }
29
+ if (this.enableIdleAnimationsCheckbox.checked) {
30
+ this.client.enableFeature(GameFeature.GameIdleAnimations);
31
+ }
32
+ }
33
+
34
+ startImageGenerator(imageGenerator: ImageGenerator, otbManager: OtbManager, datManager: DatManager, spriteManager: SpriteManager, zip) {
35
+ this.generateEffectImage(imageGenerator, datManager, zip, 0);
36
+ }
37
+
38
+ generateEffectImage(imageGenerator: ImageGenerator, datManager: DatManager, zip, effectId: number) {
39
+ const self = this;
40
+ this.progressValue(effectId, datManager.getCategory(DatThingCategory.ThingCategoryEffect).length);
41
+ if (effectId > datManager.getCategory(DatThingCategory.ThingCategoryEffect).length) {
42
+ this.progressText('Packing images to ZIP file, please wait (it may take a while)');
43
+ zip.generateAsync({type: "blob"}).then(function (blob: Blob) {
44
+ console.log('zip size', blob.size);
45
+ self.progressText('ZIP generated, it should start download now.');
46
+ self.downloadBlob('effects.zip', blob);
47
+ });
48
+ return;
49
+ }
50
+
51
+ let effectThingType = this.datManager.getEffect(effectId);
52
+ if (!effectThingType) {
53
+ console.log('dat ID not found in dat file', effectId);
54
+ setTimeout(function () {
55
+ self.generateEffectImage(imageGenerator, datManager, zip, effectId + 1);
56
+ }, 1);
57
+ return;
58
+ }
59
+
60
+ const effectSprites = imageGenerator.generateEffectImagesById(effectId);
61
+ if (!effectSprites || effectSprites.length == 0) {
62
+ setTimeout(function () {
63
+ self.generateEffectImage(imageGenerator, datManager, zip, effectId + 1);
64
+ }, 1);
65
+ return;
66
+ }
67
+
68
+ const firstEffectSprite = effectSprites[0];
69
+ const canvas = <HTMLCanvasElement>document.createElement('canvas');
70
+ canvas.width = firstEffectSprite.getWidth() * effectSprites.length;
71
+ canvas.height = firstEffectSprite.getHeight();
72
+ document.getElementsByTagName('body')[0].appendChild(canvas);
73
+ const ctx = canvas.getContext("2d");
74
+
75
+ for (let animationFrame = 0; animationFrame < effectSprites.length; animationFrame++) {
76
+ const palette = ctx.getImageData(firstEffectSprite.getWidth() * animationFrame, 0, firstEffectSprite.getWidth(), firstEffectSprite.getHeight());
77
+ const effectSprite = effectSprites[animationFrame];
78
+ palette.data.set(new Uint8ClampedArray(effectSprite.getPixels().m_buffer.buffer));
79
+ ctx.putImageData(palette, firstEffectSprite.getWidth() * animationFrame, 0);
80
+ }
81
+
82
+ const callback = function (blob) {
83
+ canvas.remove();
84
+ zip.file('effects/' + effectId + '_' + effectSprites.length + '.png', blob);
85
+ setTimeout(function () {
86
+ self.generateEffectImage(imageGenerator, datManager, zip, effectId + 1);
87
+ }, 1);
88
+
89
+ };
90
+ canvas.toBlob(callback);
91
+ }
92
+ }
93
+
94
+ const effectFramesGenerator = new EffectFramesGenerator();
95
+ effectFramesGenerator.init();
@@ -0,0 +1,45 @@
1
+ <html>
2
+ <head>
3
+ <title>Item Image Frames Generator - OpenTibiaLibrary</title>
4
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
5
+ </head>
6
+ <body>
7
+ <h2>Item image frames generator (for animated items PHP script)</h2>
8
+ <blockquote>
9
+ How to use:<br/><br/>
10
+ 1. Type version of Tibia client.<br/>
11
+ 2. Select SPR, DAT and OTB files.<br/>
12
+ 3. Click "LOAD FILES", watch "Progress".<br/>
13
+ 4. Click "GENERATE IMAGES", wait for ZIP file download.<br/>
14
+ 5. Convert generated PNG images into animations using:<br/>
15
+ <a href="https://item-images.ots.me/png-to-gif-converter/">https://item-images.ots.me/png-to-gif-converter/</a><br/>
16
+ You can also download <a href="https://github.com/gesior/open-tibia-tools">https://github.com/gesior/open-tibia-tools</a>
17
+ and use command line PHP script <b>"tools/item-image-frames-to-animated-gif-converter/cli_convert.php"</b>
18
+ to convert it to animations on your PC<br/>
19
+ <br/>
20
+ <b>FILES ARE NOT SEND TO SERVER! EVERYTHING IS GENERATED ON YOUR COMPUTER.</b><br/>
21
+ <br/>
22
+ (Enable Developer console in webbrowser to get more information about problems/progress)
23
+ </blockquote>
24
+ Client Version: <input type="number" id="clientversion" value="860"/> (format 860, NOT 8.60, clients: 740 - 1099, type <b>1099</b> for latest .dat+.spr version [ex. from 12+])<br/>
25
+ Sprite file: <input type="file" id="spr"/><br/>
26
+ Dat file: <input type="file" id="dat"/><br/>
27
+ Otb file: <input type="file" id="otb"/><br/>
28
+ Only pickable items: <input type="checkbox" id="onlyPickable" checked/><br/>
29
+ Force enable extended sprites: <input type="checkbox" id="forceEnableExtendedSprites"/> (OTC feature 'GameSpritesU32')<br/>
30
+ Enable transparency: <input type="checkbox" id="enableTransparency"/> (OTC feature 'GameSpritesAlphaChannel')<br/>
31
+ Enable improved animations: <input type="checkbox" id="enableEnhancedAnimations"/> (OTC feature 'GameEnhancedAnimations')<br/>
32
+ Enable frame groups: <input type="checkbox" id="enableIdleAnimations"/> (OTC feature 'GameIdleAnimations')<br/>
33
+ Use .dat item IDs as image IDs: <input type="checkbox" id="useDatItemIdsAsImageIds"/> (no 'items.otb' required)<br/>
34
+ <br/>
35
+ <button id="loadFiles">LOAD FILES</button>
36
+ <br/>
37
+ <br/>
38
+ <button id="generateImages">GENERATE IMAGES</button>
39
+ <br/>
40
+ <br/>
41
+ <b>Progress:</b> <span id="progressBar">Not running</span><br/>
42
+ <script src="js/vendor.js"></script>
43
+ <script src="js/itemImageFramesGenerator.js"></script>
44
+ </body>
45
+ </html>
@@ -0,0 +1,140 @@
1
+ import {DatManager, DatThingCategory, GameFeature, ImageGenerator, OtbManager, SpriteManager} from "@gesior/open-tibia-library";
2
+ import {WebsiteImageGeneratorBase} from "./websiteImageGeneratorBase";
3
+
4
+ class ItemImageGenerator extends WebsiteImageGeneratorBase {
5
+ private onlyPickableCheckbox: HTMLInputElement;
6
+ private forceEnableExtendedSpritesCheckbox: HTMLInputElement;
7
+ private enableTransparencyCheckbox: HTMLInputElement;
8
+ private enableEnhancedAnimationsCheckbox: HTMLInputElement;
9
+ private enableIdleAnimationsCheckbox: HTMLInputElement;
10
+ private useDatItemIdsAsImageIdsCheckbox: HTMLInputElement;
11
+
12
+ private onlyPickable = true;
13
+ private useDatItemIdsAsImageIds = false;
14
+
15
+ init() {
16
+ super.init();
17
+ this.onlyPickableCheckbox = <HTMLInputElement>document.getElementById('onlyPickable');
18
+ this.forceEnableExtendedSpritesCheckbox = <HTMLInputElement>document.getElementById('forceEnableExtendedSprites');
19
+ this.enableTransparencyCheckbox = <HTMLInputElement>document.getElementById('enableTransparency');
20
+ this.enableEnhancedAnimationsCheckbox = <HTMLInputElement>document.getElementById('enableEnhancedAnimations');
21
+ this.enableIdleAnimationsCheckbox = <HTMLInputElement>document.getElementById('enableIdleAnimations');
22
+ this.useDatItemIdsAsImageIdsCheckbox = <HTMLInputElement>document.getElementById('useDatItemIdsAsImageIds');
23
+ }
24
+
25
+ afterSetClientVersion() {
26
+ if (this.forceEnableExtendedSpritesCheckbox.checked) {
27
+ this.client.enableFeature(GameFeature.GameSpritesU32);
28
+ }
29
+ if (this.enableTransparencyCheckbox.checked) {
30
+ this.client.enableFeature(GameFeature.GameSpritesAlphaChannel);
31
+ }
32
+ if (this.enableEnhancedAnimationsCheckbox.checked) {
33
+ this.client.enableFeature(GameFeature.GameEnhancedAnimations);
34
+ }
35
+ if (this.enableIdleAnimationsCheckbox.checked) {
36
+ this.client.enableFeature(GameFeature.GameIdleAnimations);
37
+ }
38
+ this.otbRequired = !this.useDatItemIdsAsImageIdsCheckbox.checked;
39
+ }
40
+
41
+ startImageGenerator(imageGenerator: ImageGenerator, otbManager: OtbManager, datManager: DatManager, spriteManager: SpriteManager, zip) {
42
+ this.onlyPickable = this.onlyPickableCheckbox.checked;
43
+ this.useDatItemIdsAsImageIds = this.useDatItemIdsAsImageIdsCheckbox.checked;
44
+ this.generateItemImage(imageGenerator, zip, 0);
45
+ }
46
+
47
+ generateItemImage(imageGenerator: ImageGenerator, zip, serverId: number) {
48
+ const self = this;
49
+ if (this.useDatItemIdsAsImageIds) {
50
+ this.progressValue(serverId, this.datManager.getCategory(DatThingCategory.ThingCategoryItem).length);
51
+ } else {
52
+ this.progressValue(serverId, this.otbManager.getLastId());
53
+ }
54
+ if ((this.useDatItemIdsAsImageIds && serverId > this.datManager.getCategory(DatThingCategory.ThingCategoryItem).length) ||
55
+ (!this.useDatItemIdsAsImageIds && serverId > this.otbManager.getLastId())) {
56
+ this.progressText('Packing images to ZIP file, please wait (it may take a while)');
57
+ zip.generateAsync({type: "blob"}).then(function (blob: Blob) {
58
+ console.log('zip size', blob.size);
59
+ self.progressText('ZIP generated, it should start download now.');
60
+ self.downloadBlob('items.zip', blob);
61
+ });
62
+ return;
63
+ }
64
+
65
+ let clientItemId = serverId;
66
+ if (!this.useDatItemIdsAsImageIds) {
67
+ if (!this.otbManager.isValidOtbId(serverId)) {
68
+ setTimeout(function () {
69
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
70
+ }, 1);
71
+ return;
72
+ }
73
+
74
+ clientItemId = this.otbManager.getItem(serverId).getClientId();
75
+ if (!clientItemId) {
76
+ console.log('otb ID not mapped to any dat ID', serverId);
77
+ setTimeout(function () {
78
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
79
+ }, 1);
80
+ return;
81
+ }
82
+ }
83
+
84
+ let itemThingType = this.datManager.getItem(clientItemId);
85
+ if (!itemThingType) {
86
+ console.log('dat ID not found in dat file', serverId, clientItemId);
87
+ setTimeout(function () {
88
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
89
+ }, 1);
90
+ return;
91
+ }
92
+ if (this.onlyPickable && !itemThingType.isPickupable()) {
93
+ console.log('skip not pickable', serverId);
94
+ setTimeout(function () {
95
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
96
+ }, 1);
97
+ return;
98
+ }
99
+
100
+ let itemSprites = null;
101
+ if (this.useDatItemIdsAsImageIds) {
102
+ itemSprites = imageGenerator.generateItemImagesByClientId(serverId);
103
+ } else {
104
+ itemSprites = imageGenerator.generateItemImagesByServerId(serverId);
105
+ }
106
+ if (!itemSprites || itemSprites.length == 0) {
107
+ setTimeout(function () {
108
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
109
+ }, 1);
110
+ return;
111
+ }
112
+
113
+ const firstItemSprite = itemSprites[0];
114
+ const canvas = <HTMLCanvasElement>document.createElement('canvas');
115
+ canvas.width = firstItemSprite.getWidth() * itemSprites.length;
116
+ canvas.height = firstItemSprite.getHeight();
117
+ document.getElementsByTagName('body')[0].appendChild(canvas);
118
+ const ctx = canvas.getContext("2d");
119
+
120
+ for (let animationFrame = 0; animationFrame < itemSprites.length; animationFrame++) {
121
+ const palette = ctx.getImageData(firstItemSprite.getWidth() * animationFrame, 0, firstItemSprite.getWidth(), firstItemSprite.getHeight());
122
+ const itemSprite = itemSprites[animationFrame];
123
+ palette.data.set(new Uint8ClampedArray(itemSprite.getPixels().m_buffer.buffer));
124
+ ctx.putImageData(palette, firstItemSprite.getWidth() * animationFrame, 0);
125
+ }
126
+
127
+ const callback = function (blob) {
128
+ canvas.remove();
129
+ zip.file('items/' + serverId + '_' + itemSprites.length + '.png', blob);
130
+ setTimeout(function () {
131
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
132
+ }, 1);
133
+
134
+ };
135
+ canvas.toBlob(callback);
136
+ }
137
+ }
138
+
139
+ const itemImageGenerator = new ItemImageGenerator();
140
+ itemImageGenerator.init();
@@ -0,0 +1,40 @@
1
+ <html>
2
+ <head>
3
+ <title>Item Image Generator - OpenTibiaLibrary</title>
4
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
5
+ </head>
6
+ <body>
7
+ <h2>Item images generator</h2>
8
+ <blockquote>
9
+ How to use:<br/><br/>
10
+ 1. Type version of Tibia client.<br/>
11
+ 2. Select SPR, DAT and OTB files.<br/>
12
+ 3. Click "LOAD FILES", watch "Progress".<br/>
13
+ 4. Click "GENERATE IMAGES", wait for ZIP file download.<br/>
14
+ <br/>
15
+ <b>FILES ARE NOT SEND TO SERVER! EVERYTHING IS GENERATED ON YOUR COMPUTER.</b><br/>
16
+ <br/>
17
+ (Enable Developer console in webbrowser to get more information about problems/progress)
18
+ </blockquote>
19
+ Client Version: <input type="number" id="clientversion" value="860"/> (format 860, NOT 8.60, clients: 740 - 1099, type <b>1099</b> for latest .dat+.spr version [ex. from 12+])<br/>
20
+ Sprite file: <input type="file" id="spr"/><br/>
21
+ Dat file: <input type="file" id="dat"/><br/>
22
+ Otb file: <input type="file" id="otb"/><br/>
23
+ Only pickable items: <input type="checkbox" id="onlyPickable" checked/><br/>
24
+ Force enable extended sprites: <input type="checkbox" id="forceEnableExtendedSprites"/> (OTC feature 'GameSpritesU32')<br/>
25
+ Enable transparency: <input type="checkbox" id="enableTransparency"/> (OTC feature 'GameSpritesAlphaChannel')<br/>
26
+ Enable improved animations: <input type="checkbox" id="enableEnhancedAnimations"/> (OTC feature 'GameEnhancedAnimations')<br/>
27
+ Enable frame groups: <input type="checkbox" id="enableIdleAnimations"/> (OTC feature 'GameIdleAnimations')<br/>
28
+ Use .dat item IDs as image IDs: <input type="checkbox" id="useDatItemIdsAsImageIds"/> (no 'items.otb' required)<br/>
29
+ <br/>
30
+ <button id="loadFiles">LOAD FILES</button>
31
+ <br/>
32
+ <br/>
33
+ <button id="generateImages">GENERATE IMAGES</button>
34
+ <br/>
35
+ <br/>
36
+ <b>Progress:</b> <span id="progressBar">Not running</span><br/>
37
+ <script src="js/vendor.js"></script>
38
+ <script src="js/itemImageGenerator.js"></script>
39
+ </body>
40
+ </html>
@@ -0,0 +1,161 @@
1
+ import {DatManager, DatThingCategory, GameFeature, ImageGenerator, OtbManager, SpriteManager} from "@gesior/open-tibia-library";
2
+ import {WebsiteImageGeneratorBase} from "./websiteImageGeneratorBase";
3
+
4
+ let GIF = require('gif.js');
5
+
6
+ class ItemImageGenerator extends WebsiteImageGeneratorBase {
7
+ private onlyPickableCheckbox: HTMLInputElement;
8
+ private forceEnableExtendedSpritesCheckbox: HTMLInputElement;
9
+ private enableTransparencyCheckbox: HTMLInputElement;
10
+ private enableEnhancedAnimationsCheckbox: HTMLInputElement;
11
+ private enableIdleAnimationsCheckbox: HTMLInputElement;
12
+ private useDatItemIdsAsImageIdsCheckbox: HTMLInputElement;
13
+
14
+ private onlyPickable = true;
15
+ private useDatItemIdsAsImageIds = false;
16
+
17
+ init() {
18
+ super.init();
19
+ this.onlyPickableCheckbox = <HTMLInputElement>document.getElementById('onlyPickable');
20
+ this.forceEnableExtendedSpritesCheckbox = <HTMLInputElement>document.getElementById('forceEnableExtendedSprites');
21
+ this.enableTransparencyCheckbox = <HTMLInputElement>document.getElementById('enableTransparency');
22
+ this.enableEnhancedAnimationsCheckbox = <HTMLInputElement>document.getElementById('enableEnhancedAnimations');
23
+ this.enableIdleAnimationsCheckbox = <HTMLInputElement>document.getElementById('enableIdleAnimations');
24
+ this.useDatItemIdsAsImageIdsCheckbox = <HTMLInputElement>document.getElementById('useDatItemIdsAsImageIds');
25
+ }
26
+
27
+ afterSetClientVersion() {
28
+ if (this.forceEnableExtendedSpritesCheckbox.checked) {
29
+ this.client.enableFeature(GameFeature.GameSpritesU32);
30
+ }
31
+ if (this.enableTransparencyCheckbox.checked) {
32
+ this.client.enableFeature(GameFeature.GameSpritesAlphaChannel);
33
+ }
34
+ if (this.enableEnhancedAnimationsCheckbox.checked) {
35
+ this.client.enableFeature(GameFeature.GameEnhancedAnimations);
36
+ }
37
+ if (this.enableIdleAnimationsCheckbox.checked) {
38
+ this.client.enableFeature(GameFeature.GameIdleAnimations);
39
+ }
40
+ this.otbRequired = !this.useDatItemIdsAsImageIdsCheckbox.checked;
41
+ }
42
+
43
+ startImageGenerator(imageGenerator: ImageGenerator, otbManager: OtbManager, datManager: DatManager, spriteManager: SpriteManager, zip) {
44
+ this.onlyPickable = this.onlyPickableCheckbox.checked;
45
+ this.useDatItemIdsAsImageIds = this.useDatItemIdsAsImageIdsCheckbox.checked;
46
+ this.generateItemImage(imageGenerator, zip, 0);
47
+ }
48
+
49
+ generateItemImage(imageGenerator: ImageGenerator, zip, serverId: number) {
50
+ const self = this;
51
+ if (this.useDatItemIdsAsImageIds) {
52
+ this.progressValue(serverId, this.datManager.getCategory(DatThingCategory.ThingCategoryItem).length);
53
+ } else {
54
+ this.progressValue(serverId, this.otbManager.getLastId());
55
+ }
56
+ if ((this.useDatItemIdsAsImageIds && serverId > this.datManager.getCategory(DatThingCategory.ThingCategoryItem).length) ||
57
+ (!this.useDatItemIdsAsImageIds && serverId > this.otbManager.getLastId())) {
58
+ this.progressText('Packing images to ZIP file, please wait (it may take a while)');
59
+ zip.generateAsync({type: "blob"}).then(function (blob: Blob) {
60
+ console.log('zip size', blob.size);
61
+ self.progressText('ZIP generated, it should start download now.');
62
+ self.downloadBlob('items.zip', blob);
63
+ });
64
+ return;
65
+ }
66
+
67
+ let clientItemId = serverId;
68
+ if (!this.useDatItemIdsAsImageIds) {
69
+ if (!this.otbManager.isValidOtbId(serverId)) {
70
+ setTimeout(function () {
71
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
72
+ }, 1);
73
+ return;
74
+ }
75
+
76
+ clientItemId = this.otbManager.getItem(serverId).getClientId();
77
+ if (!clientItemId) {
78
+ console.log('otb ID not mapped to any dat ID', serverId);
79
+ setTimeout(function () {
80
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
81
+ }, 1);
82
+ return;
83
+ }
84
+ }
85
+
86
+ let itemThingType = this.datManager.getItem(clientItemId);
87
+ if (!itemThingType) {
88
+ console.log('dat ID not found in dat file', serverId, clientItemId);
89
+ setTimeout(function () {
90
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
91
+ }, 1);
92
+ return;
93
+ }
94
+ if (this.onlyPickable && !itemThingType.isPickupable()) {
95
+ console.log('skip not pickable', serverId);
96
+ setTimeout(function () {
97
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
98
+ }, 1);
99
+ return;
100
+ }
101
+
102
+ let itemSprite = null;
103
+ if (this.useDatItemIdsAsImageIds) {
104
+ itemSprite = imageGenerator.generateItemImageByClientId(serverId);
105
+ } else {
106
+ itemSprite = imageGenerator.generateItemImageByServerId(serverId);
107
+ }
108
+ if (!itemSprite) {
109
+ setTimeout(function () {
110
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
111
+ }, 1);
112
+ return;
113
+ }
114
+
115
+ const canvas = <HTMLCanvasElement>document.createElement('canvas');
116
+ canvas.width = itemSprite.getWidth();
117
+ canvas.height = itemSprite.getHeight();
118
+ document.getElementsByTagName('body')[0].appendChild(canvas);
119
+ const ctx = canvas.getContext("2d");
120
+ const palette = ctx.getImageData(0, 0, itemSprite.getWidth(), itemSprite.getHeight());
121
+ palette.data.set(new Uint8ClampedArray(itemSprite.getPixels().m_buffer.buffer));
122
+ ctx.putImageData(palette, 0, 0);
123
+
124
+ if (self.imageFormat == 'png') {
125
+ const callback = function (blob) {
126
+ canvas.remove();
127
+ zip.file('items/' + serverId + '.png', blob);
128
+ setTimeout(function () {
129
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
130
+ }, 1);
131
+
132
+ };
133
+ canvas.toBlob(callback);
134
+ } else {
135
+ const gif = new GIF({
136
+ workers: 1,
137
+ quality: 10,
138
+ width: itemSprite.getWidth(),
139
+ height: itemSprite.getHeight(),
140
+ workerScript: './js/gif.worker.js',
141
+ transparent: 'rgba(0,0,0,0)'
142
+ });
143
+
144
+ gif.addFrame(canvas, {copy: true});
145
+ canvas.remove();
146
+
147
+ gif.on('finished', function (blob) {
148
+ zip.file(serverId + '.gif', blob);
149
+ setTimeout(function () {
150
+ self.generateItemImage(imageGenerator, zip, serverId + 1);
151
+ }, 1);
152
+
153
+ });
154
+
155
+ gif.render();
156
+ }
157
+ }
158
+ }
159
+
160
+ const itemImageGenerator = new ItemImageGenerator();
161
+ itemImageGenerator.init();
@@ -0,0 +1,42 @@
1
+ <html>
2
+ <head>
3
+ <title>Missile Frames Generator - OpenTibiaLibrary</title>
4
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
5
+ </head>
6
+ <body>
7
+ <h2>Missile frames generator</h2>
8
+ <blockquote>
9
+ How to use:<br/><br/>
10
+ 1. Type version of Tibia client.<br/>
11
+ 2. Select SPR and DAT files.<br/>
12
+ 3. Click "LOAD FILES", watch "Progress".<br/>
13
+ 4. Click "GENERATE IMAGES", wait for ZIP file download.<br/>
14
+ 5. Convert generated PNG images into animations using:<br/>
15
+ <a href="https://item-images.ots.me/png-to-gif-converter/">https://item-images.ots.me/png-to-gif-converter/</a><br/>
16
+ You can also download <a href="https://github.com/gesior/open-tibia-tools">https://github.com/gesior/open-tibia-tools</a>
17
+ and use command line PHP script <b>"tools/item-image-frames-to-animated-gif-converter/cli_convert.php"</b>
18
+ to convert it into animations on your PC<br/>
19
+ <br/>
20
+ <b>FILES ARE NOT SEND TO SERVER! EVERYTHING IS GENERATED ON YOUR COMPUTER.</b><br/>
21
+ <br/>
22
+ (Enable Developer console in webbrowser to get more information about problems/progress)
23
+ </blockquote>
24
+ Client Version: <input type="number" id="clientversion" value="860"/> (format 860, NOT 8.60, clients: 740 - 1099, type <b>1099</b> for latest .dat+.spr version [ex. from 12+])<br/>
25
+ Sprite file: <input type="file" id="spr"/><br/>
26
+ Dat file: <input type="file" id="dat"/><br/>
27
+ Force enable extended sprites: <input type="checkbox" id="forceEnableExtendedSprites"/> (OTC feature 'GameSpritesU32')<br/>
28
+ Enable transparency: <input type="checkbox" id="enableTransparency"/> (OTC feature 'GameSpritesAlphaChannel')<br/>
29
+ Enable improved animations: <input type="checkbox" id="enableEnhancedAnimations"/> (OTC feature 'GameEnhancedAnimations')<br/>
30
+ Enable frame groups: <input type="checkbox" id="enableIdleAnimations"/> (OTC feature 'GameIdleAnimations')<br/>
31
+ <br/>
32
+ <button id="loadFiles">LOAD FILES</button>
33
+ <br/>
34
+ <br/>
35
+ <button id="generateImages">GENERATE IMAGES</button>
36
+ <br/>
37
+ <br/>
38
+ <b>Progress:</b> <span id="progressBar">Not running</span><br/>
39
+ <script src="js/vendor.js"></script>
40
+ <script src="js/missileFramesGenerator.js"></script>
41
+ </body>
42
+ </html>