├── .classpath
├── .gitattributes
├── .gitignore
├── .project
├── AndroidManifest.xml
├── ChangeLog.Android
├── README.md
├── bin
├── classes.dex
└── resources.ap_
├── default.properties
├── res
├── drawable-hdpi
│ └── icon.png
├── drawable-ldpi
│ └── icon.png
├── drawable-mdpi
│ └── icon.png
├── layout
│ ├── main.xml
│ └── savename.xml
├── menu
│ └── options_menu.xml
├── values
│ └── strings.xml
└── xml
│ └── preferences.xml
└── src
└── com
└── exult
└── android
├── AStarPathFinder.java
├── Actor.java
├── ActorAction.java
├── ActorGump.java
├── AndroidSave.java
├── Animator.java
├── Audio.java
├── AudioSample.java
├── BargeObject.java
├── Block.java
├── Cheat.java
├── ChunkTerrain.java
├── CombatSchedule.java
├── ContainerGameObject.java
├── Conversation.java
├── DataSource.java
├── DataUtils.java
├── DraggingInfo.java
├── EConst.java
├── EFile.java
├── EFileManager.java
├── EUtil.java
├── EffectsManager.java
├── EggObject.java
├── ExultActivity.java
├── FlexFile.java
├── FontsVgaFile.java
├── Game.java
├── GameClock.java
├── GameMap.java
├── GameMenuGump.java
├── GameObject.java
├── GameRender.java
├── GameSingletons.java
├── GameWindow.java
├── Gump.java
├── GumpManager.java
├── GumpWidget.java
├── IfixGameObject.java
├── ImageBuf.java
├── IregGameObject.java
├── ItemNames.java
├── MainActor.java
├── MapChunk.java
├── MonsterActor.java
├── Mouse.java
├── NewFileGump.java
├── NpcActor.java
├── NpcTimers.java
├── ObjectList.java
├── Palette.java
├── PartyManager.java
├── PathFinder.java
├── PlasmaThread.java
├── Preferences.java
├── Ready.java
├── Rectangle.java
├── Schedule.java
├── Shape.java
├── ShapeFiles.java
├── ShapeFrame.java
├── ShapeID.java
├── ShapeInfo.java
├── ShapesVgaFile.java
├── Shortcuts.java
├── SignGump.java
├── SliderGump.java
├── SpellbookGump.java
├── SpellbookObject.java
├── StatsGump.java
├── TerrainGameObject.java
├── TextGump.java
├── Tile.java
├── TimeQueue.java
├── TimeSensitive.java
├── UsecodeIntrinsics.java
├── UsecodeMachine.java
├── UsecodeScript.java
├── UsecodeValue.java
├── VgaFile.java
├── VideoPlayer.java
├── VirtueStoneObject.java
├── YesNoGump.java
├── ZombiePathFinder.java
└── shapeinf
├── AmmoInfo.java
├── AnimationInfo.java
├── ArmorInfo.java
├── BaseInfo.java
├── BodyInfo.java
├── ContentRules.java
├── EffectiveHpInfo.java
├── ExplosionInfo.java
├── FrameFlagsInfo.java
├── FrameNameInfo.java
├── FrameUsecodeInfo.java
├── MonsterInfo.java
├── PaperdollItem.java
├── PaperdollNpc.java
├── SFXInfo.java
├── ShapeInfoLookup.java
├── WarmthInfo.java
└── WeaponInfo.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.bin binary
2 | *.flx binary
3 | *.pal binary
4 | *.shp binary
5 | *.vga binary
6 | *.xpm text
7 |
8 | *.bmp binary
9 | *.gif binary
10 | *.ico binary
11 | *.jpeg binary
12 | *.jpg binary
13 | *.png binary
14 |
15 | *.mid binary
16 | *.wav binary
17 |
18 | *.xls binary
19 |
20 | *.tar.gz binary
21 | *.tar.bz2 binary
22 | *.zip binary
23 |
24 | *.exe binary
25 | *.dmg binary
26 | *.zip binary
27 |
28 | *.sln eol=crlf
29 | *.vcproj eol=crlf
30 | *.vcxproj eol=crlf
31 | *.vsprops eol=crlf
32 |
33 | *.glade text diff=html
34 | *.htm text diff=html
35 | *.html text diff=html
36 | *.shtml text diff=html
37 | *.ui text diff=html
38 | *.xml text diff=html
39 |
40 | *.dat text diff=php
41 | *.inc text diff=php
42 | *.php text diff=php
43 | *.php3 text diff=php
44 | *.tpl text diff=php
45 |
46 | *.ac text
47 | *.am text
48 | *.in text
49 | *.m4 text
50 |
51 | *.bat text
52 | *.sh text
53 |
54 | *.cfg text
55 | *.txt text
56 |
57 | *.iss text
58 |
59 | *.c text diff=cpp
60 | *.cc text diff=cpp
61 | *.cpp text diff=cpp
62 | *.cxx text diff=cpp
63 | *.c++ text diff=cpp
64 | *.h text diff=cpp
65 | *.hh text diff=cpp
66 | *.hpp text diff=cpp
67 | *.ll text diff=cpp
68 | *.rc text
69 | *.uc text
70 | *.yy text diff=cpp
71 |
72 | Changelog text
73 | Makefile* text
74 |
75 | AUTHORS text
76 | COPYING text
77 | FAQ text
78 | INSTALL text
79 | NEWS text
80 | README* text
81 |
82 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | /bin/
13 | /gen/
14 | /out/
15 |
16 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ExultAndroid
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ChangeLog.Android:
--------------------------------------------------------------------------------
1 | 12-18-2010
2 | Show mouse when dragging or moving.
3 | Set Avatar speed to 1-3 ticks/frame.
4 | 12-19-2010
5 | Fixed bug in GumpManager that caused bad rendering and crashes.
6 | Show mouse 'flash'.
7 | 12-25-2010
8 | Opening scene seems to work.
9 | 12-30-2010
10 | Save/restore seems to work. Press 's' to bring up screen.
11 | 12-31-2010
12 | Music works with ogg files placed in /sdcard/Games/exult/music
13 | 1-3-2011
14 | Digital SFX supported with, for example, sqsfxbg.flx, in the
15 | /sdcard/Games/exult directory.
16 | Avatar moves when you drag with the mouse on any area that isn't
17 | draggable.
18 | Fixed a crash when double-clicking doors.
19 | 1-20-2011
20 | Several schedules implemented, and maybe work:
21 | Loiter
22 | Wander
23 | Pace
24 | Sit - You can double-click a chair.
25 | Talk - The mayor approaches you at the start.
26 | Waiter
27 | EatAtInn
28 | Preach (untested)
29 | I suggest removing all files from gamedat, and old savegames too.
30 | 1-25-2011
31 | Weapons are drawn with NPC's.
32 | Shortcut buttons are on the left side, and a few work: Q, T, S, I.
33 | Targeting: You drag with the mouse, and the object it's on shows up
34 | with a red outline. When you release, the action is taken.
35 | 2-24-2011
36 | Implemented spellbook.
37 | Implemented combat.
38 | Most usecode intrinsics are written.
39 | Alt-t = teleport, Alt-g = god mode, Alt-i = infravision
40 | Some of the above might even work a little.:-)
41 |
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ExultAndroid
2 | Ancient, unmaintained port of Exult to Java for Android.
3 |
4 | Quoting Dominus on issue #2:
5 |
6 | > This port to Android is very old by now and never even close to being finished. Probably a lot of things changed since then. You are more likely to succeed by adapting the native Android patch
7 | > http://goo.gl/E2y7Z. Since that patch we changed a lot of stuff, most importantly we switched to SDL2 which is much more compatible with Android. Also the port to iOS is probably helpful as some kind of guidance what needs to be done to make it work
8 | > https://github.com/litchie/exult-ios
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/bin/classes.dex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exult/ExultAndroid/abab4f2672f610a37c8c1ee4e35bba803cde6f46/bin/classes.dex
--------------------------------------------------------------------------------
/bin/resources.ap_:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exult/ExultAndroid/abab4f2672f610a37c8c1ee4e35bba803cde6f46/bin/resources.ap_
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-8
12 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exult/ExultAndroid/abab4f2672f610a37c8c1ee4e35bba803cde6f46/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exult/ExultAndroid/abab4f2672f610a37c8c1ee4e35bba803cde6f46/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exult/ExultAndroid/abab4f2672f610a37c8c1ee4e35bba803cde6f46/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
18 |
26 |
34 |
42 |
50 |
58 |
65 |
66 |
71 |
79 |
80 |
81 |
87 |
91 |
96 |
100 |
106 |
107 |
112 |
118 |
125 |
132 |
139 |
140 |
141 |
147 |
153 |
154 |
162 |
163 |
169 |
170 |
171 |
172 |
173 |
179 |
180 |
--------------------------------------------------------------------------------
/res/layout/savename.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/res/menu/options_menu.xml:
--------------------------------------------------------------------------------
1 |
63 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, ExultActivity!
4 | Exult
5 |
6 |
--------------------------------------------------------------------------------
/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
10 |
15 |
20 |
24 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/com/exult/android/AStarPathFinder.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.util.HashMap;
3 | import java.util.PriorityQueue;
4 | import java.util.Comparator;
5 |
6 | public class AStarPathFinder extends PathFinder {
7 | public static boolean debug = false;
8 | private PriorityQueue open; // Nodes to be done, by priority.
9 | private HashMap lookup; // For finding each tile's node.
10 | private Tile ntile = new Tile(); // For going through neighbors.
11 | private Tile path[]; // The resulting path.
12 | private int dir; // -1 or 1
13 | private int stop; // Index in path to stop at.
14 | private int nextIndex; // Index of next tile in 'path' to return.
15 | private static NodeComparator cmp;
16 | public AStarPathFinder() {
17 | cmp = new NodeComparator();
18 | open = new PriorityQueue(300, cmp);
19 | lookup = new HashMap(300);
20 | }
21 | public boolean followingSmartPath() {
22 | return true;
23 | }
24 | public boolean NewPath(Tile s, Tile d, Client client) {
25 | // Store start, destination.
26 | if (src == null)
27 | src = new Tile();
28 | if (dest == null)
29 | dest = new Tile();
30 | src.set(s);
31 | dest.set(d);
32 | path = null; // Clear out old path, if there.
33 | nextIndex = 0;
34 | dir = 1;
35 | stop = 0;
36 | open.clear();
37 | lookup.clear();
38 | if (!findPath(s, d, client))
39 | return false;
40 | stop = path.length;
41 | return true;
42 | }
43 | public boolean getNextStep(Tile n) {
44 | if (nextIndex == stop) {
45 | // done = true;
46 | return false;
47 | }
48 | n.set(path[nextIndex]);
49 | nextIndex += dir;
50 | //done = (nextIndex == stop);
51 | return true;
52 | }
53 | public int getNumSteps() {
54 | return (stop - nextIndex)*dir;
55 | }
56 | public boolean isDone() {
57 | return nextIndex == stop;
58 | }
59 | public boolean setBackwards() {
60 | dir = -1;
61 | stop = -1;
62 | nextIndex = path.length - 1;
63 | return true;
64 | }
65 | private void add(SearchNode nd) {
66 | open.offer(nd);
67 | lookup.put(nd.tile, nd);
68 | }
69 | private SearchNode find(Tile t) {
70 | return lookup.get(t);
71 | }
72 | private boolean findPath(Tile start, Tile goal, PathFinder.Client client) {
73 | int maxCost = client.estimateCost(start, goal);
74 | // Create start node.
75 | add(new SearchNode(start, 0, maxCost, null));
76 | // Figure when to give up.
77 | maxCost = client.getMaxCost(maxCost);
78 | SearchNode node; // Try 'best' node each iteration.
79 | while ((node = open.poll()) != null) {
80 | Tile curtile = node.tile;
81 | //System.out.printf("AStar: curtile is %1$d, %2$d, goal is %3$d, %4$d\n",
82 | // curtile.tx, curtile.ty, goal.tx, goal.ty);
83 | //System.out.println("Curtile totalCost = " + node.totalCost);
84 | if (client.atGoal(curtile, goal)) {
85 | // Success.
86 | path = node.createPath();
87 | if (debug)
88 | System.out.printf("AStar: SUCCESS. Path.length = %1$d\n", path.length);
89 | return true;
90 | }
91 | // Go through neighbors.
92 | for (int dir = 0; dir < 8; ++dir) {
93 |
94 | curtile.getNeighbor(ntile, dir);
95 |
96 | // Get cost to next tile.
97 | int stepCost = client.getStepCost(curtile, ntile);
98 | //System.out.printf("AStar: neighbor is %1$d, %2$d, stepCost = %3$d\n",
99 | // ntile.tx, ntile.ty, stepCost);
100 | // Blocked?
101 | if (stepCost == -1)
102 | continue;
103 | // Get cost from start to ntile.
104 | int newCost = node.startCost + stepCost;
105 | // See if next tile already seen.
106 | SearchNode next = find(ntile);
107 | //if (next != null)
108 | // System.out.printf("next.startCost = %1$d, newCost = %2$d",
109 | // next.startCost, newCost);
110 | // Already there, and cheaper?
111 | if (next != null && next.startCost <= newCost)
112 | continue;
113 | int newGoalCost = client.estimateCost(ntile, goal);
114 | // System.out.println("newGoalCost = " + newGoalCost);
115 | // Skip nodes too far away.
116 | if (newCost + newGoalCost >= maxCost)
117 | continue;
118 | if (next == null) { // Create if necessary.
119 | next = new SearchNode(ntile, newCost,
120 | newGoalCost, node);
121 | add(next);
122 | } else { // It's going to move.
123 | open.remove(next);
124 | next.set(newCost, newGoalCost, node);
125 | open.offer(next);
126 | }
127 | }
128 | }
129 | return false; // Failed if here.
130 | }
131 | /*
132 | * Local classes.
133 | */
134 | static class NodeComparator implements Comparator {
135 | public int compare(SearchNode n1, SearchNode n2) {
136 | return n1.totalCost - n2.totalCost;
137 | }
138 | }
139 | static class SearchNode {
140 | Tile tile; // The coords (x, y, z) in tiles.
141 | int startCost; // Actual cost from start.
142 | int goalCost; // Estimated cost to goal.
143 | int totalCost; // Sum of the two above.
144 | boolean open; // In priority queue.
145 | SearchNode parent; // Prev. in path.
146 | SearchNode() {
147 | }
148 | SearchNode(Tile t, int scost, int gcost, SearchNode p) {
149 | tile = new Tile(t.tx, t.ty, t.tz);
150 | startCost = scost; goalCost = gcost;
151 | totalCost = scost + gcost;
152 | parent = p;
153 | }
154 | void set(int scost, int gcost, SearchNode p) {
155 | startCost = scost;
156 | goalCost = gcost;
157 | totalCost = gcost + scost;
158 | parent = p;
159 | }
160 | @Override
161 | public int hashCode() {
162 | return ((tile.tz << 24) + (tile.ty << 12) + tile.tx);
163 | }
164 | @Override
165 | public boolean equals(Object o2) {
166 | SearchNode nd2 = (SearchNode)o2;
167 | return tile.equals(nd2.tile);
168 | }
169 | // Create path back to start.
170 | Tile[] createPath() {
171 | int cnt = 1; // This.
172 | // Count back to start.
173 | SearchNode each = this;
174 | while ((each = each.parent) != null)
175 | cnt++;
176 | int pathlen = cnt - 1; // Don't want starting tile.
177 | Tile path[] = new Tile[pathlen];
178 | each = this;
179 | for (int i = pathlen - 1; i >= 0; i--) {
180 | path[i] = each.tile;
181 | each = each.parent;
182 | }
183 | return path;
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/src/com/exult/android/ActorGump.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | import com.exult.android.Gump.Container;
4 |
5 | public class ActorGump extends Container {
6 | public static final int TWO_HANDED_BROWN_SHAPE = 48;
7 | public static final int TWO_HANDED_BROWN_FRAME = 0;
8 | public static final int TWO_FINGER_BROWN_SHAPE = 48;
9 | public static final int TWO_FINGER_BROWN_FRAME = 1;
10 | protected static short coords[] = { // Coords. of where to draw things,
11 | // indexed by spot # (0-11).
12 | 114, 10, /* head */ 115, 24, /* back */
13 | 115, 37, /* belt */ 115, 55, /* lhand */
14 | 115, 71, /* lfinger */ 114, 85, /* legs */
15 | 76, 98, /* feet */ 35, 70, /* rfinger */
16 | 37, 56, /* rhand */ 37, 37, /* torso */
17 | 37, 24, /* neck */ 37, 11}; /* ammo */
18 | protected static int spotx(int i) { return coords[2*i]; }
19 | protected static int spoty(int i) { return coords[2*i + 1]; }
20 |
21 | // Locations:
22 | protected static short diskx = 124, disky = 115;// 'diskette' button.
23 | protected static short heartx = 124, hearty = 132; // 'stats' button.
24 | protected static short combatx = 52, combaty = 100; // Combat button.
25 | protected static short halox = 47, haloy = 110; // "Protected" halo.
26 | protected static short cmodex = 48, cmodey = 132; // Combat mode.
27 | // Find index of closest spot, or -1 if unsuccessful.
28 | protected int findClosest(int mx, int my, boolean only_empty) {
29 | mx -= x; my -= y; // Get point rel. to us.
30 | long closest_squared = 1000000; // Best distance squared.
31 | int closest = -1; // Best index.
32 | for (int i = 0; i < coords.length/2; i++) {
33 | int dx = mx - spotx(i), dy = my - spoty(i);
34 | long dsquared = dx*dx + dy*dy;
35 | // Better than prev.?
36 | if (dsquared < closest_squared && (!only_empty ||
37 | container.getReadied(i) == null)) {
38 | closest_squared = dsquared;
39 | closest = i;
40 | }
41 | }
42 | return closest;
43 | }
44 | protected void setToSpot(GameObject obj, int index) {
45 | ShapeFrame shape = obj.getShape();
46 | if (shape == null)
47 | return; // Not much we can do.
48 | int w = shape.getWidth(), h = shape.getHeight();
49 | // Set object's position.
50 | obj.setShapePos(
51 | spotx(index) + shape.getXLeft() - w/2 - objectArea.x,
52 | spoty(index) + shape.getYAbove() - h/2 - objectArea.y);
53 | // Shift if necessary.
54 | int x0 = obj.getTx() - shape.getXLeft(),
55 | y0 = obj.getTy() - shape.getYAbove();
56 | int newcx = obj.getTx(), newcy = obj.getTy();
57 | if (x0 < 0)
58 | newcx -= x0;
59 | if (y0 < 0)
60 | newcy -= y0;
61 | int x1 = x0 + w, y1 = y0 + h;
62 | if (x1 > objectArea.w)
63 | newcx -= x1 - objectArea.w;
64 | if (y1 > objectArea.h)
65 | newcy -= y1 - objectArea.h;
66 | obj.setShapePos(newcx, newcy);
67 | }
68 | ActorGump(Actor npc, int initx, int inity, int shnum) {
69 | super(npc, initx, inity, shnum);
70 | setObjectArea(26, 0, 104, 132, 6, 136);
71 | addElem(new GumpWidget.HeartButton(this, heartx, hearty));
72 | if (npc.getNpcNum() == 0) {
73 | addElem(new GumpWidget.DiskButton(this, diskx, disky));
74 | addElem(new GumpWidget.CombatButton(this, combatx, combaty));
75 | }
76 | addElem(new GumpWidget.HaloButton(this, halox, haloy, npc));
77 | addElem(new GumpWidget.CombatModeButton(this, cmodex, cmodey, npc));
78 | for (int i = 0; i < coords.length/2; i++) {
79 | // Set object coords.
80 | GameObject obj = container.getReadied(i);
81 | if (obj != null)
82 | setToSpot(obj, i);
83 | }
84 | }
85 | /*
86 | * Add an object.
87 | *
88 | * Output: 0 if cannot add it.
89 | */
90 | public boolean add
91 | (
92 | GameObject obj,
93 | int mx, int my, // Screen location of mouse.
94 | int sx, int sy, // Screen location of obj's hotspot.
95 | boolean dont_check, // Skip volume check.
96 | boolean combine // True to try to combine obj. MAY
97 | // cause obj to be deleted.
98 | ) {
99 | GameObject cont = findObject(mx, my);
100 |
101 | if (cont != null && cont.add(obj, false, combine, false))
102 | return true;
103 | int index = findClosest(mx, my, true);
104 | if (index != -1 && container.addReadied(obj, index, false, false, false))
105 | return true;
106 |
107 | if (container.add(obj, dont_check, combine, false))
108 | return true;
109 |
110 | return false;
111 | }
112 | public void paint() {
113 | // Watch for any newly added objs.
114 | for (int i = 0; i < coords.length/2; i++) {
115 | // Set object coords.
116 | GameObject obj = container.getReadied(i);
117 | if (obj != null)
118 | setToSpot(obj, i);
119 | }
120 | super.paint(); // Paint gump & objects.
121 |
122 | // Paint over blue lines for 2 handed
123 | Actor actor = container.asActor();
124 | if (actor != null) {
125 | if (actor.isTwoFingered()) {
126 | int sx = x + 36, // Note this is the right finger slot shifted slightly
127 | sy = y + 70;
128 | ShapeFrame s = ShapeFiles.GUMPS_VGA.getShape(TWO_FINGER_BROWN_SHAPE, TWO_FINGER_BROWN_FRAME);
129 | s.paint(win, sx, sy);
130 | }
131 | if (actor.isTwoHanded()) {
132 | int sx = x + 36, // Note this is the right hand slot shifted slightly
133 | sy = y + 55;
134 | ShapeFrame s = ShapeFiles.GUMPS_VGA.getShape(TWO_HANDED_BROWN_SHAPE, TWO_HANDED_BROWN_FRAME);
135 | s.paint(win, sx, sy);
136 | }
137 | }
138 | // Show weight.
139 | int max_weight = container.getMaxWeight();
140 | int weight = container.getWeight()/10;
141 | String text = weight + "/" + max_weight;
142 | int twidth = fonts.getTextWidth(2, text);
143 | int boxw = 102;
144 | fonts.paintText(2, text, x + 28 + (boxw - twidth)/2, y + 120);
145 | }
146 | public ContainerGameObject findActor(int mx, int my) {
147 | return container;
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/com/exult/android/AudioSample.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.InputStream;
3 | import java.io.ByteArrayInputStream;
4 | import java.io.IOException;
5 | /*
6 | Copyright (C) 2005 The Pentagram team
7 | Copyright (C) 2010 The Exult team
8 |
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; if not, write to the Free Software
21 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 | */
23 |
24 | //CURRENTLY not finished and not used.
25 | public class AudioSample {
26 | protected int sampleRate;
27 | protected int bits;
28 | protected boolean stereo;
29 | protected int frameSize;
30 | protected int decompressorSize;
31 | protected int length;
32 |
33 | protected int bufferSize;
34 | protected byte buffer[];
35 | protected int refcount;
36 |
37 | public AudioSample(byte buf[], int sz) {
38 | this.buffer = buf;
39 | this.bufferSize = sz;
40 | refcount = 1;
41 | }
42 | public static AudioSample createAudioSample(byte data[], int size) {
43 | InputStream in = new ByteArrayInputStream(data, 0, size);
44 | if (VocAudioSample.isThis(in))
45 | return new VocAudioSample(data,size);
46 | //++MORE
47 | else
48 | return null;
49 | }
50 |
51 | static class VocAudioSample extends AudioSample {
52 | public VocAudioSample(byte buf[], int sz) {
53 | super(buf, sz);
54 | }
55 | public static boolean isThis(InputStream in) {
56 | byte buf[] = new byte[19];
57 | try {
58 | in.read(buf);
59 | if (new String(buf).equals("Creative Voice File"))
60 | return true;
61 | } catch (IOException e) {
62 | return false;
63 | }
64 | return false;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/com/exult/android/Block.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | /*
3 | * A 3-dim. block.
4 | */
5 | public final class Block {
6 | public int x, y, z; // Position.
7 | public int w, d, h; // Dimensions.
8 | public Block(int xin, int yin, int zin, int win, int din, int hin) {
9 | x = xin; y = yin; z = zin;
10 | w = win; d = din; h = hin;
11 | }
12 | public void set(int xin, int yin, int zin, int win, int din, int hin) {
13 | x = xin; y = yin; z = zin;
14 | w = win; d = din; h = hin;
15 | }
16 | public Block() { } // An uninitialized one.
17 | // Is this point in it?
18 | public boolean hasPoint(int px, int py, int pz) {
19 | return (px >= x && px < x + w && py >= y && py < y + d &&
20 | pz >= z && pz < z + h);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/com/exult/android/Cheat.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | import android.view.KeyEvent;
4 |
5 | public final class Cheat extends GameSingletons {
6 | private boolean hackMover;
7 | private boolean godMode;
8 | private boolean wizardMode;
9 | private boolean infravision;
10 | private boolean pickpocket;
11 |
12 | public boolean inHackMover() {
13 | return hackMover;
14 | }
15 | public void toggleHackMover() {
16 | hackMover = !hackMover;
17 | ExultActivity.showToast(hackMover?"HackMover Mode":"Ending HackMover");
18 | }
19 | public boolean inGodMode() {
20 | return godMode;
21 | }
22 | public void toggleGodMode() {
23 | godMode = !godMode;
24 | ExultActivity.showToast(godMode?"GodMode Mode":"Ending GodMode");
25 | }
26 | public boolean inWizardMode() {
27 | return wizardMode;
28 | }
29 | public void toggleWizardMode() {
30 | wizardMode = !wizardMode;
31 | ExultActivity.showToast(wizardMode?"WizardMode Mode":"Ending WizardMode");
32 | }
33 | public boolean inPickpocket() {
34 | return pickpocket;
35 | }
36 | public void togglePickpocket() {
37 | pickpocket = !pickpocket;
38 | ExultActivity.showToast(pickpocket?"Pickpocket Mode":"Ending Pickpocket");
39 | }
40 | public boolean inInfravision() {
41 | return infravision;
42 | }
43 | public void toggleInfravision() {
44 | infravision = !infravision;
45 | ExultActivity.showToast(infravision?"Infravision Mode":"Ending Infravision");
46 | clock.setPalette();
47 | }
48 | public void mapTeleport() {
49 | ShapeFrame map;
50 | if (EUtil.U7exists(EFile.PATCH_MINIMAPS) != null) {
51 | VgaFile mini = new VgaFile(EFile.PATCH_MINIMAPS, null);
52 | if ((map = mini.getShape(0, gwin.getMap().getNum())) == null)
53 | map = mini.getShape(0, 0);
54 | } else {
55 | int shnum = game.getShape("sprites/cheatmap");
56 | map = ShapeFiles.GAME_FLX.getShape(shnum, 1);
57 | }
58 | CheatMapGump g = new CheatMapGump(map);
59 | g.track(mouse.getShortArrow(EConst.northeast));
60 | }
61 | private static class CheatMapGump extends Gump.Modal {
62 | Tile t = new Tile(); // For Avatar's pos.
63 | CheatMapGump(ShapeFrame map) {
64 | super(map); // Manage everything here.
65 | }
66 | // Handle events for ClickTracker
67 | @Override
68 | public void onUp(int mx, int my) {
69 | mx -= x - shape.getXLeft() + border;
70 | my -= y - shape.getYAbove() + border;
71 |
72 | t.tx = (short)(((mx + 0.5)*worldsize) / (shape.getWidth() - 2*border));
73 | t.ty = (short)(((my + 0.5)*worldsize) / (shape.getHeight() - 2*border));
74 | System.out.printf("mouseUp at %1$d, %2$d, tx = %3$d, ty = %4$d\n", mx, my,
75 | t.tx, t.ty);
76 | // World-wrapping.
77 | t.tx = (short)((t.tx + EConst.c_num_tiles)%EConst.c_num_tiles);
78 | t.ty = (short)((t.ty + EConst.c_num_tiles)%EConst.c_num_tiles);
79 | System.out.println("Teleporting to " + t.tx + "," + t.ty + "!");
80 | t.tz = 0;
81 | ExultActivity.showToast("Teleport!!!");
82 | gwin.teleportParty(t, false, -1);
83 | close();
84 | }
85 | @Override
86 | public void keyDown(int chr) { // Character typed.
87 | if (chr == KeyEvent.KEYCODE_BACK)
88 | close();
89 | }
90 | private static final int border=2; // For showing map.
91 | private static final int worldsize = EConst.c_tiles_per_chunk * EConst.c_num_chunks;
92 | public void paint() {
93 | super.paint();
94 | // mark current location
95 | int xx, yy;
96 | gwin.getMainActor().getTile(t);
97 | xx = ((t.tx * (shape.getWidth() - border*2)) / worldsize);
98 | yy = ((t.ty * (shape.getHeight() - border*2)) / worldsize);
99 |
100 | xx += x - shape.getXLeft() + border;
101 | yy += y - shape.getYAbove() + border;
102 | gwin.getWin().fill8((byte)255, 1, 5, xx, yy - 2);
103 | gwin.getWin().fill8((byte)255, 5, 1, xx - 2, yy);
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/com/exult/android/ChunkTerrain.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | import java.lang.ref.SoftReference;
4 |
5 | /*
6 | * The flat landscape, 16x16 tiles:
7 | */
8 | public class ChunkTerrain {
9 | private int shapes[]; // The flat (non-RLE's) are
10 | // rendered here, the others are
11 | // turned into Game_objects in the
12 | // chunks that point to us. Each entry
13 | // is of form 0x00ssssff, s=shape, f=frame.
14 | private int numClients; // # of Chunk's that point to us.
15 | private SoftReference renderedFlats; // Flats rendered for entire chunk.
16 | // Kept only for nearby chunks.
17 |
18 | // Create rendered_flats.
19 | private final void paintTile(int tilex, int tiley) {
20 | ShapeFrame shape = getShape(tilex, tiley);
21 | if (shape != null && !shape.isRle()) { // Only do flat tiles.
22 | byte src[] = shape.getData();
23 | byte flats[] = renderedFlats.get();
24 | int from = 0, to = tilex*EConst.c_tilesize +
25 | tiley*EConst.c_tilesize*EConst.c_chunksize;
26 | for (int y = 0; y < EConst.c_tilesize; ++y) {
27 | System.arraycopy(src, from, flats, to, EConst.c_tilesize);
28 | from += EConst.c_tilesize;
29 | to += EConst.c_chunksize;
30 | }
31 | }
32 | }
33 | private byte[] renderFlats() {
34 | byte flats[] = new byte[EConst.c_chunksize*EConst.c_chunksize];
35 | assert(renderedFlats == null || renderedFlats.get() == null);
36 | renderedFlats = new SoftReference(flats);
37 | // Go through array of tiles.
38 | for (int tiley = 0; tiley < EConst.c_tiles_per_chunk; tiley++)
39 | for (int tilex = 0; tilex < EConst.c_tiles_per_chunk; tilex++)
40 | paintTile(tilex, tiley);
41 | return flats;
42 | }
43 | // Create from 16x16x2 data:
44 | public ChunkTerrain(byte []data, boolean v2_chunks) {
45 | numClients = 0;
46 | renderedFlats = null;
47 | shapes = new int[16*16];
48 | int ind = 0;
49 | for (int tiley = 0; tiley < EConst.c_tiles_per_chunk; tiley++)
50 | for (int tilex = 0; tilex < EConst.c_tiles_per_chunk; tilex++) {
51 | int shnum, frnum;
52 | if (v2_chunks) {
53 | shnum = data[ind + 0]&0xff + 256*(data[ind + 1]&0xff);
54 | frnum = data[ind + 2]&0xff;
55 | ind += 3;
56 | } else {
57 | int hi = data[ind + 1]&3;
58 | shnum = (int)(data[ind + 0]&0xff) + 256*hi;
59 | frnum = (data[ind + 1]>>2)&0x1f;
60 | ind += 2;
61 | }
62 | shapes[16*tiley + tilex] = ((shnum<<8)&0xffff00) | (frnum&0xff);
63 | }
64 | }
65 | public final void addClient()
66 | { numClients++; }
67 | public final void removeClient()
68 | { numClients--; }
69 | // Get tile's shape ID.
70 | public final void getFlat(ShapeID retId, int tilex, int tiley) {
71 | int n = shapes[16*tiley + tilex];
72 | retId.set((n>>8)&0xffff, n&0xff, ShapeFiles.SHAPES_VGA);
73 | }
74 | public final int getShapeNum(int tilex, int tiley) {
75 | int n = shapes[16*tiley + tilex];
76 | return (n>>8)&0xffff;
77 | }
78 | public final int getFrameNum(int tilex, int tiley) {
79 | int n = shapes[16*tiley + tilex];
80 | return n&0xff;
81 | }
82 | public final ShapeFrame getShape(int tilex, int tiley) {
83 | int n = shapes[16*tiley + tilex];
84 | return ShapeFiles.SHAPES_VGA.getFile().getShape((n>>8)&0xffff, n&0xff);
85 | }
86 | public final byte[] getRenderedFlats() {
87 | if (renderedFlats == null)
88 | return renderFlats();
89 | else {
90 | byte flats[] = renderedFlats.get();
91 | return flats != null ? flats : renderFlats();
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/com/exult/android/DataSource.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | import java.io.IOException;
4 | import java.io.RandomAccessFile;
5 |
6 | /*
7 | * This class acts like a RandomAccessFile but can represent a byte array.
8 | */
9 | public abstract class DataSource {
10 | public abstract int read() throws IOException ;
11 | public abstract int read(byte buf[]) throws IOException ;
12 | public abstract void seek(long pos) throws IOException ;
13 | public abstract long length() throws IOException;
14 | public abstract long getFilePointer() throws IOException;
15 | public void close() throws IOException { }
16 | // Create from file.
17 | public static DataSource create(String fname) {
18 | try {
19 | RandomAccessFile file = EUtil.U7open(fname, true);
20 | return file == null ? null : new DataSource.File(file);
21 | } catch (IOException e) {
22 | return null;
23 | }
24 | }
25 | // Create from resource within flex file, or whole file if rsc == -1.
26 | public static DataSource create(String fname, int rsc) {
27 | if (rsc == -1)
28 | return create(fname);
29 |
30 | byte buf[] = GameSingletons.fman.retrieve(fname, rsc);
31 | if (buf != null && buf.length != 0)
32 | return new DataSource.Buffer(buf);
33 | else
34 | return null;
35 | }
36 | public static class File extends DataSource {
37 | private RandomAccessFile file;
38 |
39 | public File(RandomAccessFile f) {
40 | file = f;
41 | }
42 | public int read() throws IOException {
43 | return file.read();
44 | }
45 | public int read(byte buf[]) throws IOException {
46 | return file.read(buf);
47 | }
48 | public void seek(long pos) throws IOException {
49 | file.seek(pos);
50 | }
51 | public long length() throws IOException {
52 | return file.length();
53 | }
54 | public long getFilePointer() throws IOException {
55 | return file.getFilePointer();
56 | }
57 | public void close() throws IOException {
58 | file.close();
59 | }
60 | }
61 | public static class Buffer extends DataSource {
62 | private byte data[];
63 | private int pos;
64 |
65 | public Buffer(byte b[]) {
66 | data = b;
67 | pos = 0;
68 | }
69 | public int read() throws IOException {
70 | if (pos >= data.length)
71 | return -1;
72 | return data[pos++];
73 | }
74 | public int read(byte buf[]) throws IOException {
75 | int max = data.length - pos;
76 | int cnt = buf.length < max ? buf.length : max;
77 | System.arraycopy(data, pos, buf, 0, cnt);
78 | pos += cnt;
79 | return cnt;
80 | }
81 | public void seek(long pos) throws IOException {
82 | this.pos = (int)pos;
83 | }
84 | public long length() throws IOException {
85 | return data.length;
86 | }
87 | public long getFilePointer() throws IOException {
88 | return pos;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/com/exult/android/EConst.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class EConst {
4 | public static final int c_game_w = 320, c_game_h = 200; // Standard game area.
5 | public static final int c_basetilesize = 8; // A tile (shape) is 8x8 pixels.
6 | public static final int c_tilesize = 8; // A tile (shape) is 8x8 pixels.
7 | public static final int c_num_tile_bytes = c_tilesize * c_tilesize; // Total pixels per tile.
8 | public static final int c_screen_tile_size = c_game_w/c_basetilesize; // Number of tiles in a 'screen'.
9 | public static final int c_tiles_per_chunk = 16; // A chunk is 16x16 tiles.
10 | public static final int c_chunksize = 16 * 8; // A chunk has 16 8x8 shapes.
11 | public static final int c_num_schunks = 12;
12 | public static final int c_num_chunks = 12*16; // Total # of chunks in each dir.
13 | public static final int c_chunks_per_schunk = 16; // # chunks in each superchunk.
14 | public static final int c_tiles_per_schunk = 16*16; // # tiles in each superchunk.
15 | // Total # tiles in each dir.:
16 | public static final int c_num_tiles = c_tiles_per_chunk*c_num_chunks;
17 |
18 | public static final int c_fade_in_time = 30; // Time for fade in
19 | public static final int c_fade_out_time = 30; // Time for fade out
20 | public static final int c_std_delay = 200; // Standard animation delay. May want to
21 | // make this settable!
22 |
23 | public static final int c_any_shapenum = -359;
24 | public static final int c_any_qual = -359;
25 | public static final int c_any_framenum = -359;
26 | public static final int c_any_quantity = -359;
27 |
28 | // Maximum number of shapes:
29 | public static final int c_max_shapes = 2048;
30 | //UNUSED public static final int c_occsize = c_max_shapes/8 + (((c_max_shapes%8) !=0) ? 1 : 0);
31 |
32 | public static final int c_first_obj_shape = 0x96; // 0-0x95 are 8x8 flat shapes.
33 | // Directions:
34 | public static final int
35 | north = 0,
36 | northeast = 1,
37 | east = 2,
38 | southeast = 3,
39 | south = 4,
40 | southwest = 5,
41 | west = 6,
42 | northwest = 7;
43 | public static final int
44 | MOVE_NODROP = (1<<3),
45 | MOVE_FLY = (1<<4),
46 | MOVE_LEVITATE = (MOVE_FLY|MOVE_NODROP),
47 | MOVE_WALK = (1<<5),
48 | MOVE_SWIM = (1<<6),
49 | MOVE_ALL_TERRAIN = ((1<<5)|(1<<6)),
50 | MOVE_ETHEREAL = (1<<7),
51 | MOVE_ALL = (MOVE_FLY|MOVE_WALK|MOVE_SWIM|MOVE_ETHEREAL),
52 | MOVE_MAPEDIT = (1<<8);
53 | // Maximum number of global flags:
54 | public static final int c_last_gflag = 2047;
55 |
56 | public static final int INCR_CHUNK(int x) {
57 | return ((x) + 1)%c_num_chunks;
58 | }
59 | public static final int DECR_CHUNK(int x) {
60 | return ((x) - 1 + c_num_chunks)%c_num_chunks;
61 | }
62 | public static final int INCR_TILE(int x) {
63 | return ((x) + 1)%c_num_tiles;
64 | }
65 | public static final int DECR_TILE(int x) {
66 | return (x - 1 + c_num_tiles)%c_num_tiles;
67 | }
68 | public static final int DECR_TILE(int x, int amt) {
69 | return (x - amt + c_num_tiles)%c_num_tiles;
70 | }
71 | // Return x - y with wrapping.
72 | public static final int SUB_TILE(int x, int y) {
73 | int delta = x - y;
74 | return delta < -c_num_tiles/2 ? delta + c_num_tiles :
75 | delta >= c_num_tiles/2 ? delta - c_num_tiles : delta;
76 | }
77 | // Game types.
78 | public static final int // enum Exult_Game
79 | NONE = 0,
80 | BLACK_GATE = 1,
81 | SERPENT_ISLE = 2,
82 | EXULT_DEVEL_GAME = 3, // One that we develop.
83 | EXULT_MENU_GAME = 4; // Game type for the exult menu
84 | }
85 |
--------------------------------------------------------------------------------
/src/com/exult/android/EFileManager.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.util.TreeMap;
3 |
4 | public class EFileManager {
5 | static EFileManager instance;
6 | private TreeMap fileList;
7 | private EFileManager() {
8 | fileList = new TreeMap();
9 | }
10 | public static EFileManager instanceOf() {
11 | if (instance == null)
12 | instance = new EFileManager();
13 | return instance;
14 | }
15 | public EFile getFileObject(String nm) {
16 | if (nm == null)
17 | return null;
18 | EFile file = fileList.get(nm);
19 | if (file != null)
20 | return file;
21 | String fname = EUtil.U7exists(nm);
22 | if (fname == null)
23 | return null;
24 | if (EUtil.isFlex(fname))
25 | file = new FlexFile(fname, nm);
26 | /* +++++FINISH
27 | else if (EUtil.isIff(s.name))
28 | uf = new IFFFile(s.name);
29 | else if (Table::is_table(s.name))
30 | uf = new TableFile(s.name);
31 | */
32 | else
33 | file = new EFile(fname, nm); // Flat file.
34 | // Failed
35 | if (file == null) {
36 | return null;
37 | }
38 | fileList.put(nm, file);
39 | return file;
40 | }
41 | /*
42 | * Try files in reverse order, looking for given objnum in file.
43 | */
44 | public EFile getFileObject(String nm1, String nm2) {
45 | EFile file = getFileObject(nm2);
46 | if (file == null)
47 | file = getFileObject(nm1);
48 | return file;
49 | }
50 | public void remove(EFile file) {
51 | String nm = file.getIdentifier();
52 | fileList.remove(nm);
53 | }
54 | /*
55 | * Retrieve given obj with file.
56 | */
57 | public byte[] retrieve(String nm, int objnum) {
58 | EFile file = getFileObject(nm);
59 | if (file != null) {
60 | byte res[] = file.retrieve(objnum);
61 | if (res != null)
62 | return res;
63 | }
64 | return null;
65 | }
66 | /*
67 | * Try files in reverse order, looking for given objnum in file.
68 | */
69 | public byte[] retrieve(String nm1, String nm2, int objnum) {
70 | byte res[] = retrieve(nm2, objnum);
71 | if (res == null)
72 | res = retrieve(nm1, objnum);
73 | return res;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/com/exult/android/FlexFile.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.IOException;
3 |
4 | public class FlexFile extends EFile {
5 | public static final int EXULT_FLEX_MAGIC2 = 0x0000cc00;
6 | public static final int orig = 0; // Original U7 version.
7 | public static final int exultV2 = 1;// Exult extension for IFIX files.
8 | byte title[]; // 80 bytes
9 | int magic1;
10 | int count;
11 | int magic2;
12 | int padding[]; // 9 words
13 | static class Reference {
14 | int offset;
15 | int size;
16 | byte buf[];
17 | Reference() {
18 | offset = 0; size = 0;
19 | buf = null;
20 | }
21 | }
22 | Reference objects[];
23 | public FlexFile(String fname, String id) {
24 | super(fname, id);
25 | try {
26 | title = new byte[80];
27 | file.seek(0);
28 | file.read(title);
29 | magic1 = EUtil.Read4(file);
30 | count = EUtil.Read4(file);
31 | magic2 = EUtil.Read4(file);
32 | if (magic1!=0xffff1a00L)
33 | // Not a flex file.
34 | ; // Throw exception?
35 | padding = new int[9];
36 | for (int i=0; i<9; i++)
37 | padding[i] = EUtil.Read4(file);
38 | file.seek(128); // Should already be there.
39 | objects = new Reference[count];
40 | for (int c = 0; c < count; c++) {
41 | Reference f = new Reference();
42 | f.offset = EUtil.Read4(file);
43 | f.size = EUtil.Read4(file);
44 | objects[c] = f;
45 | }
46 | } catch (IOException e) {
47 | }
48 | }
49 | public int getVers() {
50 | return (magic2&~0xff) == EXULT_FLEX_MAGIC2 ? exultV2 : orig;
51 | }
52 | public int numberOfObjects() {
53 | return objects.length;
54 | }
55 | public void close() {
56 | super.close();
57 | int cnt = objects.length;
58 | for (int i = 0; i < cnt; ++i)
59 | objects[i] = null;
60 | }
61 | public byte [] retrieve(int objnum) {
62 | if (objnum < 0 || objnum >= objects.length)
63 | return null;
64 | Reference ref = objects[objnum];
65 | if (ref.buf == null)
66 | try {
67 | file.seek(ref.offset);
68 | ref.buf = new byte[ref.size];
69 | file.read(ref.buf);
70 | } catch (IOException e) {
71 | return null;
72 | }
73 | return ref.buf;
74 | }
75 | public String getArchiveType() {
76 | return "FLEX";
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/com/exult/android/GameClock.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class GameClock extends TimeSensitive.Timer {
4 | public static final int ticksPerMinute = 25; // Ticks per game minute.
5 | private int hour, minute; // Time (0-23, 0-59).
6 | private int day; // Keep track of days played.
7 | private int lightSourceLevel; // Last set light source level.
8 | private int oldLightLevel; // Last set light source level.
9 | private boolean oldSpecialLight; // Last set light source level.
10 | private boolean oldInfravision; // If infravision was on last time.
11 | private boolean oldInvisible; // If invisibility was on last time.
12 | private int dungeon; // Last set 'in_dungeon' value.
13 | private int overcast; // >0 if day is overcast (e.g., from a storm).
14 | private boolean wasOvercast;
15 | private int fog; // >0 if there is fog.
16 | private boolean wasFoggy;
17 | private Palette.Transition transition; // For smooth palette transitions.
18 | private int timeRate;
19 | private static int getTimePalette(int hour, boolean dungeon) {
20 | if (dungeon || hour < 6)
21 | return Palette.PALETTE_NIGHT;
22 | else if (hour == 6)
23 | return Palette.PALETTE_DAWN;
24 | else if (hour == 7)
25 | return Palette.PALETTE_DAY;
26 | else if (hour < 20)
27 | return Palette.PALETTE_DAY;
28 | else if (hour == 20)
29 | return Palette.PALETTE_DUSK;
30 | else
31 | return Palette.PALETTE_NIGHT;
32 | }
33 | /* UNUSED
34 | private static boolean isLightPalette(int pal) {
35 | return (pal == Palette.PALETTE_SINGLE_LIGHT || pal == Palette.PALETTE_MANY_LIGHTS);
36 | }*/
37 | private static boolean isDarkPalette(int pal) {
38 | return (pal == Palette.PALETTE_DUSK || pal == Palette.PALETTE_NIGHT);
39 | }
40 | /* UNUSED
41 | private static boolean isWeatherPalette(int pal) {
42 | return (pal == Palette.PALETTE_OVERCAST || pal == Palette.PALETTE_FOG);
43 | }*/
44 | private static boolean isDayPalette(int pal) {
45 | return (pal == Palette.PALETTE_DAWN || pal == Palette.PALETTE_DAY);
46 | }
47 | private static int getFinalPalette(int pal, boolean cloudy, boolean foggy,
48 | int light, boolean special) {
49 | if ((light != 0 || special) && isDarkPalette(pal)) {
50 | int light_palette = Palette.PALETTE_SINGLE_LIGHT;
51 | // Gump mode, or light spell?
52 | if (special || (light > 1))
53 | light_palette = Palette.PALETTE_MANY_LIGHTS;
54 | return light_palette;
55 | } else if (isDayPalette(pal)) {
56 | if (foggy)
57 | return Palette.PALETTE_FOG;
58 | else if (cloudy)
59 | return Palette.PALETTE_OVERCAST;
60 | }
61 | return pal;
62 | }
63 |
64 | public GameClock() {
65 | hour = 6;
66 | dungeon = 255;
67 | timeRate = 1;
68 | }
69 | public int getHour()
70 | { return hour; }
71 | public void setHour(int h)
72 | { hour = h; }
73 | public int getMinute()
74 | { return minute; }
75 | public void setMinute(int m)
76 | { minute = m; }
77 | public int getDay()
78 | { return day; }
79 | public void setDay(int d)
80 | { day = d; }
81 | public int getTotalHours() // Get total # hours.
82 | { return day*24 + hour; }
83 | public int getTotalMinutes()
84 | { return getTotalHours()*60 + minute; }
85 | public void setLightSource(int lev, int dun) {
86 | if (lev != lightSourceLevel || dun != dungeon)
87 | setLightSourceLevel(lev);
88 | }
89 | private void setLightSourceLevel(int lev) {
90 | lightSourceLevel = lev;
91 | setPalette();
92 | }
93 | public void setPalette() {
94 | Actor main_actor = gwin.getMainActor();
95 | boolean invis = main_actor != null && main_actor.getFlag(GameObject.invisible);
96 | if (invis && !oldInvisible) {
97 | transition = null;
98 | gwin.getPal().set(Palette.PALETTE_INVISIBLE);
99 | if (!gwin.getPal().isFadedOut())
100 | gwin.getPal().apply();
101 | return;
102 | }
103 | oldInvisible = invis;
104 |
105 | if (main_actor == null || cheat.inInfravision() && !oldInfravision) {
106 | transition = null;
107 | gwin.getPal().set(Palette.PALETTE_DAY);
108 | if (!gwin.getPal().isFadedOut())
109 | gwin.getPal().apply();
110 | return;
111 | }
112 | oldInfravision = cheat.inInfravision();
113 |
114 | int new_dungeon = gwin.isInDungeon();
115 | int new_palette = getTimePalette(hour+1, new_dungeon != 0),
116 | old_palette = getTimePalette(hour, (dungeon!=255 ? dungeon : new_dungeon) != 0);
117 | boolean cloudy = overcast > 0;
118 | boolean foggy = fog > 0;
119 | boolean weather_change = (cloudy != wasOvercast) || (foggy != wasFoggy);
120 | boolean light_sensitive = isDarkPalette(new_palette) &&
121 | isDarkPalette(old_palette);
122 | boolean light_change = light_sensitive &&
123 | ((lightSourceLevel != oldLightLevel) ||
124 | (gwin.isSpecialLight() != oldSpecialLight));
125 |
126 | new_palette = getFinalPalette(new_palette, cloudy, foggy,
127 | lightSourceLevel, gwin.isSpecialLight());
128 | old_palette = getFinalPalette(old_palette, wasOvercast, wasFoggy,
129 | oldLightLevel, oldSpecialLight);
130 |
131 | if (gwin.getPal().isFadedOut()) {
132 | transition = null;
133 | gwin.getPal().set(old_palette);
134 | if (!gwin.getPal().isFadedOut()) {
135 | gwin.getPal().apply();
136 | gwin.setAllDirty();
137 | }
138 | return;
139 | }
140 | wasOvercast = cloudy;
141 | wasFoggy = foggy;
142 | oldLightLevel = lightSourceLevel;
143 | oldSpecialLight = gwin.isSpecialLight();
144 | dungeon = new_dungeon;
145 |
146 | if (weather_change) {
147 | // TODO: Maybe implement smoother transition from
148 | // weather to/from dawn/sunrise/sundown/dusk.
149 | // Right now, it works like the original.
150 | transition = new Palette.Transition(old_palette, new_palette,
151 | hour, minute, 1, 4, hour, minute);
152 | return;
153 | } else if (light_change) {
154 | transition = null;
155 | gwin.getPal().set(new_palette);
156 | if (!gwin.getPal().isFadedOut()) {
157 | gwin.getPal().apply();
158 | gwin.setAllDirty();
159 | }
160 | return;
161 | }
162 | if (transition != null) {
163 | if (transition.setStep(hour, minute))
164 | return;
165 | transition = null;
166 | }
167 | if (old_palette != new_palette) { // Do we have a transition?
168 | transition = new Palette.Transition(old_palette, new_palette,
169 | hour, minute, 4, 15, hour, 0);
170 | return;
171 | }
172 | gwin.getPal().set(new_palette);
173 | if (!gwin.getPal().isFadedOut()) {
174 | gwin.getPal().apply();
175 | gwin.setAllDirty();
176 | }
177 | }
178 | public void reset() {
179 | overcast = fog = 0;
180 | wasOvercast = wasFoggy = false;
181 | oldSpecialLight = false;
182 | oldInfravision = false;
183 | oldInvisible = false;
184 | dungeon = 255;
185 | transition = null;
186 | }
187 | // Start end cloud cover.
188 | public void setOvercast(boolean onoff) {
189 | overcast += (onoff ? 1 : -1);
190 | setPalette(); // Update palette.
191 | }
192 | public void increment(int numMinutes) {
193 | int oldHour;
194 | long newMin;
195 |
196 | oldHour = hour; // Remember current 3-hour period.
197 | numMinutes += 7; // Round to nearest 15 minutes.
198 | numMinutes -= numMinutes%15;
199 | newMin = minute + numMinutes;
200 | hour += (int) (newMin/60); // Update hour.
201 | minute = (int) (newMin%60);
202 | day += hour/24; // Update day.
203 | hour %= 24;
204 |
205 | // Update palette to new time.
206 | setPalette();
207 | // Check to see if we need to update the NPC schedules.
208 | if (hour != oldHour) // Update NPC schedules.
209 | gwin.scheduleNpcs(hour);
210 | }
211 | @Override
212 | public void handleEvent(int ctime, Object udata) {
213 | // TODO Auto-generated method stub
214 | int minOld = minute;
215 | int hourOld = hour;
216 | // Time stopped? Don't advance.
217 | if (gwin.isTimeStopped() == 0) {
218 | minute += timeRate;
219 | // ++++ TESTING
220 | // if (Game::get_game_type() == SERPENT_ISLE)
221 | //+++++FINISH Check_freezing();
222 | }
223 | while (minute >= 60) { // advance to the correct hour (and day)
224 | minute -= 60;
225 | if (++hour >= 24) {
226 | hour -= 24;
227 | day++;
228 | }
229 | gwin.mendNpcs(); // Restore HP's each hour.
230 | checkHunger(); // Use food, and print complaints.
231 | gwin.scheduleNpcs(hour);
232 | }
233 | if (transition != null && !transition.setStep(hour, minute)) {
234 | transition = null;
235 | setPalette();
236 | } else if (hour != hourOld)
237 | setPalette();
238 |
239 | if ((hour != hourOld) || (minute/15 != minOld/15))
240 | System.out.println("Clock updated to " + hour + ':' + minute);
241 | ctime += ticksPerMinute;
242 | tqueue.add(ctime, this, udata);
243 | }
244 | /*
245 | * Fake an update to the next 3-hour period.
246 | */
247 |
248 | public void fakeNextPeriod() {
249 | minute = 0;
250 | hour = ((hour/3 + 1)*3);
251 | day += hour/24; // Update day.
252 | hour %= 24;
253 | setPalette();
254 | checkHunger();
255 | gwin.scheduleNpcs(hour);
256 | gwin.mendNpcs(); // Just do it once, cheater.
257 | ExultActivity.showToast("The hour is now " + hour);
258 | }
259 | public void checkHunger() {
260 | gwin.getMainActor().useFood();
261 | int cnt = partyman.getCount();
262 | for (int i = 0; i < cnt; ++i)
263 | gwin.getNpc(partyman.getMember(i)).useFood();
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/src/com/exult/android/GameSingletons.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class GameSingletons {
4 | public static GameWindow gwin;
5 | public static ImageBuf win;
6 | public static EFileManager fman;
7 | public static TimeQueue tqueue;
8 | public static GameMap gmap;
9 | public static EffectsManager eman;
10 | public static FontsVgaFile fonts;
11 | public static UsecodeMachine ucmachine;
12 | public static Conversation conv; // This stays null until needed.
13 | public static PartyManager partyman;
14 | public static GumpManager gumpman;
15 | public static Game game;
16 | public static DraggingInfo drag;
17 | public static Mouse mouse;
18 | public static Cheat cheat;
19 | public static Audio audio;
20 | public static GameClock clock;
21 | public static void init(GameWindow gw) {
22 | gwin = gw;
23 | win = gwin.getWin();
24 | fman = EFileManager.instanceOf();
25 | gmap = gwin.getMap();
26 | tqueue = gwin.getTqueue();
27 | eman = gwin.getEffects();
28 | fonts = new FontsVgaFile();
29 | ucmachine = gwin.getUsecode();
30 | partyman = new PartyManager();
31 | gumpman = new GumpManager();
32 | mouse = new Mouse();
33 | cheat = new Cheat();
34 | audio = new Audio();
35 | clock = new GameClock();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/com/exult/android/IfixGameObject.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class IfixGameObject extends GameObject {
4 | public IfixGameObject(int shapenum, int framenum, int tilex,
5 | int tiley, int lft) {
6 | super(shapenum, framenum, tilex, tiley, lft);
7 | }
8 | public static class Animated extends IfixGameObject {
9 | private Animator animator;
10 | public Animated(int shapenum, int framenum, int tilex, int tiley, int lft) {
11 | super(shapenum, framenum, tilex, tiley, lft);
12 | animator = Animator.create(this);
13 | }
14 | @Override
15 | public void removeThis() {
16 | super.removeThis();
17 | animator.delete();
18 | }
19 | @Override
20 | public void paint() {
21 | animator.wantAnimation(); // Be sure animation is on.
22 | super.paint();
23 | }
24 | // Get coord. where this was placed.
25 | @Override
26 | public void getOriginalTileCoord(Tile t) {
27 | getTile(t);
28 | t.tx -= animator.getDeltax();
29 | t.ty -= animator.getDeltay();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/com/exult/android/IregGameObject.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.OutputStream;
3 | import java.io.IOException;
4 |
5 | /*
6 | * These are moveable objects.
7 | */
8 | public class IregGameObject extends GameObject {
9 | private ContainerGameObject owner; // Container this is in, or 0.
10 | protected int flags; // 32 flags used in 'usecode'.
11 | protected int flags2; // Another 32 flags used in 'usecode'.
12 | private static final byte writeBuf[] = new byte[20];
13 |
14 | public IregGameObject(int shapenum, int framenum, int tilex, int tiley, int lft) {
15 | super(shapenum, framenum, tilex, tiley, lft);
16 | }
17 | public final void setFlags(int f) {
18 | flags = f;
19 | }
20 | public final int getFlags() {
21 | return flags;
22 | }
23 | public final int getFlags2() {
24 | return flags2;
25 | }
26 | public boolean getFlag(int flag) {
27 | if (flag >= 0 && flag < 32)
28 | return (flags & (1 << flag)) != 0;
29 | else if (flag >= 32 && flag < 64)
30 | return (flags2 & (1 << (flag-32))) != 0;
31 | return false;
32 | }
33 | public void setFlag(int flag) {
34 | if (flag >= 0 && flag < 32)
35 | flags |= (1 << flag);
36 | else if (flag >= 32 && flag < 64)
37 | flags2 |= (1 << (flag-32));
38 | }
39 | public void clearFlag(int flag) {
40 | if (flag >= 0 && flag < 32)
41 | flags &= ~(1 << flag);
42 | else if (flag >= 32 && flag < 64)
43 | flags2 &= ~(1 << (flag-32));
44 | }
45 | public ContainerGameObject getOwner() {
46 | return owner;
47 | }
48 | public void setOwner(ContainerGameObject o) {
49 | owner = o;
50 | }
51 | public void removeThis() {
52 | if (owner != null) // In a bag, box, or person.
53 | owner.remove(this);
54 | else if (chunk != null) // In the outside world.
55 | chunk.remove(this);
56 | }
57 | public boolean isDragable() {
58 | return getInfo().getWeight() > 0; // 0 means 'too heavy'.
59 | }
60 | public static IregGameObject create(ShapeInfo info, int shnum, int frnum) {
61 | return create(info, shnum, frnum, 0, 0, 0);
62 | }
63 | public static IregGameObject create
64 | (
65 | ShapeInfo info, // Info. about shape.
66 | int shnum, int frnum, // Shape, frame.
67 | int tilex, int tiley, // Tile within chunk.
68 | int lift // Desired lift.
69 | ) {
70 | // (These are all animated.)
71 | if (info.isField() && info.getFieldType() >= 0)
72 | return new EggObject.Field(shnum, frnum, tilex, tiley,
73 | lift, (byte)(EggObject.fire_field + info.getFieldType()));
74 | else if (info.isAnimated() || info.hasSfx())
75 | return new Animated(shnum, frnum, tilex, tiley, lift);
76 | else if (shnum == 607) // Path.
77 | return new EggObject.PathMarker(
78 | shnum, frnum, tilex, tiley, lift);
79 | else if (info.isMirror()) // Mirror
80 | return new EggObject.Mirror(shnum, frnum, tilex, tiley, lift);
81 | else if (info.isBodyShape())
82 | return new Actor.DeadBody(shnum, frnum, tilex, tiley, lift, -1);
83 | else if (info.getShapeClass() == ShapeInfo.virtue_stone)
84 | return new VirtueStoneObject(
85 | shnum, frnum, tilex, tiley, lift);
86 | else if (info.getShapeClass() == ShapeInfo.spellbook) {
87 | final byte circles[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
88 | return new SpellbookObject(
89 | shnum, frnum, tilex, tiley, lift, circles, (byte)0);
90 | } else if (info.getShapeClass() == ShapeInfo.container) {
91 | /*
92 | if (info.is_jawbone())
93 | return new Jawbone_object(shnum, frnum, tilex, tiley,
94 | lift);
95 | else */
96 | return new ContainerGameObject(shnum, frnum,
97 | tilex, tiley, lift, 0);
98 | } else
99 | return new IregGameObject(shnum, frnum, tilex, tiley, lift);
100 | }
101 | public static IregGameObject create(int shnum, int frnum) {
102 | return create(ShapeID.getInfo(shnum), shnum, frnum, 0, 0, 0);
103 | }
104 | // Write 1 IREG data.
105 | public final int getCommonIregSize() {
106 | return (getShapeNum() >= 1024 || getFrameNum() >= 64)
107 | ? 7 : 5;
108 | }
109 | @Override
110 | public int getIregSize() {
111 | return iregGetIregSize();
112 | }
113 | protected int iregGetIregSize() {
114 | // These shouldn't ever happen, but you never know
115 | if (gumpman.findGump(this) != null || UsecodeScript.find(this) != null)
116 | return -1;
117 | return 6 + getCommonIregSize();
118 | }
119 | /*
120 | * Write the common IREG data for an entry.
121 | * Note: Length is incremented if this is an extended entry (shape# >
122 | * 1023).
123 | * Output: Index past data written.
124 | */
125 | protected int writeCommonIreg
126 | (
127 | int norm_len, // Normal length (if not extended).
128 | byte buf[] // Buffer to be filled.
129 | )
130 | {
131 | int endptr;
132 | int ind = 0;
133 | int shapenum = getShapeNum(), framenum = getFrameNum();
134 | if (shapenum >= 1024 || framenum >= 64) {
135 | buf[ind++] = (byte)GameMap.IREG_EXTENDED;
136 | norm_len++;
137 | buf[3] = (byte)(shapenum&0xff);
138 | buf[4] = (byte)((shapenum>>8)&0xff);
139 | buf[5] = (byte)framenum;
140 | endptr = 6;
141 | } else {
142 | buf[3] = (byte)(shapenum&0xff);
143 | buf[4] = (byte)(((shapenum>>8)&3) | (framenum<<2));
144 | endptr = 5;
145 | }
146 | buf[0] = (byte)norm_len;
147 | if (owner != null) { // Coords within gump.
148 | buf[1] = (byte)getTx();
149 | buf[2] = (byte)getTy();
150 | } else { // Coords on map.
151 | int cx = chunk != null ? chunk.getCx() : 255;
152 | int cy = chunk != null ? chunk.getCy() : 255;
153 | buf[1] = (byte)(((cx%16) << 4) | (getTx()&0xff));
154 | buf[2] = (byte)(((cy%16) << 4) | (getTy()&0xff));
155 | }
156 | return endptr;
157 | }
158 | @Override
159 | public void writeIreg(OutputStream out) throws IOException {
160 | iregWriteIreg(out);
161 | }
162 | public void iregWriteIreg(OutputStream out) throws IOException {
163 | int ind = writeCommonIreg(10, writeBuf);
164 | writeBuf[ind++] = (byte)((getLift()&15)<<4);
165 | writeBuf[ind] = (byte)getQuality();
166 | ShapeInfo info = getInfo();
167 | if (info.hasQualityFlags()) { // Store 'quality_flags'.
168 | writeBuf[ind] = (byte)((getFlag(GameObject.invisible)?1:0) +
169 | ((getFlag(GameObject.okay_to_take)?1:0) << 3));
170 | }
171 | // Special case for 'quantity' items:
172 | else if (getFlag(GameObject.okay_to_take) && info.hasQuantity())
173 | writeBuf[ind] |= 0x80;
174 | ++ind;
175 | writeBuf[ind++] = (byte)(getFlag(GameObject.is_temporary) ? 1 : 0);
176 | writeBuf[ind++] = 0; // Filler, I guess.
177 | writeBuf[ind++] = 0;
178 | writeBuf[ind++] = 0;
179 | out.write(writeBuf, 0, ind);
180 | // Write scheduled usecode.
181 | GameMap.writeScheduled(out, this, false);
182 | }
183 | public static class Animated extends IregGameObject {
184 | private Animator animator;
185 | public Animated(int shapenum, int framenum, int tilex, int tiley, int lft) {
186 | super(shapenum, framenum, tilex, tiley, lft);
187 | animator = Animator.create(this);
188 | }
189 | @Override
190 | public void removeThis() {
191 | super.removeThis();
192 | animator.delete();
193 | }
194 | @Override
195 | public void paint() {
196 | animator.wantAnimation(); // Be sure animation is on.
197 | super.paint();
198 | }
199 | // Get coord. where this was placed.
200 | @Override
201 | public void getOriginalTileCoord(Tile t) {
202 | getTile(t);
203 | t.tx -= animator.getDeltax();
204 | t.ty -= animator.getDeltay();
205 | }
206 | // Write out to IREG file.
207 | public void writeIreg(OutputStream out) throws IOException {
208 | int oldframe = getFrameNum();
209 | setFrame(animator.getFrameNum());
210 | super.writeIreg(out);
211 | setFrame(oldframe);
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/src/com/exult/android/ItemNames.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.RandomAccessFile;
3 | import java.io.IOException;
4 | // UNUSED import java.util.Vector;
5 |
6 | public class ItemNames {
7 | /* +++FINISH
8 | private static final String // File section names.
9 | SHAPES_SECT = "shapes",
10 | MSGS_SECT = "msgs",
11 | MISC_SECT = "miscnames";
12 | */
13 | public static String names[]; // The game items' names.
14 | public static String msgs[]; // Msgs. (0x400 - ).
15 | public static String misc[]; //Frames, etc (0x500 - 0x5ff/0x685 (BG/SI)).
16 |
17 | public final static void init(boolean si, boolean expansion) {
18 | // Exult new-style messages?
19 | RandomAccessFile txtfile = EUtil.U7open2(EFile.PATCH_TEXTMSGS, EFile.TEXTMSGS);
20 | if (txtfile != null) {
21 | SetupText(txtfile);
22 | } else {
23 | txtfile = EUtil.U7open2(EFile.PATCH_TEXT, EFile.TEXT_FLX);
24 | RandomAccessFile exultmsg = null;
25 | /* +++++++++FINISH?
26 | const char *msgs = BUNDLE_CHECK(BUNDLE_EXULTMSG, EXULTMSG);
27 | if (is_patch && U7exists(PATCH_EXULTMSG))
28 | U7open(exultmsg, PATCH_EXULTMSG, true);
29 | else
30 | U7open(exultmsg, msgs, true);
31 | */
32 | try {
33 | SetupItemNames(txtfile, exultmsg, si, expansion);
34 | } catch (IOException e) {
35 | System.out.println("ERROR reading in " + EFile.TEXT_FLX);
36 | }
37 | }
38 | }
39 | /*
40 | * Set up names of items.
41 | *
42 | * Msg. names start at 0x400.
43 | * Frame names start at entry 0x500 (reagents,medallions,food,etc.).
44 | */
45 |
46 | private static void SetupItemNames
47 | (
48 | RandomAccessFile itemfile,
49 | RandomAccessFile msgfile,
50 | boolean si,
51 | boolean expansion
52 | ) throws IOException {
53 | /* UNUSED +++LATER
54 | Vector msglist = null;
55 | int first_msg; // First in exultmsg.txt. Should
56 | */
57 | // follow those in text.flx.
58 | int num_text_msgs = 0, num_item_names = 0, num_misc_names = 0, total_msgs = 0;
59 | byte buf[] = new byte[256];
60 |
61 | itemfile.seek(0x54);
62 | int flxcnt = EUtil.Read4(itemfile);
63 | /*UNUSED first_msg = */ num_item_names = flxcnt;
64 | if (flxcnt > 0x400) {
65 | num_item_names = 0x400;
66 | num_text_msgs = flxcnt - 0x400;
67 | if (flxcnt > 0x500) {
68 | num_text_msgs = 0x100;
69 | num_misc_names = flxcnt - 0x500;
70 | int last_name = si ? 0x686 : 0x600; // Discard all starting from this.
71 | if (flxcnt > last_name) {
72 | num_misc_names = last_name - 0x500;
73 | flxcnt = last_name;
74 | }
75 | }
76 | total_msgs = num_text_msgs;
77 | }
78 | if (msgfile != null) { // Exult msgs. too?
79 | /*
80 | first_msg = Read_text_msg_file(msgfile, msglist);
81 | if (first_msg >= 0) {
82 | first_msg -= 0x400;
83 | if (first_msg < num_text_msgs) {
84 | cerr << "Exult msg. # " << first_msg <<
85 | " conflicts with 'text.flx'" << endl;
86 | first_msg = num_text_msgs;
87 | }
88 | total_msgs = static_cast(msglist.size() - 0x400);
89 | } else
90 | first_msg = num_text_msgs;
91 | */
92 | }
93 | names = new String[num_item_names];
94 | msgs = new String[total_msgs];
95 | misc = new String[num_misc_names];
96 | // Hack alert: move SI misc_names around to match those of SS.
97 | boolean doremap = si && !expansion;
98 | if (doremap)
99 | flxcnt -= 11; // Just to be safe.
100 | int i;
101 | for(i=0; i < flxcnt; i++)
102 | {
103 | itemfile.seek(0x80+i*8);
104 | int itemoffs = EUtil.Read4(itemfile);
105 | if(itemoffs == 0)
106 | continue;
107 | int itemlen = EUtil.Read4(itemfile);
108 | itemfile.seek(itemoffs);
109 | if (itemlen > buf.length)
110 | buf = new byte[itemlen];
111 | itemfile.read(buf, 0, itemlen);
112 | while (itemlen > 0 && buf[itemlen - 1] == 0) // Skip ending nulls.
113 | itemlen--;
114 | String nm = new String(buf, 0, itemlen);
115 | if (i < num_item_names) {
116 | names[i] = nm;
117 | } else if (i - num_item_names < num_text_msgs) {
118 | msgs[i - num_item_names] = nm;
119 | } else {
120 | misc[remapIndex(doremap, i - num_item_names - num_text_msgs)] = nm;
121 | }
122 | }
123 | /* +++++FINISH
124 | for (i = first_msg; i < total_msgs; i++)
125 | msgs[i] = msglist.get(i + 0x400);
126 | */
127 | num_text_msgs = total_msgs;
128 | }
129 | private static int remapIndex(boolean remap, int index) {
130 | if (!remap)
131 | return index;
132 | if (index >= 0x0fa)
133 | return index +11;
134 | else if (index >= 0x0b2)
135 | return index +10;
136 | else if (index >= 0x0af)
137 | return index +9;
138 | else if (index >= 0x094)
139 | return index +8;
140 | else if (index >= 0x08b)
141 | return index +7;
142 | else if (index >= 0x07f)
143 | return index +2;
144 | else
145 | return index;
146 | }
147 | /*
148 | * This sets up item names and messages from Exult's new file,
149 | * "textmsgs.txt".
150 | */
151 | private static void SetupText(RandomAccessFile txtfile){
152 | /* +++++++LATER
153 | ReadTextMsgFile(txtfile, names, SHAPES_SECT);
154 | ReadTextMsgFile(txtfile, msgs, MSGS_SECT);
155 | ReadTextMsgFile(txtfile, misc, MISC_SECT);
156 | */
157 | }
158 | /*
159 | * Message #'s. These are (offset-0x400) in text.flx and exultmsg.txt:
160 | */
161 | public static final int first_move_aside = 0x00, // For guards when blocked.
162 | last_move_aside = 0x02,
163 | first_preach = 0x03, last_preach = 0x07,
164 | first_preach2 = 0x08, last_preach2 = 0x0b,
165 | first_amen = 0x0c, last_amen = 0x0f,
166 | first_thief = 0x10, last_thief = 0x13,
167 | first_talk = 0x14, last_talk = 0x16,
168 | first_waiter_ask = 0x1b, last_waiter_ask = 0x1f,
169 | first_more_food = 0x20, last_more_food = 0x24,
170 | first_munch = 0x25, last_munch = 0x28,
171 | first_ouch = 0x29,
172 | last_ouch = 0x2c,
173 | first_need_help = 0x30,
174 | last_need_help = 0x33,
175 | first_will_help = 0x34,
176 | last_will_help = 0x36,
177 | first_to_battle = 0x39,
178 | last_to_battle = 0x3b,
179 | first_farmer = 0x3f, last_farmer = 0x41,
180 | first_miner = 0x42, last_miner = 0x44,
181 | first_miner_gold = 0x45, last_miner_gold = 0x47,
182 | first_flee = 0x48,
183 | last_flee = 0x4e,
184 | first_farmer2 = 0x60, last_farmer2 = 0x62,
185 | first_lamp_on = 0x63,
186 | last_lamp_on = 0x66,
187 | lamp_off = 0x67,
188 | first_call_police = 0x69,
189 | last_call_police = 0x6d,
190 | first_call_guards = 0x6c,
191 | last_call_guards = 0x6d,
192 | first_theft = 0x6e, // Warnings.
193 | last_theft = 0x70,
194 | first_close_shutters = 0x71,
195 | last_close_shutters = 0x73,
196 | first_open_shutters = 0x74,
197 | last_open_shutters = 0x76,
198 | first_hunger = 0x77, // A little hungry. (3 of each).
199 | first_needfood = 0x7a, // Must have food.
200 | first_starving = 0x7b, // Starving.
201 | heard_something = 0x95,
202 | first_awakened = 0x95,
203 | last_awakened = 0x9a,
204 | first_magebane_struck = 0x9b, // (SI only).
205 | last_magebane_struck = 0x9d; // (SI only).
206 | // Messages in exultmsg.txt ( - 0x400):
207 | public static final int first_chair_thief = 0x100, last_chair_thief = 0x104,
208 | first_waiter_banter = 0x105, last_waiter_banter = 0x107,
209 | first_waiter_serve = 0x108, last_waiter_serve = 0x109,
210 | first_bed_occupied = 0x10a, num_bed_occupied = 3,
211 | first_catchup = 0x10d, last_catchup = 0x10f,
212 | with_help_from = 0x110, exult_team = 0x111, driven_by_exult = 0x112,
213 | end_of_ultima7 = 0x113, end_of_britannia = 0x114,
214 | you_cannot_do_that = 0x115, damn_avatar = 0x116,
215 | blackgate_destroyed = 0x117, guardian_has_stopped = 0x118,
216 | txt_screen0 = 0x119, //to 0x11E
217 | txt_screen1 = 0x11F, //to 0x128
218 | txt_screen2 = 0x129, //to 0x12E
219 | txt_screen3 = 0x12F, //to 0x134
220 | txt_screen4 = 0x135, //to 0x138
221 | lord_castle = 0x139, dick_castle = 0x13A,
222 | bg_fellow = 0x13B, //to 0x13D
223 | my_leige = 0x13E, yo_homes = 0x53F,
224 | all_we0 = 0x140, //to 0x541
225 | and_a0 = 0x142, //to 0x543
226 | indeed = 0x144, //to 0x545
227 | iree = 0x146,
228 | stand_back = 0x147,
229 | jump_back = 0x148,
230 | batlin = 0x149,
231 | you_shall = 0x14B,
232 | there_i = 0x14D,
233 | batlin2 = 0x14F,
234 | you_must = 0x151,
235 | soon_i = 0x153,
236 | tis_my = 0x155;
237 |
238 | }
239 |
--------------------------------------------------------------------------------
/src/com/exult/android/MainActor.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import com.exult.android.shapeinf.*;
3 |
4 | public class MainActor extends Actor {
5 | static Tile stepFrom = new Tile();
6 | public MainActor(String nm, int shapenum) {
7 | super(nm, shapenum, -1, -1);
8 | frames = avatarFrames;
9 | setFlag(GameObject.in_party);
10 | }
11 | /*
12 | * Handle a time event (for TimeSensitive).
13 | */
14 | public void handleEvent(int ctime, Object udata) {
15 | if (action != null) { // Doing anything?
16 | // Do what we should.
17 | int speed = action.getSpeed();
18 | int delay = action.handleEvent(this);
19 | if (delay == 0) {
20 | // Action finished.
21 | // This makes for a smoother scrolling and prevents the
22 | // avatar from skipping a step when walking.
23 | frameTime = speed;
24 | if (frameTime == 0) // Not a path. Add a delay anyway.
25 | frameTime = 1; // 1 tick.
26 | delay = frameTime;
27 | setAction(null);
28 | }
29 | gwin.getTqueue().add(ctime + delay, this, udata);
30 | } else if (inUsecodeControl() || getFlag(GameObject.paralyzed))
31 | // Keep trying if we are in usecode control.
32 | gwin.getTqueue().add(ctime + 1, this, udata);
33 | else if (schedule != null)
34 | schedule.nowWhat();
35 | }
36 | /*
37 | * Get the party to follow.
38 | */
39 | public final void getFollowers() {
40 | int cnt = partyman.getCount();
41 | for (int i = 0; i < cnt; i++)
42 | {
43 | Actor npc = gwin.getNpc(partyman.getMember(i));
44 | if (npc == null || npc.getFlag(GameObject.asleep) ||
45 | npc.isDead())
46 | continue;
47 | int sched = npc.getScheduleType();
48 | // Skip if in combat or set to 'wait'.
49 | if (sched != Schedule.combat &&
50 | sched != Schedule.wait &&
51 | // Loiter added for SI.
52 | sched != Schedule.loiter) {
53 | if (sched != Schedule.follow_avatar)
54 | npc.setScheduleType(
55 | Schedule.follow_avatar);
56 | else
57 | npc.follow(this);
58 | }
59 | }
60 | }
61 | public boolean step(Tile t, int frame, boolean force) {
62 | restTime = 0; // Reset counter.
63 | t.fixme();
64 | // Get chunk.
65 | int cx = t.tx/EConst.c_tiles_per_chunk, cy = t.ty/EConst.c_tiles_per_chunk;
66 | // Get rel. tile coords.
67 | int tx = t.tx%EConst.c_tiles_per_chunk, ty = t.ty%EConst.c_tiles_per_chunk;
68 | MapChunk nlist = gmap.getChunk(cx, cy);
69 | int flags = getTileInfo(this, nlist, tx, ty);
70 | boolean poison = (flags&Actor.tilePoison) != 0;
71 | if (!areaAvailable(t, null, force ? EConst.MOVE_ALL : 0)) {
72 | if (isReallyBlocked(t, force)) {
73 | if (schedule != null) // Tell scheduler.
74 | schedule.setBlocked(t);
75 | stop();
76 | return false;
77 | }
78 | }
79 | if (poison && t.tz == 0)
80 | setFlag(GameObject.poisoned);
81 | // Check for scrolling.
82 | gwin.scrollIfNeeded(this, t);
83 | addDirty(false); // Set to update old location.
84 | // Get old chunk, old tile.
85 | MapChunk olist = getChunk();
86 | getTile(stepFrom);
87 | // Move it.
88 | movef(olist, nlist, tx, ty, frame, t.tz);
89 | addDirty(true); // Set to update new.
90 | // In a new chunk?
91 | if (olist != nlist)
92 | this.switchedChunks(olist, nlist);
93 | int roof_height = nlist.isRoof (tx, ty, t.tz);
94 | gwin.setIceDungeon(nlist.isIceDungeon(tx, ty));
95 | if (gwin.setAboveMainActor(roof_height)) {
96 | gwin.setInDungeon(nlist.hasDungeon()?
97 | nlist.isDungeon(tx, ty):0);
98 | gwin.setAllDirty();
99 | }
100 | else if (roof_height < 31 && gwin.setInDungeon(nlist.hasDungeon()?
101 | nlist.isDungeon(tx, ty):0))
102 | gwin.setAllDirty();
103 | // Near an egg? (Do this last, since
104 | // it may teleport.)
105 | nlist.activateEggs(this, t.tx, t.ty, t.tz,
106 | stepFrom.tx, stepFrom.ty, false);
107 | /*
108 | quake_on_walk();
109 | */
110 | return true;
111 | }
112 | public void switchedChunks(MapChunk olist, MapChunk nlist) {
113 | /* ++ MAYBE NOT NEED anymore.
114 | int newcx = nlist.getCx(), newcy = nlist.getCy();
115 | int xfrom, xto, yfrom, yto; // Get range of chunks.
116 | if (olist == null || // No old, or new map? Use all 9.
117 | olist.getMap() != nlist.getMap()) {
118 | xfrom = newcx > 0 ? newcx - 1 : newcx;
119 | xto = newcx < EConst.c_num_chunks - 1 ? newcx + 1 : newcx;
120 | yfrom = newcy > 0 ? newcy - 1 : newcy;
121 | yto = newcy < EConst.c_num_chunks - 1 ? newcy + 1 : newcy;
122 | } else {
123 | int oldcx = olist.getCx(), oldcy = olist.getCy();
124 | if (newcx == oldcx + 1)
125 | {
126 | xfrom = newcx;
127 | xto = newcx < EConst.c_num_chunks - 1 ? newcx + 1 : newcx;
128 | }
129 | else if (newcx == oldcx - 1)
130 | {
131 | xfrom = newcx > 0 ? newcx - 1 : newcx;
132 | xto = newcx;
133 | }
134 | else
135 | {
136 | xfrom = newcx > 0 ? newcx - 1 : newcx;
137 | xto = newcx < EConst.c_num_chunks - 1 ? newcx + 1 : newcx;
138 | }
139 | if (newcy == oldcy + 1)
140 | {
141 | yfrom = newcy;
142 | yto = newcy < EConst.c_num_chunks - 1 ? newcy + 1 : newcy;
143 | }
144 | else if (newcy == oldcy - 1)
145 | {
146 | yfrom = newcy > 0 ? newcy - 1 : newcy;
147 | yto = newcy;
148 | }
149 | else
150 | {
151 | yfrom = newcy > 0 ? newcy - 1 : newcy;
152 | yto = newcy < EConst.c_num_chunks - 1 ? newcy + 1 : newcy;
153 | }
154 | }
155 | */
156 | // If change in Superchunk number, apply Old Style caching emulation
157 | gwin.emulateCache(olist, nlist);
158 | }
159 | /*
160 | * Move (teleport) to a new spot.
161 | */
162 | public void move(int newtx, int newty, int newlift, int newmap) {
163 | MapChunk olist = getChunk(); // Store old chunk list.
164 | // Move it.
165 | super.move(newtx, newty, newlift, newmap);
166 | MapChunk nlist = getChunk();
167 | if (nlist != olist)
168 | switchedChunks(olist, nlist);
169 | int tx = getTx(), ty = getTy();
170 | gwin.setIceDungeon(nlist.isIceDungeon(tx, ty));
171 | if (gwin.setAboveMainActor(nlist.isRoof(tx, ty, newlift)))
172 | gwin.setInDungeon(nlist.hasDungeon() ? nlist.isDungeon(tx, ty) : 0);
173 | }
174 | /*
175 | * We're dead.
176 | */
177 | @Override
178 | public void die(GameObject attacker) {
179 | if (gwin.inCombat())
180 | gwin.toggleCombat(); // Hope this is safe....
181 | super.setFlag(GameObject.dead);
182 | gumpman.closeAllGumps(false); // Obviously.
183 | // Special function for dying:
184 | ShapeInfoLookup.UsecodeFunctionData info = ShapeInfoLookup.getAvUsecode(0);
185 | ucmachine.callUsecode(info.funId, this, info.eventId);
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/src/com/exult/android/Mouse.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import android.graphics.Point;
3 |
4 | public final class Mouse extends GameSingletons {
5 | private VgaFile.ShapeFile pointers; // Pointers from 'pointers.shp'.
6 | private int maxw, maxh; // Max size. Used as size of 'backup'.
7 | private byte backup[]; // Stores image below mouse shape.Rectangle box; // Area backed up.
8 | private Rectangle box; // Area backed up.
9 | private Point avLoc;
10 | private int mousex, mousey; // Last place where mouse was.
11 | private int cur_framenum; // Frame # of current shape.
12 | private ShapeFrame cur; // Current shape.
13 | boolean onscreen; // true if mouse is drawn on screen.
14 | // Frame #'s of short arrows, by int (0-7, 0=east).
15 | private static int shortArrows[] =
16 | {8, 9, 10, 11, 12, 13, 14, 15};
17 | private static int medArrows[] = {16, 17, 18, 19, 20, 21, 22, 23};
18 | private static int longArrows[] = {24, 25, 26, 27, 28, 29, 30, 31};
19 | private static int shortCombatArrows[] =
20 | {32, 33, 34, 35, 36, 37, 38, 39};
21 | private static int medCombatArrows[] =
22 | {40, 41, 42, 43, 44, 45, 46, 47};
23 | private void setShape0(int framenum) { // Set shape without checking first.
24 | cur_framenum = framenum;
25 | cur = pointers.getFrame(framenum);
26 | while (cur == null) // For newly-created games.
27 | cur = pointers.getFrame(--framenum);
28 | // Set backup box to cover mouse.
29 | box.x = mousex - cur.getXLeft();
30 | box.y = mousey - cur.getYAbove();
31 | }
32 | private void init() {
33 | box = new Rectangle();
34 | avLoc = new Point();
35 | int cnt = pointers.getNumFrames();
36 | int maxleft = 0, maxright = 0, maxabove = 0, maxbelow = 0;
37 | for (int i = 0; i < cnt; i++) {
38 | ShapeFrame frame = pointers.getFrame(i);
39 | int xleft = frame.getXLeft(), xright = frame.getXRight();
40 | int yabove = frame.getYAbove(), ybelow = frame.getYBelow();
41 | if (xleft > maxleft)
42 | maxleft = xleft;
43 | if (xright > maxright)
44 | maxright = xright;
45 | if (yabove > maxabove)
46 | maxabove = yabove;
47 | if (ybelow > maxbelow)
48 | maxbelow = ybelow;
49 | }
50 | maxw = maxleft + maxright;
51 | maxh = maxabove + maxbelow;
52 | // Create backup buffer.
53 | backup = new byte[maxw * maxh];
54 | box.w = maxw;
55 | box.h = maxh;
56 |
57 | onscreen = false; // initially offscreen
58 | setShape(getShortArrow(EConst.east)); // For now.
59 | }
60 | public static final int // enum int :List of shapes' frame #'s.
61 | dontchange = 1000, // Flag to not change.
62 | hand = 0,
63 | redx = 1,
64 | greenselect = 2, // For modal select.
65 | tooheavy = 3,
66 | outofrange = 4,
67 | outofammo = 5,
68 | wontfit = 6,
69 | hourglass = 7,
70 | greensquare = 23,
71 | blocked = 49;
72 |
73 | /* Avatar speed, relative to standard delay:
74 | * avatarSpeed = standard_delay * 100 / avatarSpeedFactor
75 | *
76 | *
77 | * Experimental results, Serpent Isle
78 | *
79 | * "short" arrow within central 0.4 of screen in each dimension
80 | * "middle" arrow within central 0.8 of screen in each dimension
81 | * "long" arrow (non-combat, non-threat only) outside
82 | *
83 | * relative speeds:
84 | * (movement type - time for a certain dist. - rel. speed)
85 | * non-combat short arrow - 8 - 1
86 | * non-combat medium arrow - 4 - 2
87 | * non-combat long arrow - 2 - 4
88 | * combat short arrow - 8 - 1
89 | * combat medium arrow - 6 - 4/3
90 | */
91 | public static final int // Avatar speeds in ticks/step.
92 | slow = 3,
93 | mediumCombat = 2,
94 | medium = 2,
95 | fast = 1;
96 | public int avatarSpeed; // One of the above.
97 |
98 | Mouse() {
99 | pointers = new VgaFile.ShapeFile(EFile.POINTERS);
100 | init();
101 | }
102 | public Mouse(byte data[]) {
103 | pointers = new VgaFile.ShapeFile(data);
104 | init();
105 | setShape0(0);
106 | }
107 | public int getX() {
108 | return mousex;
109 | }
110 | public int getY() {
111 | return mousey;
112 | }
113 | boolean show() { // Paint it.
114 | synchronized(gwin.getWin()) {
115 | if (!onscreen){
116 | onscreen = true;
117 | // Save background.
118 | gwin.getWin().get(backup, maxw, maxh, box.x, box.y);
119 | // Paint new location.
120 | cur.paintRle(gwin.getWin(), mousex, mousey);
121 | return true;
122 | } else
123 | return false;
124 | }
125 | }
126 | void hide() { // Restore area under mouse.
127 | synchronized(gwin.getWin()) {
128 | if (onscreen) {
129 | onscreen = false;
130 | gwin.getWin().put(backup, maxw, maxh, box.x, box.y);
131 | }
132 | }
133 | }
134 | public void setShape(int framenum) { // Set to desired shape.
135 | if (framenum != cur_framenum)
136 | setShape0(framenum);
137 | }
138 | int getShape()
139 | { return cur_framenum; }
140 | void move(int x, int y) { // Move to new location (mouse motion).
141 | hide();
142 | // Shift to new position.
143 | box.shift(x - mousex, y - mousey);
144 | mousex = x;
145 | mousey = y;
146 | }
147 | void setLocation(int x, int y) {// Set to given location.
148 | mousex = x;
149 | mousey = y;
150 | box.x = mousex - cur.getXLeft();
151 | box.y = mousey - cur.getYAbove();
152 | }
153 | // Flash desired shape for 1/2 sec.
154 | public void flashShape(int flash) {
155 | ShapeFrame s = pointers.getFrame(flash);
156 | if (s != null)
157 | new EffectsManager.MouseFlash(s, mousex, mousey);
158 | }
159 | // Set to short arrow.
160 | int getShortArrow(int dir)
161 | { return (shortArrows[(dir)]); }
162 | // Set to medium arrow.
163 | int getMediumArrow(int dir)
164 | { return (medArrows[(dir)]); }
165 | // Set to long arrow.
166 | int getLongArrow(int dir)
167 | { return (longArrows[(dir)]); }
168 | // Set to short combat mode arrow.
169 | int getShortCombatArrow(int dir)
170 | { return (shortCombatArrows[(dir)]); }
171 | // Set to medium combat mode arrow.
172 | int getMediumCombatArrow(int dir)
173 | { return (medCombatArrows[(dir)]); }
174 |
175 | boolean isOnscreen() {
176 | return onscreen;
177 | }
178 | // Sets hand or speed cursors
179 | void setSpeedCursor(int ax, int ay) {
180 | int cursor = dontchange;
181 |
182 | // Check if we are in dont_move mode, in this case display the hand cursor
183 | if (gwin.mainActorDontMove())
184 | cursor = hand;
185 | else if (gumpman.gumpMode()) {
186 | cursor = hand;
187 | }
188 | if (cursor == dontchange) {
189 | BargeObject barge = gwin.getMovingBarge();
190 | if (barge != null) { // Use center of barge.
191 | gwin.getShapeLocation(avLoc, barge);
192 | ax = avLoc.x - barge.getXtiles()*(EConst.c_tilesize/2);
193 | ay = avLoc.y - barge.getYtiles()*(EConst.c_tilesize/2);
194 | } else {
195 | int dy = ay - mousey, dx = mousex - ax;
196 | int dir = EUtil.getDirection(dy, dx);
197 | int gamew = gwin.getWidth(), gameh = gwin.getHeight();
198 | float speed_section = Math.max( Math.max( -(float)dx/ax, (float)dx/(gamew-ax)),
199 | Math.max((float)dy/ay, -(float)dy/(gameh-ay)) );
200 | boolean nearby_hostile = false; //+++++++ gwin.isHostileNearby();
201 | boolean has_active_nohalt_scr = false;
202 | UsecodeScript scr = null;
203 | Actor act = gwin.getMainActor();
204 | while ((scr = UsecodeScript.findActive(act, scr)) != null)
205 | // We should only be here is scripts are nohalt, but just
206 | // in case...
207 | if (scr.isNoHalt()) {
208 | has_active_nohalt_scr = true;
209 | break;
210 | }
211 | if(speed_section < 0.4 ) {
212 | if( gwin.inCombat() )
213 | cursor = getShortCombatArrow( dir );
214 | else
215 | cursor = getShortArrow( dir );
216 | avatarSpeed = slow;
217 | } else if( speed_section < 0.8 || gwin.inCombat() || nearby_hostile
218 | || has_active_nohalt_scr) {
219 | if( gwin.inCombat() )
220 | cursor = getMediumCombatArrow( dir );
221 | else
222 | cursor = getMediumArrow( dir );
223 | if( gwin.inCombat() || nearby_hostile )
224 | avatarSpeed = mediumCombat;
225 | else
226 | avatarSpeed = medium;
227 | } else { /* Fast - NB, we can't get here in combat mode; there is no
228 | * long combat arrow, nor is there a fast combat speed. */
229 | cursor = getLongArrow( dir );
230 | avatarSpeed = fast;
231 | }
232 | }
233 | }
234 | if (cursor != dontchange)
235 | setShape(cursor);
236 | }
237 | /*
238 | * ++++++EXPERIMENTAL: New method of showing mouse using ImageBuf
239 | */
240 | private ImageBuf mouseRender;
241 | /*
242 | * Set up mouse when 'cur' shape changes.
243 | */
244 | private void setup() {
245 | int w = cur.getWidth(), h = cur.getHeight(), xleft = cur.getXLeft(), yabove = cur.getYAbove();
246 | if (mouseRender == null) {
247 | mouseRender = new ImageBuf(w, h);
248 | Palette pal = new Palette(mouseRender);
249 | pal.set(Palette.PALETTE_DAY);
250 | pal.apply();
251 | mouseRender.setPaletteVal(0xff, 0xff000000); // Set 0xff to be transparent.
252 | } else if (mouseRender.getWidth() != w || mouseRender.getHeight() != h)
253 | mouseRender.setSize(w, h);
254 | mouseRender.fill8((byte)0xff);
255 | cur.paintRle(mouseRender, xleft, yabove);
256 | mouseRender.blit();
257 | gwin.getWin().setMouse(mouseRender);
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/src/com/exult/android/NpcActor.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class NpcActor extends Actor {
4 | protected Schedule.ScheduleChange schedules[];
5 |
6 | public NpcActor(String nm, int shapenum) {
7 | super(nm, shapenum, -1, -1);
8 | }
9 | public NpcActor(String nm, int shapenum, int num, int uc) {
10 | super(nm, shapenum, num, uc);
11 | }
12 | /*
13 | * Run usecode when double-clicked.
14 | */
15 | public void activate(int event) {
16 | if (!isDead())
17 | super.activate(event);;
18 | }
19 | /*
20 | * Handle a time event (for TimeSensitive).
21 | */
22 | public void handleEvent(int ctime, Object udata) {
23 | if ((getFlag(GameObject.paralyzed) || isDead() ||
24 | getProperty(health) <= 0 ||
25 | (getFlag(GameObject.asleep) && scheduleType != Schedule.sleep))) {
26 | tqueue.add(ctime + 1, this, udata);
27 | return;
28 | }
29 | // Prevent actor from doing anything if not in the active map.
30 | // ... but not if the NPC is not on the map (breaks pathfinding
31 | // from offscreen if NPC not on map).
32 | if (getMap() != null && getMap() != gwin.getMap()) {
33 | setAction(null);
34 | dormant = true;
35 | if (schedule != null)
36 | schedule.imDormant();
37 | return;
38 | }
39 | if (schedule != null && partyId < 0 && canAct() &&
40 | (scheduleType != Schedule.combat || // Not if already in combat.
41 | // Patrol schedule already does this.
42 | scheduleType != Schedule.patrol ||
43 | scheduleType != Schedule.sleep ||
44 | scheduleType != Schedule.wait) &&
45 | (EUtil.rand()%3) == 0) // Don't do it every time.
46 | schedule.seekFoes();
47 |
48 | if (action == null) { // Not doing anything?
49 | if (inUsecodeControl() || !canAct())
50 | // Can't move on our own. Keep trying.
51 | tqueue.add(ctime + 1, this, udata);
52 | else if (schedule != null) {
53 | // Should try seeking foes?
54 | if (partyId < 0 && canAct() &&
55 | // Not if already in combat.
56 | (scheduleType != Schedule.combat ||
57 | // Patrol schedule already does this.
58 | scheduleType != Schedule.patrol ||
59 | scheduleType != Schedule.sleep ||
60 | scheduleType != Schedule.wait) &&
61 | (EUtil.rand()%4) == 0) { // Don't do it every time.
62 | schedule.seekFoes();
63 | // Get back into queue.
64 | tqueue.add(ctime + 1, this, udata);
65 | } else if (dormant && scheduleType != Schedule.walk_to_schedule)
66 | tqueue.add(ctime + 3, this, udata); // Check in 1/2 sec.
67 | else
68 | schedule.nowWhat();
69 | }
70 | } else { // Do what we should.
71 | int delay = partyId < 0 ? gwin.isTimeStopped() : 0;
72 | if (delay <= 0) { // Time not stopped?
73 | int speed = action.getSpeed();
74 | delay = action.handleEvent(this);
75 | if (delay == 0) { // Action finished. Add a slight delay.
76 | frameTime = speed;
77 | if (frameTime == 0) // Not a path. Add a delay anyway.
78 | frameTime = 1;
79 | delay = frameTime;
80 | setAction(null);
81 | }
82 | }
83 | tqueue.add(ctime + delay, this, udata);
84 | }
85 | }
86 | /*
87 | * Step onto an adjacent tile.
88 | *
89 | * Output: 0 if blocked (or paralyzed).
90 | * Dormant is set if off screen.
91 | */
92 | public boolean step(Tile t, int frame, boolean force) {
93 | if (getFlag(GameObject.paralyzed) || getMap() != gmap)
94 | return false;
95 | int oldtx = getTileX(), oldty = getTileY();
96 | //System.out.println("Npc #" + npcNum + " stepping to " + t.tx + "," + t.ty);
97 | // Get old chunk.
98 | MapChunk olist = getChunk();
99 | t.fixme();
100 | // Get chunk.
101 | int cx = t.tx/EConst.c_tiles_per_chunk, cy = t.ty/EConst.c_tiles_per_chunk;
102 | // Get rel. tile coords.
103 | int tx = t.tx%EConst.c_tiles_per_chunk, ty = t.ty%EConst.c_tiles_per_chunk;
104 | // Get .new chunk.
105 | MapChunk nlist = gmap.getChunk(cx, cy);
106 | if (nlist == null || !nlist.isRead()) {
107 | stop();
108 | dormant = true;
109 | return false;
110 | }
111 | int flags = getTileInfo(this, nlist, tx, ty);
112 | boolean poison = (flags&Actor.tilePoison) != 0;
113 | if (!areaAvailable(t, null, force ? EConst.MOVE_ALL : 0)) {
114 | if (isReallyBlocked(t, force)) {
115 | if (schedule != null) // Tell scheduler.
116 | schedule.setBlocked(t);
117 | stop();
118 | // Offscreen, but not in party?
119 | if (gwin.addDirty(this) && partyId < 0 &&
120 | // And > a screenful away?
121 | distance(gwin.getCameraActor()) >
122 | 1 + EConst.c_screen_tile_size)
123 | dormant = true; // Go dormant.
124 | return false; // Done.
125 | }
126 | }
127 | if (poison && t.tz == 0)
128 | setFlag(GameObject.poisoned);
129 | addDirty(false); // Set to repaint old area.
130 | // Move it.
131 | movef(olist, nlist, tx, ty, frame, t.tz);
132 | // Near an egg? (Do this last, since
133 | // it may teleport.)
134 | nlist.activateEggs(this, t.tx, t.ty, t.tz, oldtx, oldty, false);
135 | // Offscreen, but not in party?
136 | if (!addDirty(true) && partyId < 0 &&
137 | // And > a screenful away?
138 | distance(gwin.getCameraActor()) >
139 | 1 + EConst.c_screen_tile_size &&
140 | //+++Try getting rid of the 'talk' line:
141 | getScheduleType() != Schedule.talk &&
142 | getScheduleType() != Schedule.walk_to_schedule &&
143 | getScheduleType() != Schedule.street_maintenance) {
144 | // No longer on screen.
145 | stop();
146 | dormant = true;
147 | return false;
148 | }
149 | quakeOnWalk();
150 | return true; // Add back to queue for next time.
151 | }
152 | /*
153 | * Remove an object from its container, or from the world.
154 | * The object is deleted.
155 | */
156 | public void removeThis() {
157 | setAction(null);
158 | // Messes up resurrection num_schedules = 0;
159 | tqueue.remove(this);// Remove from time queue.
160 | // Store old chunk list.
161 | MapChunk olist = getChunk();
162 | super.removeThis(); // Remove, but don't ever delete an NPC
163 | switchedChunks(olist, null);
164 | setInvalid();
165 | }
166 | /*
167 | * Move (teleport) to a new spot.
168 | */
169 | public void move(int newtx, int newty, int newlift, int newmap) {
170 | MapChunk olist = getChunk(); // Store old chunk list.
171 | // Move it.
172 | super.move(newtx, newty, newlift, newmap);
173 | MapChunk nlist = getChunk();
174 | if (nlist != olist) {
175 | switchedChunks(olist, nlist);
176 | if (olist != null) // Moving back into world?
177 | dormant = true; // Cause activation if painted.
178 | }
179 | }
180 | public void setSchedules(Schedule.ScheduleChange sched[]) {
181 | schedules = sched;
182 | }
183 | public Schedule.ScheduleChange[] getSchedules() {
184 | return schedules;
185 | }
186 | /*
187 | * Find day's schedule for a given time-of-day.
188 | *
189 | * Output: index of schedule change.
190 | * -1 if not found, or if a party member.
191 | */
192 | int findScheduleChange
193 | (
194 | int hour3 // 0=midnight, 1=3am, etc.
195 | ) {
196 | if (partyId >= 0 || isDead())
197 | return (-1); // Fail if a party member or dead.
198 | int cnt = schedules == null ? 0 : schedules.length;
199 | for (int i = 0; i < cnt; i++)
200 | if (schedules[i].getTime() == hour3)
201 | return i;
202 | return -1;
203 | }
204 | /*
205 | * Update schedule at a 3-hour time change.
206 | */
207 | @Override
208 | public void updateSchedule
209 | (
210 | int hour3, // 0=midnight, 1=3am, etc.
211 | int backwards, // Extra periods to look backwards.
212 | int delay // Delay in msecs, or -1 for random.
213 | ) {
214 | int i = findScheduleChange(hour3);
215 | if (i < 0) { // Not found? Look at prev.?
216 | // Always if noon of first day.
217 | long hour = clock.getTotalHours();
218 | if (hour == 12 && backwards == 0)
219 | backwards++;
220 | while (backwards-- != 0 && i < 0)
221 | i = findScheduleChange((--hour3 + 8)%8);
222 | if (i < 0)
223 | return;
224 | // This is bad, not always true
225 | // location might be different
226 | //if (scheduleType == schedules[i].get_type())
227 | // return; // Already in it.
228 | }
229 | setScheduleAndLoc(schedules[i].getType(), schedules[i].getPos(),
230 | delay);
231 | }
232 | /*
233 | * Render.
234 | */
235 | public void paint() {
236 | super.paint(); // Draw on screen.
237 | if (dormant && schedule != null && // Resume schedule.
238 | // FOR NOW: Not when in formation.
239 | (partyId < 0 || scheduleType != Schedule.follow_avatar)) {
240 | dormant = false; // But clear out old entries first.??
241 | tqueue.remove(this);
242 | // Force schedule->now_what() in about 1/2 sec.
243 | // DO NOT call now_what here!!!
244 | int curtime = TimeQueue.ticks;
245 | tqueue.add(curtime + 3, this, gwin);
246 | }
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/src/com/exult/android/ObjectList.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | /*
4 | * A list of objects chained together using the 'next' and 'prev' fields in GameObject.
5 | */
6 | public class ObjectList {
7 | private GameObject first; // .first in (circular) chain.
8 | private short iterCount; // # of iterators.
9 | public ObjectList(GameObject f) {
10 | first = f;
11 | }
12 | public ObjectList() { }
13 | public void reportProblem() {
14 | //++FINISH?
15 | }
16 | public boolean isEmpty()
17 | { return first == null; }
18 | public void addIterator()
19 | { iterCount++; }
20 | public void removeIterator()
21 | { iterCount--; }
22 | public GameObject getFirst()
23 | { return first; }
24 | // Insert at head of chain.
25 | public void insert(GameObject nobj) {
26 | if (iterCount != 0)
27 | reportProblem();
28 | if (first == null) // First one.
29 | nobj.next = nobj.prev = nobj;
30 | else {
31 | nobj.next = first;
32 | nobj.prev = first.prev;
33 | first.prev.next = nobj;
34 | first.prev = nobj;
35 | }
36 | first = nobj;
37 | }
38 | // Insert before given obj.
39 | public void insertBefore(GameObject nobj, GameObject before) {
40 | if (iterCount != 0)
41 | reportProblem();
42 | nobj.next = before;
43 | nobj.prev = before.prev;
44 | before.prev.next = nobj;
45 | before.prev = nobj;
46 | first = before == first ? nobj : first;
47 | }
48 | // Append.
49 | public void append(GameObject nobj)
50 | { insert(nobj); first = nobj.next; }
51 | public void remove(GameObject dobj) {
52 | if (iterCount != 0)
53 | reportProblem();
54 | if (dobj == first)
55 | first = dobj.next != first ? dobj.next : null;
56 | dobj.next.prev = dobj.prev;
57 | dobj.prev.next = dobj.next;
58 | }
59 | /*
60 | * Iterators
61 | */
62 | public static abstract class ObjectIteratorBase {
63 | protected ObjectList list;
64 | protected GameObject first, stop, cur;
65 | public ObjectIteratorBase(ObjectList l) {
66 | list = l;
67 | list.addIterator();
68 | }
69 | public void done() {
70 | list.removeIterator();
71 | }
72 | public abstract GameObject next();
73 | }
74 | public static class ObjectIterator extends ObjectIteratorBase {
75 | public ObjectIterator(ObjectList l) {
76 | super(l);
77 | cur = first = l.first;
78 | stop = null;
79 | }
80 | public void reset() {
81 | cur = first; stop = null;
82 | }
83 | public GameObject next() {
84 | if (cur == stop)
85 | return null;
86 | GameObject ret = cur;
87 | cur = cur.next;
88 | stop = first;
89 | return ret;
90 | }
91 | }
92 | public static class ObjectIteratorBackwards extends ObjectIteratorBase {
93 | public void reset() {
94 | cur = first; stop = null; }
95 | public ObjectIteratorBackwards(ObjectList l) {
96 | super(l);
97 | cur = first = l.getFirst();
98 | stop = null;
99 | }
100 | public GameObject next() {
101 | if (cur == stop)
102 | return null;
103 | cur = cur.prev;
104 | stop = first;
105 | return cur;
106 | }
107 | }
108 | public static class NonflatObjectIterator extends ObjectIterator {
109 | private GameObject nonflats;
110 | public void reset()
111 | { this.cur = nonflats; this.stop = null; }
112 | public NonflatObjectIterator(ObjectList l, GameObject firstNonflat) {
113 | super(l);
114 | nonflats = firstNonflat;
115 | reset();
116 | }
117 | };
118 | public static class FlatObjectIterator extends ObjectIteratorBase {
119 | private GameObject stopAt;
120 | public FlatObjectIterator(ObjectList l, GameObject firstNonflat) {
121 | super(l);
122 | first = l.first == firstNonflat ? null : l.first;
123 | stopAt = firstNonflat != null ? firstNonflat : l.first;
124 | cur = first; stop = null;
125 | }
126 | public GameObject next() {
127 | if (cur == stop)
128 | return null;
129 | GameObject ret = cur;
130 | cur = cur.next;
131 | stop = stopAt;
132 | return ret;
133 | }
134 | }
135 | ObjectIterator getIterator() {
136 | return new ObjectIterator(this);
137 | }
138 | FlatObjectIterator getFlatIterator(GameObject firstNonflat) {
139 | return new FlatObjectIterator(this, firstNonflat);
140 | }
141 | NonflatObjectIterator getNonflatIterator(GameObject firstNonflat) {
142 | return new NonflatObjectIterator(this, firstNonflat);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/com/exult/android/PlasmaThread.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class PlasmaThread extends Thread {
4 | static final int BG_PLASMA_START_COLOR = 128;
5 | static final int BG_PLASMA_CYCLE_RANGE = 80;
6 | static final int SI_PLASMA_START_COLOR = 16;
7 | static final int SI_PLASMA_CYCLE_RANGE = 96;
8 | private int startColor, cycleRange;
9 | private Palette pal;
10 | private GameWindow gwin;
11 | public boolean finish = false;
12 | private void plasma(int w, int h, int x, int y, int startc, int endc) {
13 | ImageBuf win = GameSingletons.win;
14 | win.fill8((byte)startc, w, h, x, y);
15 | for (int i=0; i < w*h; i += 16) { // Too many loops makes this too slow.
16 | int pc = startc + EUtil.rand()%(endc-startc+1);
17 | int px = x + EUtil.rand()%w;
18 | int py = y + EUtil.rand()%h;
19 | for (int j=0; j < 6; j++) {
20 | int px2 = px + EUtil.rand()%17 - 8;
21 | int py2 = py + EUtil.rand()%17 - 8;
22 | win.fill8((byte)pc, 3, 1, px2 - 1, py2);
23 | win.fill8((byte)pc, 1, 3, px2, py2 - 1);
24 | }
25 | }
26 | gwin.setPainted();
27 | }
28 | public PlasmaThread(Palette p) {
29 | pal = p;
30 | gwin = GameSingletons.gwin;
31 | if (GameSingletons.game.isBG()) {
32 | startColor = BG_PLASMA_START_COLOR;
33 | cycleRange = BG_PLASMA_CYCLE_RANGE;
34 | } else {
35 | startColor = SI_PLASMA_START_COLOR;
36 | cycleRange = SI_PLASMA_CYCLE_RANGE;
37 | }
38 | synchronized(gwin.getWin()) {
39 | // Load the palette
40 | if (GameSingletons.game.isBG())
41 | pal.load(EFile.INTROPAL_DAT, EFile.PATCH_INTROPAL, 2);
42 | else
43 | pal.load(EFile.MAINSHP_FLX, EFile.PATCH_MAINSHP, 1);
44 | pal.apply();
45 | plasma(gwin.getWidth(), gwin.getHeight(), 0, 0, startColor, startColor + cycleRange - 1);
46 | }
47 |
48 | }
49 | @Override
50 | public void run() {
51 | System.out.println("PlasmaThread: run: started: " + GameSingletons.tqueue.ticks);
52 | while (!finish) {
53 | for(int i = 0; i < 4; ++i)
54 | gwin.getWin().rotateColors(startColor, cycleRange);
55 | gwin.setPainted();
56 | try {
57 | sleep(100);
58 | } catch (InterruptedException e) {
59 | finish = true;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/com/exult/android/Preferences.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | import android.os.Bundle;
4 | import android.preference.PreferenceActivity;
5 |
6 | public class Preferences extends PreferenceActivity {
7 | @Override
8 | public void onCreate(Bundle savedInstanceState) {
9 | super.onCreate(savedInstanceState);
10 |
11 | addPreferencesFromResource(R.xml.preferences);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/com/exult/android/Ready.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | // Information from the ready.dat file.
4 | public final class Ready {
5 | /*
6 | * Internal Exult types describing how a shape may be worn.
7 | */
8 | public final static int // enum Ready_type_Exult
9 | head = 0x00,
10 | backpack = 0x01,
11 | belt = 0x02,
12 | lhand = 0x03,
13 | lfinger = 0x04,
14 | legs = 0x05,
15 | feet = 0x06,
16 | rfinger = 0x07, // Only for usecode or for alternate slot.
17 | rhand = 0x08,
18 | torso = 0x09,
19 | amulet = 0x0a,
20 | quiver = 0x0b,
21 | back_2h = 0x0c, // Only for usecode or for alternate slot
22 | back_shield = 0x0d, // Only for usecode or for alternate slot
23 | earrings = 0x0e,
24 | cloak = 0x0f,
25 | gloves = 0x10,
26 | ucont = 0x11,
27 | // The following four entries are not actual spots, but mark an object as
28 | // filling multiple spots of the given type.
29 | both_hands = 0x12, // Uses both hands.
30 | lrgloves = 0x13, // Uses gloves spot, fills ring.
31 | neck = 0x14, // Uses amulet spot, fills cloak.
32 | // Used for alternate slot only:
33 | scabbard = 0x15, // Uses belt spot, fills back_2h, back_shield.
34 | // Marks as firing triple crossbow bolts:
35 | triple_bolts = 0x16,
36 | // Used for paperdolling only:
37 | cloak_clasp = 102;
38 |
39 | // Black Gate Ready types
40 | public static final int // enum Ready_type_BG
41 | backpack_bg = 0x00,
42 | lhand_bg = 0x01,
43 | rhand_bg = 0x02, // Only for usecode or for alternate slot
44 | belt_bg = 0x03, // Only for usecode or for alternate slot
45 | neck_bg = 0x04,
46 | torso_bg = 0x05,
47 | lfinger_bg = 0x06,
48 | rfinger_bg = 0x07, // Only for usecode or for alternate slot
49 | quiver_bg = 0x08,
50 | head_bg = 0x09,
51 | legs_bg = 0x0a,
52 | feet_bg = 0x0b,
53 | ucont_bg = 0x0c, // Porting from SI
54 | cloak_bg = 0x0d, // Porting from SI
55 | gloves_bg = 0x0e, // Porting from SI
56 | triple_bolts_bg = 0x0f,
57 | earrings_bg = 0x10, // Porting from SI
58 | back_shield_bg = 0x11, // Porting from SI
59 | tongs_bg = 0x12, // Silently converted to lhand_bg
60 | back_2h_bg = 0x13, // Porting from SI
61 | both_hands_bg = 0x14,
62 | lrgloves_bg = 0x15,
63 | amulet_bg = 0x16,
64 | scabbard_bg = 0x17; // Only for alternate slot
65 | // Serpent Isle Ready types
66 | public static final int // enum Ready_type_SI
67 | rhand_si = 0x00,
68 | lhand_si = 0x01,
69 | cloak_si = 0x02,
70 | amulet_si = 0x03,
71 | head_si = 0x04,
72 | gloves_si = 0x05,
73 | ucont_si = 0x06,
74 | rfinger_si = 0x07, // Only for usecode or for alternate slot
75 | lfinger_si = 0x08,
76 | earrings_si = 0x09,
77 | quiver_si = 0x0a,
78 | belt_si = 0x0b,
79 | torso_si = 0x0c,
80 | feet_si = 0x0d,
81 | legs_si = 0x0e,
82 | backpack_si = 0x0f,
83 | back_shield_si = 0x10, // Only for usecode or for alternate slot
84 | back_2h_si = 0x11, // Only for usecode or for alternate slot
85 | triple_bolts_si = 0x12, // Porting from BG
86 | both_hands_si = 0x14,
87 | lrgloves_si = 0x15, // Porting from BG
88 | neck_si = 0x16,
89 | scabbard_si = 0x17; // Only for alternate slot
90 | /*
91 | * Convert to BG ready spot # from ours (or -1 if not found).
92 | */
93 |
94 | public static int spotToBG(int spot) {
95 | switch (spot)
96 | {
97 | case head: return head_bg;
98 | case backpack: return backpack_bg;
99 | case belt: return belt_bg;
100 | case lhand: return lhand_bg;
101 | case lfinger: return lfinger_bg;
102 | case legs: return legs_bg;
103 | case feet: return feet_bg;
104 | case rfinger: return rfinger_bg;
105 | case rhand: return rhand_bg;
106 | case torso: return torso_bg;
107 | case amulet: return amulet_bg;
108 | case quiver: return quiver_bg;
109 | case back_2h: return back_2h_bg;
110 | case back_shield: return back_shield_bg;
111 | case earrings: return earrings_bg;
112 | case cloak: return cloak_bg;
113 | case gloves: return gloves_bg;
114 | case ucont: return ucont_bg;
115 | case both_hands: return both_hands_bg;
116 | case lrgloves: return lrgloves_bg;
117 | case triple_bolts: return triple_bolts_bg;
118 | case scabbard: return scabbard_bg;
119 | case neck: return neck_bg;
120 | default: return -1;
121 | }
122 | }
123 | /*
124 | * Convert to SI ready spot # from ours (or -1 if not found).
125 | */
126 | public static int spotToSI(int spot) {
127 | switch (spot)
128 | {
129 | case head: return head_si;
130 | case backpack: return backpack_si;
131 | case belt: return belt_si;
132 | case lhand: return lhand_si;
133 | case lfinger: return lfinger_si;
134 | case legs: return legs_si;
135 | case feet: return feet_si;
136 | case rfinger: return rfinger_si;
137 | case rhand: return rhand_si;
138 | case torso: return torso_si;
139 | case amulet: return amulet_si;
140 | case quiver: return quiver_si;
141 | case back_2h: return back_2h_si;
142 | case back_shield: return back_shield_si;
143 | case earrings: return earrings_si;
144 | case cloak: return cloak_si;
145 | case gloves: return gloves_si;
146 | case ucont: return ucont_si;
147 | case both_hands: return both_hands_si;
148 | case lrgloves: return lrgloves_si;
149 | case triple_bolts: return triple_bolts_si;
150 | case scabbard: return scabbard_si;
151 | case neck: return neck_si;
152 | default: return -1;
153 | }
154 | }
155 | /*
156 | * Convert from BG ready spot # to ours (or -1 if not found).
157 | */
158 |
159 | public static int spotFromBG(int spot) {
160 | switch (spot)
161 | {
162 | case head_bg: return head;
163 | case backpack_bg: return backpack;
164 | case belt_bg: return belt;
165 | case lhand_bg: return lhand;
166 | case lfinger_bg: return lfinger;
167 | case legs_bg: return legs;
168 | case feet_bg: return feet;
169 | case rfinger_bg: return rfinger;
170 | case rhand_bg: return rhand;
171 | case torso_bg: return torso;
172 | case amulet_bg: return amulet;
173 | case quiver_bg: return quiver;
174 | case back_2h_bg: return back_2h;
175 | case back_shield_bg: return back_shield;
176 | case earrings_bg: return earrings;
177 | case cloak_bg: return cloak;
178 | case gloves_bg: return gloves;
179 | case ucont_bg: return ucont;
180 | case both_hands_bg: return both_hands;
181 | case lrgloves_bg: return lrgloves;
182 | case triple_bolts_bg: return triple_bolts;
183 | case tongs_bg: return lhand;
184 | case scabbard_bg: return scabbard;
185 | case neck_bg: return neck;
186 | default: return -1;
187 | }
188 | }
189 | /*
190 | * Convert from SI ready spot # to ours (or -1 if not found).
191 | */
192 | public static int spotFromSI(int spot)
193 | {
194 | switch (spot)
195 | {
196 | case head_si: return head;
197 | case backpack_si: return backpack;
198 | case belt_si: return belt;
199 | case lhand_si: return lhand;
200 | case lfinger_si: return lfinger;
201 | case legs_si: return legs;
202 | case feet_si: return feet;
203 | case rfinger_si: return rfinger;
204 | case rhand_si: return rhand;
205 | case torso_si: return torso;
206 | case amulet_si: return amulet;
207 | case quiver_si: return quiver;
208 | case back_2h_si: return back_2h;
209 | case back_shield_si: return back_shield;
210 | case earrings_si: return earrings;
211 | case cloak_si: return cloak;
212 | case gloves_si: return gloves;
213 | case ucont_si: return ucont;
214 | case both_hands_si: return both_hands;
215 | case lrgloves_si: return lrgloves;
216 | case triple_bolts_si: return triple_bolts;
217 | case scabbard_si: return scabbard;
218 | case neck_si: return neck;
219 | default: return -1;
220 | }
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/src/com/exult/android/Rectangle.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class Rectangle {
4 | public int x, y, w, h;
5 | public Rectangle(int xin, int yin, int win, int hin) {
6 | x = xin; y = yin; w = win; h = hin;
7 | }
8 | public Rectangle(Rectangle r) {
9 | x = r.x; y = r.y; w = r.w; h = r.h;
10 | }
11 | public Rectangle() {
12 | x = y = w = h = -1;
13 | }
14 | public final void set(int xx, int yy, int ww, int hh) {
15 | x = xx; y = yy; w = ww; h = hh;
16 | }
17 | public final void set(Rectangle r) {
18 | x = r.x; y = r.y; w = r.w; h = r.h;
19 | }
20 | @Override
21 | public String toString() {
22 | return "Rect("+ x + "," + y + "," + w + "," + h + ")";
23 | }
24 | public final boolean hasPoint(int px, int py) {
25 | return (px >= x && px < x + w && py >= y && py < y + h);
26 | }
27 | public final void enlarge(int left, int right, int top, int bottom, int maxw, int maxh) {
28 | x -= left; w += left+right;
29 | y -= top; h += top+bottom;
30 |
31 | if (x < 0) { w += x; x = 0; }
32 | if (y < 0) { h += y; y = 0; }
33 |
34 | if (x + w > maxw) w = maxw - x;
35 | if (y + h > maxh) h = maxh - y;
36 | }
37 | public void shift(int deltax, int deltay) {
38 | x += deltax;
39 | y += deltay;
40 | }
41 | public final void enlarge(int delta) {
42 | x -= delta; y -= delta; w += 2*delta; h += 2*delta;
43 | }
44 | public final int distance(int px, int py) { // Get distance from a point (max.
45 | // dist. along x or y coord.)
46 | int xdist = px <= x ? (x - px) : (px - x - w + 1);
47 | int ydist = py <= y ? (y - py) : (py - y - h + 1);
48 | int dist = xdist > ydist ? xdist : ydist;
49 | return dist < 0 ? 0 : dist;
50 | }
51 | // Does it intersect another?
52 | public boolean intersects(Rectangle r2) {
53 | return (x >= r2.x + r2.w ? false : r2.x >= x + w ? false :
54 | y >= r2.y + r2.h ? false : r2.y >= y + h ? false : true);
55 | }
56 | // Intersect another with this.
57 | public final void intersect(Rectangle r2) {
58 | int xend = x + w, yend = y + h;
59 | int xend2 = r2.x + r2.w, yend2 = r2.y + r2.h;
60 | x = x >= r2.x ? x : r2.x;
61 | y = y >= r2.y ? y : r2.y;
62 | w = (xend <= xend2 ? xend : xend2) - x;
63 | h = (yend <= yend2 ? yend : yend2) - y;
64 | }
65 | public final void add(Rectangle r2) {
66 | int xend = x + w, yend = y + h;
67 | int xend2 = r2.x + r2.w, yend2 = r2.y + r2.h;
68 | x = x < r2.x ? x : r2.x;
69 | y = y < r2.y ? y : r2.y;
70 | w = (xend > xend2 ? xend : xend2) - x;
71 | h = (yend > yend2 ? yend : yend2) - y;
72 | }
73 | public final boolean equals(Rectangle r2) {
74 | return x == r2.x && y == r2.y && w == r2.w && h == r2.h;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/com/exult/android/Shape.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.RandomAccessFile;
3 | import java.io.IOException;
4 | import java.lang.ref.WeakReference;
5 |
6 | public class Shape {
7 | private WeakReference raw; // Entire shape from file.
8 | protected ShapeFrame frames[]; // List of ->'s to frames.
9 | protected int numFrames; // # of frames (not counting reflects).
10 | private boolean fromPatch;
11 | /*
12 | * Resize list upwards.
13 | */
14 | private void enlarge(int newsize)
15 | {
16 | ShapeFrame newframes[] = new ShapeFrame[newsize];
17 | System.arraycopy(frames, 0, newframes, 0, frames.length);
18 | frames = newframes;
19 | }
20 | private void createFramesList(int nframes) {
21 | numFrames = nframes;
22 | frames = new ShapeFrame[nframes];
23 | }
24 | private ShapeFrame read(DataSource files[], boolean patch_flags[], int counts[],
25 | int shnum, int frnum, int srcnum) {
26 | DataSource shpfile = null;
27 | // Figure offset in "shapes.vga".
28 | int shapeoff = 0x80 + shnum*8;
29 | int shapelen = 0;
30 |
31 | // Check backwards for the shape file to use.
32 | int i = counts.length - 1;
33 | if (srcnum < 0) {
34 | for ( ; i >= 0; --i) {
35 | if (shnum < counts[i]) {
36 | DataSource ds = files[i];
37 | try {
38 | ds.seek(shapeoff);
39 | } catch (IOException e) {
40 | continue;
41 | }
42 | // Get location, length.
43 | int s = EUtil.Read4(ds);
44 | shapelen = EUtil.Read4(ds);
45 | if (s > 0 && shapelen> 0) {
46 | shapeoff = s;
47 | shpfile = ds;
48 | fromPatch = patch_flags[i];
49 | break;
50 | }
51 | }
52 | }
53 | } else if (shnum < counts[srcnum]) {
54 | DataSource ds = files[srcnum];
55 | try {
56 | ds.seek(shapeoff);
57 | } catch (IOException e) {
58 | return null;
59 | }
60 | // Get location, length.
61 | int s = EUtil.Read4(ds);
62 | shapelen = EUtil.Read4(ds);
63 | if (s > 0 && shapelen> 0) {
64 | shapeoff = s;
65 | shpfile = ds;
66 | fromPatch = patch_flags[i];
67 | }
68 | }
69 | // The shape was not found anywhere, so leave.
70 | if (shpfile == null) {
71 | // std::cerr << "Shape num out of range: " << shapenum << std::endl;
72 | return null;
73 | }
74 | if (shapelen == 0)
75 | return null; // Empty shape.
76 | // Read it in and get frame count.
77 | ShapeFrame frame = new ShapeFrame();
78 | int nframes;
79 | try {
80 | byte data[];
81 | if (raw == null || (data = raw.get()) == null) {
82 | data = new byte[shapelen];
83 | raw = new WeakReference(data);
84 | shpfile.seek(shapeoff);
85 | shpfile.read(data);
86 | }
87 | nframes = frame.read(data, shapelen, frnum);
88 | } catch (IOException e) {
89 | return null;
90 | }
91 | if (numFrames== 0) // 1st time?
92 | createFramesList(nframes);
93 | if (!frame.isRle())
94 | frnum &= 31; // !!Guessing.
95 | if (frnum >= nframes && // Compare against #frames in file.
96 | (frnum&32) != 0) { // Reflection desired?
97 | return (reflect(files, patch_flags, counts, shnum, frnum&0x1f));
98 | }
99 | return storeFrame(frame, frnum);
100 | }
101 | /*
102 | * Store frame that was read.
103 | *
104 | * Output: ->frame, or 0 if not valid.
105 | */
106 | private ShapeFrame storeFrame
107 | (
108 | ShapeFrame frame, // Frame that was read.
109 | int frnum // It's frame #.
110 | )
111 | {
112 | if (frnum < 0 || frnum >= frames.length) { // Something fishy?
113 | //cerr << "Shape::store_frame: framenum < 0 ("
114 | // << framenum << " >= " << (unsigned int)(frames_size)
115 | // << ")" << endl;
116 | return (null);
117 | }
118 | if (frames == null) { // First one?
119 | frames = new ShapeFrame[numFrames];
120 | }
121 | frames[frnum] = frame;
122 | return (frame);
123 | }
124 | /*
125 | * Load all frames for a single shape. (Assumes RLE-type shape.)
126 | */
127 | protected void load(byte data[]) {
128 | ShapeFrame frame = new ShapeFrame();
129 | // Read frame 0 & get frame count.
130 | createFramesList(frame.read(data, data.length, 0));
131 | storeFrame(frame, 0);
132 | // Get the rest.
133 | for (int i = 1; i < frames.length; i++) {
134 | frame = new ShapeFrame();
135 | frame.read(data, data.length, i);
136 | storeFrame(frame, i);
137 | }
138 | }
139 | protected void load(RandomAccessFile shapeSource) throws IOException {
140 | int shapelen = EUtil.Read4(shapeSource);
141 | byte data[] = new byte[shapelen];
142 | shapeSource.seek(0);
143 | shapeSource.read(data);
144 | load(data);
145 | }
146 | protected void load(DataSource shapeSource) throws IOException {
147 | int shapelen = EUtil.Read4(shapeSource);
148 | byte data[] = new byte[shapelen];
149 | shapeSource.seek(0);
150 | shapeSource.read(data);
151 | load(data);
152 | }
153 | /*
154 | * Create the reflection of a shape.
155 | */
156 | private ShapeFrame reflect(DataSource files[], boolean patch_flags[], int counts[],
157 | int shnum, int frnum) {
158 | // Get normal frame.
159 | ShapeFrame normal = get(files, patch_flags, counts, shnum, frnum, -1);
160 | if (normal == null)
161 | return (null);
162 | // Reflect it.
163 | ShapeFrame reflected = normal.reflect();
164 | if (reflected == null)
165 | return (null);
166 | frnum |= 32; // Put back 'reflect' flag.
167 | if (frnum >= frames.length - 1)// Expand list if necessary.
168 | enlarge(frnum + 1);
169 | frames[frnum] = reflected; // Store new frame.
170 | return reflected;
171 | }
172 | public Shape() {
173 | frames = null;
174 | numFrames = 0;
175 | fromPatch = false;
176 | }
177 | /*
178 | * Create with given # of frames.
179 | */
180 | public Shape(int n) {
181 | fromPatch = false;
182 | createFramesList(n);
183 | }
184 | public Shape(ShapeFrame fr) {
185 | fromPatch = false;
186 | numFrames = 1;
187 | frames = new ShapeFrame[1];
188 | frames[0] = fr;
189 | }
190 | public int getNumFrames() {
191 | return numFrames;
192 | }
193 | public boolean isFromPatch() {
194 | return fromPatch;
195 | }
196 | public ShapeFrame getFrame(int framenum) {
197 | return 0 <= framenum && framenum < frames.length
198 | ? frames[framenum] : null;
199 | }
200 | public ShapeFrame get(DataSource files[], boolean patch_flags[], int counts[],
201 | int shnum, int frnum, int srcnum) {
202 | return (frames != null && frnum < frames.length &&
203 | frames[frnum] != null) ? frames[frnum] :
204 | read(files, patch_flags, counts, shnum, frnum, srcnum);
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/src/com/exult/android/ShapeFiles.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public enum ShapeFiles {
4 | SHAPES_VGA,
5 | GUMPS_VGA,
6 | PAPERDOL,
7 | SPRITES_VGA,
8 | FACES_VGA,
9 | EXULT_FLX,
10 | GAME_FLX;
11 |
12 | private VgaFile file;
13 | ShapeFiles() {
14 | file = null;
15 | }
16 | public final VgaFile getFile() {
17 | return file;
18 | }
19 | public ShapeFrame getShape(int shapenum, int framenum) {
20 | return file.getShape(shapenum, framenum);
21 | }
22 | public static final void load() {
23 | SHAPES_VGA.file = new ShapesVgaFile(EFile.SHAPES_VGA, EFile.PATCH_SHAPES);
24 | FACES_VGA.file = new VgaFile(EFile.FACES_VGA, EFile.PATCH_FACES);
25 | GUMPS_VGA.file = new VgaFile(EFile.GUMPS_VGA, EFile.PATCH_GUMPS);
26 | SPRITES_VGA.file = new VgaFile(EFile.SPRITES_VGA, EFile.PATCH_SPRITES);
27 | if (EUtil.U7exists(EFile.EXULT_FLX) == null)
28 | ExultActivity.fileFatal(EFile.EXULT_FLX);
29 | EXULT_FLX.file = new VgaFile(EFile.EXULT_FLX, EFile.BUNDLE_EXULT_FLX);
30 | GAME_FLX.file = GameSingletons.game.isBG()
31 | ? new VgaFile(EFile.EXULT_BG_FLX, EFile.BUNDLE_EXULT_BG_FLX)
32 | : new VgaFile(EFile.EXULT_SI_FLX, EFile.BUNDLE_EXULT_SI_FLX);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/com/exult/android/ShapeID.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class ShapeID extends GameSingletons {
4 | private short shapeNum; // Shape #.
5 | private byte frameNum; // Frame # within shape.
6 | private byte hasTrans;
7 | private ShapeFiles shapeFile;
8 | private ShapeFrame shape;
9 | private static boolean canHavePaperdolls; // Set true if the SI paperdoll file
10 | // is found when playing BG
11 | private static boolean paperdollsEnabled; // True if paperdolls are on.
12 | private static boolean gotSiShapes; // Set true if the SI shapes file
13 | // is found when playing BGXformPalette xforms[];
14 | private static ImageBuf.XformPalette xforms[];
15 | private static ImageBuf.XformPalette invisXform; // For showing invisible NPC's.
16 | public static final int // Special pixels
17 | POISON_PIXEL = 0, PROTECT_PIXEL = 1, CURSED_PIXEL = 2,
18 | CHARMED_PIXEL = 3, HIT_PIXEL = 4, PARALYZE_PIXEL = 5, NPIXCOLORS = 6;
19 | private static byte specialPixels[];
20 | // Shape_info *info;
21 |
22 | private ShapeFrame cacheShape() {
23 | if (frameNum == -1) return null;
24 |
25 | if (hasTrans != 2) hasTrans = 0;
26 | if (shapeFile == ShapeFiles.SHAPES_VGA) {
27 | shape = shapeFile.getFile().getShape(shapeNum, frameNum);
28 | if (hasTrans != 2)
29 | hasTrans = getInfo(shapeNum).hasTranslucency() ? (byte)1 : (byte)0;
30 |
31 | } else if (shapeFile != null) {
32 | shape = shapeFile.getFile().getShape(shapeNum, frameNum);
33 | if (shapeFile == ShapeFiles.SPRITES_VGA)
34 | hasTrans = 1;
35 | } else {
36 | // std::cerr << "Error! Wrong ShapeFile!" << std::endl;
37 | return null;
38 | }
39 | return shape;
40 | }
41 | public final void set(int shnum, int frnum, ShapeFiles shfile) {
42 | shapeNum = (short)shnum; frameNum = (byte)frnum;
43 | hasTrans = 0;
44 | shape = null;
45 | shapeFile = shfile;
46 | }
47 | public ShapeID(int shnum, int frnum, ShapeFiles shfile) {
48 | set(shnum, frnum, shfile);
49 | }
50 | public ShapeID(int shnum, int frnum) {
51 | set(shnum, frnum, ShapeFiles.SHAPES_VGA);
52 | }
53 | public ShapeID() {
54 | set(0,0, null);
55 | }
56 | public final boolean isInvalid()
57 | { return shapeNum == -1; }
58 |
59 | public final int getShapeNum()
60 | { return shapeNum; }
61 | public final int getFrameNum()
62 | { return frameNum; }
63 | public final ShapeFiles getShapeFile()
64 | { return shapeFile; }
65 | public final ShapeFrame getShape()
66 | { return (shape!=null)?shape:cacheShape(); }
67 | public final ShapeInfo getInfo() {
68 | return ShapesVgaFile.getInfo(shapeNum);
69 | }
70 | public static final ShapeInfo getInfo(int shnum) {
71 | return ShapesVgaFile.getInfo(shnum);
72 | }
73 | public final void set_translucent(int trans)
74 | { hasTrans = (byte)trans; }
75 | public final boolean isTranslucent()
76 | { if (shape==null) cacheShape(); return hasTrans!=0; }
77 | // Set to given shape.
78 | public final void setShape(int shnum, int frnum) {
79 | shapeNum = (short)shnum;
80 | frameNum = (byte)frnum;
81 | shape = null;
82 | //info = null;
83 | }
84 | public final void setShape(int shnum) // Set shape, but keep old frame #.
85 | { shapeNum = (short)shnum; shape = null; /* info = 0; */ }
86 | public final void setFrame(int frnum) // Set to new frame.
87 | { frameNum = (byte)frnum; shape = null; }
88 | public final void setFile(ShapeFiles shfile) // Set to new flex
89 | { shapeFile = shfile; shape = null; }
90 | public final int getNumFrames() {
91 | if (shapeFile != null)
92 | return shapeFile.getFile().getNumFrames(shapeNum);
93 | else
94 | return 0;
95 | }
96 | public static final byte getSpecialPixel(int pix) {
97 | return specialPixels[pix];
98 | }
99 | // BG Only
100 | public static boolean canUsePaperdolls()
101 | { return canHavePaperdolls; }
102 |
103 | public static boolean arePaperdollsEnabled()
104 | { return paperdollsEnabled; }
105 |
106 | public static void setPaperdollStatus(boolean p)
107 | { paperdollsEnabled = p; }
108 |
109 | public static boolean haveSiShapes()
110 | { return gotSiShapes; }
111 | public static void paintShapeTranslucent(ShapeFrame s, int xoff, int yoff) {
112 | if (s != null) {
113 | if (xforms != null) {
114 | s.paintRleTranslucent(gwin.getWin(), xoff, yoff, xforms);
115 | } else {
116 | s.paint(gwin.getWin(), xoff, yoff);
117 | }
118 | }
119 | }
120 | public void paintShapeTranslucent(int xoff, int yoff) {
121 | ShapeFrame s = getShape();
122 | paintShapeTranslucent(s, xoff, yoff);
123 | }
124 | public void paintShape(int xoff, int yoff) {
125 | ShapeFrame s = getShape();
126 | if (s != null) {
127 | if (hasTrans != 0 && xforms != null) {
128 | s.paintRleTranslucent(gwin.getWin(), xoff, yoff, xforms);
129 | } else {
130 | s.paint(gwin.getWin(), xoff, yoff);
131 | }
132 | }
133 | }
134 | public static void paintInvisible(ShapeFrame s, int xoff, int yoff) {
135 | s.paintRleTransformed(gwin.getWin(), xoff, yoff, invisXform);
136 | }
137 | void paintInvisible(int xoff, int yoff) {
138 | ShapeFrame s = getShape();
139 | if (s != null) {
140 | s.paintRleTransformed(gwin.getWin(), xoff, yoff, invisXform);
141 | }
142 | }
143 | public void paintOutline(int xoff, int yoff, int pix) {
144 | ShapeFrame s = getShape();
145 | if (s != null) {
146 | s.paintRleOutline(gwin.getWin(), xoff, yoff, specialPixels[pix]);
147 | }
148 | }
149 | /*
150 | * Load static/global data.
151 | */
152 | public static void loadStatic() {
153 | EFile xf = fman.getFileObject(EFile.XFORMTBL, EFile.PATCH_XFORMS);
154 | int nxforms = 17; // FOR NOW.
155 | if (xf != null) {
156 | int nobjs = xf.numberOfObjects();
157 | if (nobjs > nxforms)
158 | nobjs = nxforms;
159 | xforms = new ImageBuf.XformPalette[nobjs];
160 | for (int i = 0; i < nobjs; ++i) {
161 | xforms[nxforms - 1 - i] = new ImageBuf.XformPalette();
162 | byte data[] = xf.retrieve(i);
163 | if (data == null) {
164 | // No XForm data at all. Make this XForm into an
165 | // identity transformation.
166 | for (int j = 0; j < ImageBuf.XformPalette.NCOLORS; j++)
167 | xforms[nxforms - 1 - i].colors[j] = (byte)j;
168 | } else {
169 | System.arraycopy(data, 0, xforms[nxforms - 1 - i].colors, 0,
170 | ImageBuf.XformPalette.NCOLORS);
171 | }
172 | }
173 | invisXform = xforms[nxforms - 1 - 0]; // ->entry 0.
174 | xf.close();
175 | } else {
176 | xforms = null;
177 | }
178 | specialPixels = new byte[NPIXCOLORS];
179 | // Determine some colors based on the default palette
180 | Palette pal = new Palette(gwin.getWin());
181 | pal.load(EFile.PALETTES_FLX, EFile.PATCH_PALETTES, 0);
182 | // Get a bright green.
183 | specialPixels[POISON_PIXEL] = (byte)pal.findColor(4, 63, 4);
184 | // Get a light gray.
185 | specialPixels[PROTECT_PIXEL] = (byte)pal.findColor(62, 62, 55);
186 | // Yellow for cursed.
187 | specialPixels[CURSED_PIXEL] = (byte)pal.findColor(62, 62, 5);
188 | // Light blue for charmed.
189 | specialPixels[CHARMED_PIXEL] = (byte)pal.findColor(30, 40, 63);
190 | // Red for hit in battle.
191 | specialPixels[HIT_PIXEL] = (byte)pal.findColor(63, 4, 4);
192 | // Purple for paralyze.
193 | specialPixels[PARALYZE_PIXEL] = (byte)pal.findColor(49, 27, 49);
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/src/com/exult/android/ShapesVgaFile.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | /*
4 | * Represents THE 'shapes.vga' file.
5 | */
6 | public class ShapesVgaFile extends VgaFile {
7 | //UNUSED private boolean infoRead;
8 | private static ShapeInfo info[];
9 | private static ShapeInfo zinfo = new ShapeInfo(); //A fake one (all 0's).
10 | public ShapesVgaFile(
11 | String nm, // Path to file.
12 | String nm2 // Patch file, or null.
13 | ) {
14 | super(nm, nm2);
15 | info = new ShapeInfo[shapes.length];
16 | int gameType = GameSingletons.game.getGameType();
17 | ShapeInfo.read(this, info, gameType);
18 | zinfo.setReadyType((byte) (gameType == EConst.BLACK_GATE
19 | ? Ready.backpack : Ready.rhand));
20 | }
21 | public static ShapeInfo getInfo(int shapenum) {
22 | ShapeInfo s = shapenum >= 0 && shapenum < info.length ? info[shapenum] : zinfo;
23 | return s;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/com/exult/android/Shortcuts.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import android.app.Activity;
3 | import android.graphics.Point;
4 |
5 | public final class Shortcuts extends GameSingletons {
6 | // Get party member, with 0 = Avatar.
7 | private static Actor getPartyMember(int num) {
8 | int npc_num = 0; // Default to Avatar
9 | if (num > 0)
10 | npc_num = partyman.getMember(num - 1);
11 | return gwin.getNpc(npc_num);
12 | }
13 | public static void target() {
14 | Thread t = new Thread() {
15 | public void run() {
16 | GameObject t = ExultActivity.getTarget(new Point(-1, -1), mouse.getShortArrow(EConst.northeast));
17 | if (t != null)
18 | t.activate();
19 | }
20 | };
21 | t.start();
22 | }
23 | public static void combat() {
24 | gwin.toggleCombat();
25 | }
26 | /*
27 | * Show inventory page.
28 | */
29 | private static int inventoryPage = -1;
30 | public static void inv() {
31 | int party_count = partyman.getCount();
32 | int shapenum = game.getShape("gumps/statsdisplay");
33 | Actor actor;
34 | for(int i=0;i<=party_count;++i) {
35 | actor = getPartyMember(i);
36 | if (actor == null)
37 | continue;
38 |
39 | shapenum = actor.inventoryShapenum();
40 | // Check if this actor's inventory page is open or not
41 | if (gumpman.findGump(actor, shapenum) == null) {
42 | gumpman.addGump(actor, shapenum, true); //force showing inv.
43 | inventoryPage = i;
44 | return;
45 | }
46 | }
47 | inventoryPage = (inventoryPage+1)%(party_count+1);
48 | actor = getPartyMember(inventoryPage);
49 | if (actor != null) {
50 | actor.showInventory(); //force showing inv.
51 | }
52 | }
53 | /*
54 | * Show stats page.
55 | */
56 | private static int statsPage = -1;
57 | public static void stats() {
58 | int party_count = partyman.getCount();
59 | int shapenum = game.getShape("gumps/statsdisplay");
60 | Actor actor;
61 |
62 | for (int i=0;i<=party_count;++i) {
63 | actor = getPartyMember(i);
64 | if (actor == null)
65 | continue;
66 |
67 | // Check if this actor's stats page is open or not
68 | if (gumpman.findGump(actor, shapenum) == null) {
69 | gumpman.addGump(actor, shapenum, false); //force showing stats.
70 | statsPage = i;
71 | return;
72 | }
73 | }
74 | statsPage = (statsPage+1)%(party_count+1);
75 | actor = getPartyMember(statsPage);
76 | if (actor != null)
77 | gumpman.addGump(actor, game.getShape("gumps/statsdisplay"), false);
78 | }
79 | public static void feed() {
80 |
81 | }
82 | private static int zoomCount = 0;
83 | private static float zoomFactor = 1.0f;
84 | // Cycle through zooms.
85 | public static void zoom() {
86 | if (zoomFactor > 1.0f) {
87 | clearZoom();
88 | return;
89 | }
90 | synchronized(win) {
91 | zoomCount = (zoomCount + 1)%4;
92 | int w = EConst.c_game_w/(zoomCount + 1), h = EConst.c_game_h/(zoomCount + 1);
93 | int x = (EConst.c_game_w - w)/2, y = (EConst.c_game_h - h)/2;
94 | System.out.printf("Zoom: %1$d,%2$d,%3$d,%4$d\n", x, y, w, h);
95 | win.setZoom(x, y, w, h);
96 | }
97 | gwin.setPainted();
98 | }
99 | public static float getZoomFactor() {
100 | return zoomFactor;
101 | }
102 | // Zoom to given factor. Returns true if size changed.
103 | public static boolean zoom(float f) {
104 |
105 | if (f <= 1) {
106 | clearZoom();
107 | return true;
108 | } else {
109 | int oldw = win.getZoomWidth(), oldh = win.getZoomHeight();
110 | int w = (int) (EConst.c_game_w/f), h = (int) (EConst.c_game_h/f);
111 | if (Math.abs(w - oldw) > 10 || Math.abs(h - oldh) > 10) {
112 | synchronized(win) {
113 | int x = win.getZoomX() + (oldw - w)/2, y = win.getZoomY() + (oldh - h)/2;
114 | zoomCount = 0;
115 | if (win.setZoom(x, y, w, h))
116 | zoomFactor = f;
117 | gwin.setPainted();
118 | return true;
119 | }
120 | } else
121 | return false;
122 | }
123 | }
124 | public static void pan(float dx, float dy) {
125 | int deltax = (int)(dx*win.getZoomWidth()/win.getWidth());
126 | int deltay = (int)(dy*win.getZoomHeight()/win.getHeight());
127 | win.pan(deltax, deltay);
128 | gwin.setPainted();
129 | }
130 | private static void clearZoom() {
131 | synchronized(win) {
132 | System.out.println("clearZoom");
133 | zoomCount = 0;
134 | zoomFactor = 1.0f;
135 | win.setZoom(0, 0, EConst.c_game_w, EConst.c_game_h);
136 | gwin.setPainted();
137 | }
138 | }
139 | public static void save(Activity exult) {
140 | //new NewFileGump();
141 | new AndroidSave(exult);
142 | gwin.setAllDirty();
143 | }
144 | public static void quit() {
145 | ExultActivity.quit();
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/com/exult/android/SignGump.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class SignGump extends Gump.Modal {
4 | protected Rectangle textArea = new Rectangle();
5 | private String lines[];
6 | private boolean serpentine;
7 | public SignGump(int shapenum, int nlines) {
8 | super(shapenum);
9 | lines = new String[nlines];// THIS IS A HACK, but don't ask me why this is like this,
10 | if (game.isSI() && shapenum==49) {
11 | // check for avatar read here
12 | Actor avatar = gwin.getMainActor();
13 | if (!avatar.getFlag(GameObject.read))
14 | serpentine = true;
15 | shapenum = game.getShape("gumps/goldsign");
16 | initShape(shapenum, null);
17 | setPos(); // Recenter
18 | }
19 | if(shapenum==game.getShape("gumps/woodsign"))
20 | {
21 | textArea.set(0, 4, 196, 92);
22 | }
23 | else if(shapenum==game.getShape("gumps/tombstone"))
24 | {
25 | textArea.set(0, 8, 200, 112);
26 | }
27 | else if(shapenum==game.getShape("gumps/goldsign"))
28 | {
29 | if (game.isBG())
30 | textArea.set(0, 4, 232, 96);
31 | else // SI
32 | textArea.set(4, 4, 312, 96);
33 | }
34 | else if (shapenum==game.getShape("gumps/scroll"))
35 | textArea.set(48, 30, 146, 118);
36 | }
37 | public void addText(int line, String txt) {
38 | if (line < 0 || line >= lines.length)
39 | return;
40 | // check for avatar read here
41 | Actor avatar = gwin.getMainActor();
42 | if (!serpentine && avatar.getFlag(GameObject.read)) {
43 | for (int i = 0; i < txt.length(); i++) {
44 | if (txt.charAt(i) == 40) {
45 | lines[line] += 'T';
46 | lines[line] += 'H';
47 | } else if (txt.charAt(i) == 41) {
48 | lines[line] += 'E';
49 | lines[line] += 'E';
50 | } else if (txt.charAt(i) == 42) {
51 | lines[line] += 'N';
52 | lines[line] += 'G';
53 | } else if (txt.charAt(i) == 43) {
54 | lines[line] += 'E';
55 | lines[line] += 'A';
56 | } else if (txt.charAt(i) == 44) {
57 | lines[line] += 'S';
58 | lines[line] += 'T';
59 | } else if (txt.charAt(i) == '|') {
60 | lines[line] += ' ';
61 | } else if (txt.charAt(i) >= 'a')
62 | lines[line] += txt.charAt(i) - 32;
63 | else
64 | lines[line] += txt.charAt(i);
65 | }
66 | } else {
67 | lines[line] = txt;
68 | }
69 | }
70 | public void paint() {
71 | int font = 1; // Normal runes.
72 | if (getShapeNum() == game.getShape("gumps/goldsign")) {
73 | if (serpentine)
74 | font = 10;
75 | else
76 | font = 6; // Embossed.
77 | }
78 | else if (serpentine)
79 | font = 8;
80 | else if (getShapeNum() == game.getShape("gumps/tombstone"))
81 | font = 3;
82 | // Get height of 1 line.
83 | int lheight = fonts.getTextHeight(font);
84 | // Get space between lines.
85 | int num_lines = lines.length;
86 | int lspace = (textArea.h - num_lines*lheight)/(num_lines + 1);
87 | // Paint the gump itself.
88 | super.paint();
89 | int ypos = y + textArea.y; // Where to paint next line.
90 | for (int i = 0; i < num_lines; i++) {
91 | ypos += lspace;
92 | if (lines[i] == null)
93 | continue;
94 | fonts.paintText(font, lines[i],
95 | x + textArea.x +
96 | (textArea.w -
97 | fonts.getTextWidth(font, lines[i]))/2,
98 | ypos);
99 | ypos += lheight;
100 | }
101 | gwin.setPainted();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/com/exult/android/SliderGump.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import android.view.KeyEvent;
3 | import java.util.Observable;
4 | import java.util.Observer;
5 |
6 | public class SliderGump extends Gump.Modal {
7 | private Reporter reporter;
8 | protected int diamondx; // Rel. pos. where diamond is shown.
9 | protected static final short diamondy = 6;
10 | protected int min_val, max_val; // Max., min. values to choose from.
11 | protected int step_val; // Amount to step by.
12 | protected int val; // Current value.
13 | protected boolean dragging; // 1 if dragging the diamond.
14 | protected int prev_dragx; // Prev. x-coord. of mouse.
15 | protected int pushed_newval = -1; // For pressing on the slider.
16 | protected void setVal(int newval) { // Set to new value.
17 | val = newval;
18 | int xdist = xmax - xmin;
19 | if(max_val-min_val==0) {
20 | val=0;
21 | diamondx=xmin;
22 | } else
23 | diamondx = xmin + ((val - min_val)*xdist)/(max_val - min_val);
24 | }
25 | // Coords:
26 | protected static final short leftbtnx = 31, rightbtnx = 103, btny = 14;
27 | protected static final short xmin = 35, xmax = 93;
28 |
29 | protected ShapeID diamond; // Diamond
30 |
31 | public SliderGump(int mival, int mxval, int step, int defval, Observer c) {
32 | super(game.getShape("gumps/slider"));
33 | min_val = mival; max_val = mxval;
34 | step_val = step;
35 | val = defval;
36 | diamond = new ShapeID(game.getShape("gumps/slider_diamond"), 0, ShapeFiles.GUMPS_VGA);
37 | addCheckMark(6, 30);
38 | addElem(new SliderButton(this, leftbtnx, btny,
39 | game.getShape("gumps/slider_left"), true));
40 | addElem(new SliderButton(this, rightbtnx, btny,
41 | game.getShape("gumps/slider_right"), false));
42 | // Init. to middle value.
43 | if (defval < min_val)
44 | defval = min_val;
45 | else if (defval > max_val)
46 | defval = max_val;
47 | setVal(defval);
48 | reporter = new Reporter();
49 | reporter.addObserver(c);
50 | }
51 | public void setDone() { // Done from 'yes'/'no' button.
52 | reporter.setChanged();
53 | reporter.notifyObservers(this);
54 | }
55 | private static class Reporter extends Observable {
56 | public void setChanged() { super.setChanged(); }
57 | }
58 | public int getVal() // Get last value set.
59 | { return val; }
60 | // An arrow was clicked on.
61 | public void clickedLeftArrow() {
62 | moveDiamond(-step_val);
63 | }
64 | public void clickedRightArrow() {
65 | moveDiamond(step_val);
66 | }
67 | public void moveDiamond(int dir) {
68 | int newval = val;
69 | newval += dir;
70 | if (newval < min_val)
71 | newval = min_val;
72 | if (newval > max_val)
73 | newval = max_val;
74 |
75 | setVal(newval);
76 | paint();
77 | gwin.setPainted();
78 | }
79 | // Paint it and its contents.
80 | public void paint() {
81 | final int textx = 128, texty = 7;
82 | // Paint the gump itself.
83 | super.paint();
84 | // Paint red "checkmark".
85 | paintElems();
86 | // Paint slider diamond.
87 | diamond.paintShape(x + diamondx, y + diamondy);
88 | // Print value.
89 | gumpman.paintNum(val, x + textx, y + texty);
90 | gwin.setPainted();
91 | }
92 | @Override
93 | public void close() {
94 | super.close();
95 | setDone();
96 | done = true;
97 | }
98 | // Clicktracker
99 | @Override
100 | public void onDown(int mx, int my) {
101 | dragging = false;
102 | GumpWidget.Button btn = super.onButton(mx, my);
103 | if (btn != null)
104 | pushed = btn;
105 | else
106 | pushed = null;
107 | if (pushed != null) {
108 | if (!pushed.push(true))
109 | pushed = null;
110 | return;
111 | }
112 | // See if on diamond.
113 | ShapeFrame d_shape = diamond.getShape();
114 | if (d_shape.hasPoint(mx - (x + diamondx), my - (y + diamondy))) {
115 | // Start to drag it.
116 | dragging = true;
117 | prev_dragx = mx;
118 | } else {
119 | if(my-getY()diamondy+d_shape.getHeight())
120 | return;
121 | diamondx = mx-getX();
122 | if(diamondxxmax)
125 | diamondx = xmax;
126 | final int xdist = xmax - xmin;
127 | int delta = (diamondx - xmin)*(max_val - min_val)/xdist;
128 | // Round down to nearest step.
129 | delta -= delta%step_val;
130 | pushed_newval = min_val + delta;
131 | }
132 | }
133 | @Override
134 | public void onUp(int mx, int my) {
135 | int newval = pushed_newval;
136 | pushed_newval = -1;
137 | if (dragging) { // Done dragging?
138 | setVal(val); // Set diamond in correct pos.
139 | paint();
140 | gwin.setPainted();
141 | dragging = false;
142 | }
143 | if (pushed == null) {
144 | if (newval >= 0 && newval != val) {
145 | val = newval;
146 | paint();
147 | }
148 | return;
149 | }
150 | pushed.unpush(true);
151 | if (pushed.onButton(mx, my) != null)
152 | pushed.activate(true);
153 | pushed = null;
154 | }
155 | @Override
156 | public void keyDown(int chr) { // Character typed.
157 | switch(chr) {
158 | case KeyEvent.KEYCODE_ENTER:
159 | close();
160 | break;
161 | case KeyEvent.KEYCODE_DPAD_LEFT:
162 | clickedLeftArrow();
163 | break;
164 | case KeyEvent.KEYCODE_DPAD_RIGHT:
165 | clickedRightArrow();
166 | break;
167 | }
168 | }
169 |
170 | /*
171 | * One of the two arrow button on the slider:
172 | */
173 | public static class SliderButton extends GumpWidget.Button {
174 | boolean is_left;
175 | public
176 | SliderButton(Gump par, int px, int py, int shapenum, boolean left) {
177 | super(par, shapenum, px, py);
178 | is_left = left;
179 | }
180 | // What to do when 'clicked':
181 | public boolean activate(boolean button) {
182 | if (!button) return false;
183 | if (is_left)
184 | ((SliderGump) parent).clickedLeftArrow();
185 | else
186 | ((SliderGump) parent).clickedRightArrow();
187 | return true;
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/com/exult/android/StatsGump.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class StatsGump extends Gump {
4 | private static final short textx = 123;
5 | private static final short texty[] = {17, 26, 35, 46, 55, 67, 76, 86, 95, 104};
6 | // Some gump shape numbers:
7 | private static final int ASLEEP = 0, POISONED = 1, CHARMED = 2, HUNGRY = 3,
8 | PROTECTED = 4, CURSED = 5, PARALYZED = 6;
9 | private Actor actor;
10 | public StatsGump(Actor a, int initx, int inity) {
11 | super(game.getShape("gumps/statsdisplay"));
12 | actor = a;
13 | addCheckMark(6, 136);
14 | }
15 | public static StatsGump create(Actor npc, int x, int y) {
16 | return new StatsGump(npc, x, y);
17 | }
18 | public ContainerGameObject getContainer() {
19 | return actor;
20 | }
21 | public void paint() {
22 | GumpManager gman = gumpman;
23 | // Area to print name in.
24 | final int namex = 30, namey = 6, namew = 95;
25 | /* ++++++++++++FINISH
26 | if (gwin.getMainActor().getFlag(GameObject.freeze)) {
27 | int frame = act.getTemperatureZone();
28 | if (getNumFrames() < frame+1) // Prevent problems in BG.
29 | frame = getNumFrames()-1;
30 | if (frame < 0)
31 | frame = 0;
32 | setFrame(frame);
33 | }
34 | */
35 | // Paint the gump itself.
36 | super.paint();
37 | // Paint red "checkmark".
38 | paintElems();
39 | // Show statistics.
40 | String nm = actor.getName();
41 | fonts.paintText(2, nm, x + namex +
42 | (namew - fonts.getTextWidth(2, nm))/2, y + namey);
43 | gman.paintNum(actor.getEffectiveProp(Actor.strength),
44 | x + textx, y + texty[0]);
45 | gman.paintNum(actor.getEffectiveProp(Actor.dexterity),
46 | x + textx, y + texty[1]);
47 | gman.paintNum(actor.getEffectiveProp(Actor.intelligence),
48 | x + textx, y + texty[2]);
49 | gman.paintNum(actor.getEffectiveProp(Actor.combat),
50 | x + textx, y + texty[3]);
51 | gman.paintNum(actor.getProperty(Actor.magic),
52 | x + textx, y + texty[4]);
53 | gman.paintNum(actor.getProperty(Actor.health),
54 | x + textx, y + texty[5]);
55 | gman.paintNum(actor.getProperty(Actor.mana),
56 | x + textx, y + texty[6]);
57 | gman.paintNum(actor.getProperty(Actor.exp),
58 | x + textx, y + texty[7]);
59 | gman.paintNum(actor.getLevel(), x + textx, y + texty[8]);
60 | gman.paintNum(actor.getProperty(Actor.training),
61 | x + textx, y + texty[9]);
62 | // Now show atts. at bottom.
63 | final int attsy = 130, attsx0 = 29;
64 | int attsx = attsx0;
65 | if (actor.getFlag(GameObject.asleep))
66 | attsx += showAtts(x + attsx, y + attsy, ASLEEP);
67 | if (actor.getFlag(GameObject.poisoned))
68 | attsx += showAtts(x + attsx, y + attsy, POISONED);
69 | if (actor.getFlag(GameObject.charmed))
70 | attsx += showAtts(x + attsx, y + attsy, CHARMED);
71 | if (actor.getProperty((int) Actor.food_level) <= 4)
72 | attsx += showAtts(x + attsx, y + attsy, HUNGRY);
73 | if (actor.getFlag(GameObject.protection))
74 | attsx += showAtts(x + attsx, y + attsy, PROTECTED);
75 | if (actor.getFlag(GameObject.cursed))
76 | attsx += showAtts(x + attsx, y + attsy, CURSED);
77 | if (actor.getFlag(GameObject.paralyzed))
78 | attsx += showAtts(x + attsx, y + attsy, PARALYZED);
79 | }/*
80 | * Show one of the atts.
81 | *
82 | * Output: Amount to increment x-pos for the next one.
83 | */
84 | private static int showAtts
85 | (
86 | int x, int y, // Pos. on screen.
87 | int framenum
88 | ) {
89 | int shnum = game.getShape("gumps/statatts");
90 | ShapeFrame s = ShapeFiles.GUMPS_VGA.getShape(shnum, framenum);
91 | s.paint(gwin.getWin(), x + s.getXLeft(), y + s.getYBelow());
92 | return s.getWidth() + 2;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/com/exult/android/TerrainGameObject.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class TerrainGameObject extends GameObject {
4 | public TerrainGameObject(int shapenum, int framenum, int tilex,
5 | int tiley, int lft) {
6 | super(shapenum, framenum, tilex, tiley, lft);
7 | }
8 | public static class Animated extends TerrainGameObject {
9 | private Animator animator;
10 | public Animated(int shapenum, int framenum, int tilex, int tiley, int lft) {
11 | super(shapenum, framenum, tilex, tiley, lft);
12 | animator = Animator.create(this);
13 | }
14 | @Override
15 | public void removeThis() {
16 | super.removeThis();
17 | animator.delete();
18 | }
19 | @Override
20 | public void paint() {
21 | animator.wantAnimation(); // Be sure animation is on.
22 | super.paint();
23 | }
24 | // Get coord. where this was placed.
25 | @Override
26 | public void getOriginalTileCoord(Tile t) {
27 | getTile(t);
28 | t.tx -= animator.getDeltax();
29 | t.ty -= animator.getDeltay();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/com/exult/android/TextGump.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class TextGump extends Gump {
4 | protected String text;
5 | protected int textlen;
6 | protected int curtop; // Offset of top of current page.
7 | protected int curend; // Offset past end of current page(s).
8 | protected int font; // The shape in fonts.vga to use
9 |
10 | public TextGump(int shapenum) {
11 | super(shapenum);
12 | font = 4;
13 | }
14 | public TextGump(int shapenum, int fontnum) {
15 | super(shapenum);
16 | font = fontnum;
17 | }
18 | public void addText(String str) { // Append text.
19 | if (text == null)
20 | text = str;
21 | else {
22 | // Add a new-line marker if necessary.
23 | if (text.charAt(textlen- 1) != '*')
24 | text = text + '~';
25 | text = text + str;
26 | }
27 | textlen = text.length();
28 | }
29 | // Paint and return index pas end of displayed page.
30 | public int paintPage(int boxX, int boxY, int boxW, int boxH, int start) {
31 | int vlead = 1; // Extra inter-line spacing.
32 | int ypos = 0;
33 | int textheight = fonts.getTextHeight(font) + vlead;
34 | int ind = start;
35 | while (ind < textlen && text.charAt(ind) != '*' &&
36 | ypos + textheight <= boxH) {
37 | int chr = text.charAt(ind);
38 | if (chr == '~') { // Empty paragraph?
39 | ypos += textheight;
40 | ind++;
41 | continue;
42 | }
43 | // Look for page break.
44 | int epage = text.indexOf('*', ind);
45 | // Look for line break.
46 | int eol = text.indexOf('~', ind);
47 | int eolchr = 0;
48 | if (epage >= 0 && (eol < 0 || eol > epage))
49 | eol = epage;
50 | if (eol < 0) // No end found?
51 | eol = textlen;
52 | else
53 | eolchr = text.charAt(eol);
54 | int endoff = fonts.paintTextBox(gwin.getWin(),
55 | font, text, ind, eol, x + boxX,
56 | y + boxY + ypos, boxW, boxH - ypos, vlead, false, false);
57 | if (endoff > 0) { // All painted?
58 | // Value returned is height.
59 | ind = eol + ((eolchr == '~') ? 1 : 0);
60 | ypos += endoff;
61 | } else { // Out of room.
62 | ind += -endoff;
63 | break;
64 | }
65 | }
66 | if (ind < textlen && text.charAt(ind) == '*') // Saw end of page?
67 | ind++;
68 | gwin.setPainted(); // Force blit.
69 | System.out.println("End of paintPage()");
70 | return (ind); // Return offset past end.
71 | }
72 | // Next page of book/scroll.
73 | boolean showNextPage() {
74 | if (text == null || curend >= text.length())
75 | return false;
76 | curtop = curend;// Start next page or pair of pages.
77 | return true;
78 | }
79 | public static class Book extends TextGump {
80 | public Book() {
81 | super(game.getShape("gumps/book"));
82 | }
83 | public Book(int fontnum) {
84 | super(game.getShape("gumps/book"), fontnum);
85 | }
86 | public void paint() {
87 | // Paint the gump itself.
88 | super.paint();
89 | // Paint left page.
90 | curend = paintPage(36, 10, 122, 130, curtop);
91 | // Paint right page.
92 | curend = paintPage(174, 10, 122, 130, curend);
93 | }
94 | }
95 | public static class Scroll extends TextGump {
96 | public Scroll() {
97 | super(game.getShape("gumps/scroll"));
98 | }
99 | public Scroll(int fontnum) {
100 | super(game.getShape("gumps/scroll"), fontnum);
101 | }
102 | public void paint() {
103 | super.paint(); // The gump itself.
104 | curend = paintPage(52, 30, 142, 118, curtop);
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/com/exult/android/Tile.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | /*
4 | * 3D tile coordinate.
5 | */
6 | public final class Tile {
7 | private final int neighbors[] =
8 | {0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0, -1,-1 };
9 | public short tx, ty, tz;
10 | public void set(int x, int y, int z) {
11 | tx = (short)x; ty = (short)y; tz = (short)z;
12 | }
13 | public void set(Tile t) {
14 | tx = t.tx; ty = t.ty; tz = t.tz;
15 | }
16 | public Tile(int x, int y, int z) {
17 | tx = (short)x; ty = (short)y; tz = (short)z;
18 | }
19 | public Tile() {
20 | }
21 | public Tile(Tile s) {
22 | tx = s.tx; ty = s.ty; tz = s.tz;
23 | }
24 | @Override
25 | public String toString() {
26 | return "Tile("+ tx + "," + ty + "," + tz + ")";
27 | }
28 | @Override
29 | public boolean equals(Object o2) {
30 | Tile t2 = (Tile)o2;
31 | return t2.tx == tx && t2.ty == ty && t2.tz == tz;
32 | }
33 | @Override
34 | public int hashCode() {
35 | return ((tz << 24) + (ty << 12) + tx);
36 | }
37 | public static boolean gte(int t1, int t2) { // Ret t1 >= t2 with wrapping.
38 | int diff = t1 - t2;
39 | return diff >= 0 ? (diff < EConst.c_num_tiles/2) :
40 | diff < -EConst.c_num_tiles/2;
41 | }
42 | public static int fix(int x) {
43 | return (x+EConst.c_num_tiles)%EConst.c_num_tiles;
44 | }
45 | public final void fixme() {
46 | tx = (short)fix(tx); ty = (short)fix(ty);
47 | }
48 | public static int delta(int from, int to) {
49 | int diff = to - from;
50 | return diff >= EConst.c_num_tiles/2 ? (diff - EConst.c_num_tiles) :
51 | (diff <= -EConst.c_num_tiles/2 ? (diff + EConst.c_num_tiles) :
52 | diff);
53 | }
54 | public int distance(Tile t2) { // Distance to another tile?
55 | int delta = distance2d(t2);
56 | int dz = t2.tz - tz;
57 | if (dz < 0)
58 | dz = -dz;
59 | // Take larger abs. value.
60 | return (delta > dz ? delta : dz);
61 | }
62 | public int distance2d(int t2x, int t2y) {
63 | int dy = (t2y - ty + EConst.c_num_tiles)%EConst.c_num_tiles;
64 | int dx = (t2x - tx + EConst.c_num_tiles)%EConst.c_num_tiles;
65 | if (dy >= EConst.c_num_tiles/2)// World-wrapping.
66 | dy = EConst.c_num_tiles - dy;
67 | if (dx >= EConst.c_num_tiles/2)
68 | dx = EConst.c_num_tiles - dx;
69 | // Take larger abs. value.
70 | return (dy > dx ? dy : dx);
71 | }
72 | public int distance2d(Tile t2) { // For pathfinder.
73 | return distance2d(t2.tx, t2.ty);
74 | }
75 | public int squareDistanceScreenSpace(Tile t2) {
76 | int dy = (t2.ty - ty + EConst.c_num_tiles)%EConst.c_num_tiles;
77 | int dx = (t2.tx - tx + EConst.c_num_tiles)%EConst.c_num_tiles;
78 | int dz = t2.tz - tz;
79 | if (dy >= EConst.c_num_tiles/2)// World-wrapping.
80 | dy = EConst.c_num_tiles - dy;
81 | if (dx >= EConst.c_num_tiles/2)
82 | dx = EConst.c_num_tiles - dx;
83 | dx = dx*2-dz;
84 | dy = dy*2-dz;
85 | return (dx*dx + dy*dy)/4;
86 | }
87 | // Get neighbor in given dir (0-7) & set 't' to it.
88 | public void getNeighbor(Tile t, int dir) {
89 | t.set(
90 | (tx + neighbors[2*dir] + EConst.c_num_tiles)%EConst.c_num_tiles,
91 | (ty + neighbors[2*dir + 1] + EConst.c_num_tiles)%EConst.c_num_tiles,
92 | tz);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/com/exult/android/TimeQueue.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.util.LinkedList;
3 | import java.util.ListIterator;
4 |
5 | public class TimeQueue {
6 | private LinkedList entries = new LinkedList();
7 | private int pauseTime; // Time when paused.
8 | private int paused; // # calls to 'pause'.
9 | public static int ticks = 0;
10 | public static int tickMsecs = 10;
11 | /*
12 | * Remove all entries.
13 | */
14 | public void clear() {
15 | ListIterator it = entries.listIterator();
16 | while (it.hasNext()) {
17 | QueueEntry ent = it.next();
18 | TimeSensitive obj = ent.handler;
19 | it.remove();
20 | obj.removedFromQueue();
21 | }
22 | }
23 | /*
24 | * Add an entry to the queue.
25 | */
26 | public void add
27 | (
28 | int t, // When entry is to be activated.
29 | TimeSensitive obj, // Object to be added.
30 | Object ud // User data.
31 | ) {
32 | obj.addedToQueue(); // It's going in, no matter what.
33 | QueueEntry newent = new QueueEntry();;
34 | if (paused > 0 && !obj.alwaysHandle()) // Paused?
35 | // Messy, but we need to fix time.
36 | t -= ticks - pauseTime;
37 | newent.set(t, obj, ud);
38 | synchronized (entries) {
39 | if (entries.isEmpty()) {
40 | entries.addFirst(newent);
41 | return;
42 | }
43 | ListIterator it = entries.listIterator();
44 | while (it.hasNext()) {
45 | QueueEntry ent = it.next();
46 | if (newent.time < ent.time) {
47 | if (ent != it.previous()) { //
48 | System.out.println("TimeQueue.add: ERROR INSERTING!!!");
49 | } else
50 | it.add(newent);
51 | return;
52 | }
53 | }
54 | }
55 | entries.addLast(newent);
56 | }
57 | /*
58 | * Activate those entries marked 'always'.
59 | */
60 | public final void activateAlways(int ctime) {
61 | if (entries.isEmpty())
62 | return;
63 |
64 | boolean tryAgain = true;
65 | while (tryAgain) synchronized (entries) {
66 | ListIterator it = entries.listIterator();
67 | tryAgain = false;
68 | while (it.hasNext()) {
69 | QueueEntry ent = it.next();
70 | if (ctime < ent.time)
71 | return;
72 | TimeSensitive obj = ent.handler;
73 | if (obj.alwaysHandle()) {
74 | //System.out.println("tqueue.activateAlways: ent.time = " + ent.time + ", obj = " + obj.toString());
75 | obj.removedFromQueue();
76 | Object udata = ent.udata;
77 | it.remove();
78 | obj.handleEvent(ctime, udata);
79 | tryAgain = true;
80 | break; // So we don't crash on the iterator.
81 | }
82 | }
83 | }
84 | }
85 | /*
86 | * Remove and activate entries that are due.
87 | */
88 | public final void activate(int ctime) {
89 | if (paused > 0) {
90 | activateAlways(ctime);
91 | } else synchronized(entries) {
92 | while (!entries.isEmpty() && ctime >= entries.getFirst().time) {
93 | QueueEntry ent = entries.removeFirst();
94 | TimeSensitive obj = ent.handler;
95 | Object udata = ent.udata;
96 | obj.removedFromQueue();
97 | obj.handleEvent(ctime, udata);
98 | }
99 | }
100 | }
101 | public void pause(int ctime) { // Game paused.
102 | if (paused++ == 0)
103 | pauseTime = ctime;
104 | }
105 | public void pause() {
106 | pause(ticks);
107 | }
108 | public void resume(int ctime) {
109 | if (paused == 0 || --paused > 0) // Only unpause when stack empty.
110 | return; // Not paused.
111 | int diff = ctime - pauseTime;
112 | //System.out.println("tqueue.resume: ctime = " + ctime + ", pauseTime = " + pauseTime + ", diff = " + diff);
113 | pauseTime = 0;
114 | if (diff < 0) // Should not happen.
115 | return;
116 | synchronized(entries) {
117 | ListIterator it = entries.listIterator();
118 | while (it.hasNext()) {
119 | QueueEntry ent = it.next();
120 | if (!ent.handler.alwaysHandle()) {
121 | ent.time += diff; // Push entries ahead.
122 | //System.out.println("tqueue.resume: ent.time = " + ent.time);
123 | }
124 | }
125 | }
126 | }
127 | public void resume() {
128 | resume(ticks);
129 | }
130 | /*
131 | * Remove first entry containing a given object.
132 | */
133 | public boolean remove(TimeSensitive obj) {
134 | if (entries.isEmpty())
135 | return false;
136 | synchronized(entries) {
137 | ListIterator it = entries.listIterator();
138 | while (it.hasNext()) {
139 | QueueEntry ent = it.next();
140 | if (ent.handler == obj) {
141 | obj.removedFromQueue();
142 | it.remove();
143 | return true;
144 | }
145 | }
146 | }
147 | return false; // Not found.
148 | }
149 | /*
150 | * Find when an entry is due.
151 | *
152 | * Output: delay in msecs. when due, or -1 if not in queue.
153 | */
154 | public int findDelay(TimeSensitive obj, int ctime) {
155 | if (entries.isEmpty())
156 | return -1;
157 | ListIterator it = entries.listIterator();
158 | while (it.hasNext()) {
159 | QueueEntry ent = it.next();
160 | if (ent.handler==obj) {
161 | if (pauseTime != 0) // Watch for case when paused.
162 | ctime = pauseTime;
163 | int delay = ent.time - ctime;
164 | return delay >= 0 ? delay : 0;
165 | }
166 | }
167 | return -1;
168 | }
169 | public static class QueueEntry {
170 | TimeSensitive handler;
171 | Object udata; // Data to pass to handler.
172 | int time; // Time when due.
173 | void set(int t, TimeSensitive h, Object u) {
174 | time = t;
175 | handler = h;
176 | udata = u;
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/com/exult/android/TimeSensitive.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public interface TimeSensitive {
4 | public void handleEvent(int ctime, Object udata);
5 | public boolean alwaysHandle(); // Activate even if time is paused.
6 | public void addedToQueue();
7 | public void removedFromQueue();
8 |
9 | /* A simple timer that just needs handleEvent overridden. */
10 | public static class Timer extends GameSingletons implements TimeSensitive {
11 | protected int timeQueueCount;
12 | public boolean alwaysHandle() { // Activate even if time is paused.
13 | return false;
14 | }
15 | public void addedToQueue() {
16 | ++timeQueueCount;
17 | }
18 | public void removedFromQueue() {
19 | --timeQueueCount;
20 | }
21 | public boolean inQueue() {
22 | return timeQueueCount > 0;
23 | }
24 | public void handleEvent(int ctime, Object udata) {
25 |
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/com/exult/android/VgaFile.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.RandomAccessFile;
3 | import java.io.OutputStream;
4 | import java.io.IOException;
5 | import java.util.Vector;
6 |
7 | public class VgaFile {
8 | protected DataSource shapeSources[];
9 | protected boolean patchFlags[];
10 | protected int shapeCnts[];
11 | protected Shape shapes[];
12 | protected boolean flex; // False if this is a single-shape file.
13 |
14 | public VgaFile(
15 | String nm, // Path to file.
16 | String nm2 // Patch file, or null.
17 | ) {
18 | flex = true;
19 | load(nm, nm2);
20 | }
21 |
22 | public VgaFile() {
23 | flex = true;
24 | }
25 | protected void reset() {
26 | // Not sure if this is needed.
27 | }
28 | public int getNumShapes() {
29 | return shapes.length;
30 | }
31 | /*
32 | * Open file.
33 | */
34 | protected DataSource U7load
35 | (
36 | String resource,
37 | int resourceId,
38 | Vector tmpSources,
39 | boolean tmpPatch[]
40 | ) {
41 | DataSource source = null;
42 | Boolean isPatch = false;
43 | source = DataSource.create(resource, resourceId);
44 | isPatch = resource.regionMatches(0, "", 0, 7);
45 | if (source != null) {
46 | tmpSources.add(source);
47 | tmpPatch[tmpSources.size() - 1] = isPatch;
48 | }
49 | return source;
50 | }
51 | public boolean load(String sources[], int resourceIds[]) {
52 | reset();
53 | int count = sources.length;
54 | int num_shapes = 0;
55 | Vector tmpSources = new Vector(count);
56 | boolean tmpPatch[] = new boolean[count];
57 | int tmpCnts[] = new int[count];
58 |
59 | boolean is_good = true;
60 | if (EUtil.U7exists(sources[0]) == null)
61 | is_good = false;
62 | for (int i = 0; i < count; ++i) {
63 | DataSource source = U7load(sources[i], resourceIds == null ? -1 : resourceIds[i], tmpSources, tmpPatch);
64 | if (source != null) {
65 | flex = EUtil.isFlex(source);
66 | if (flex) {
67 | int cnt = 0;
68 | try {
69 | source.seek(0x54); // Get # of shapes.
70 | cnt = EUtil.Read4(source);
71 | num_shapes = num_shapes > cnt ? num_shapes : cnt;
72 | tmpCnts[tmpSources.size()-1] = cnt;
73 | } catch (IOException e) {
74 | is_good = false;
75 | }
76 | }
77 | }
78 | }
79 | if (tmpSources.size() == 0)
80 | return false; // ++throw exception?
81 | if (!flex) { // Just one shape, which we preload.
82 | num_shapes = 1;
83 | tmpCnts[0] = 1;
84 | shapes = new Shape[1];
85 | shapes[0] = new Shape();
86 | is_good = true;
87 | try {
88 | shapes[0].load(tmpSources.lastElement());
89 | } catch (IOException e) {
90 | is_good = false;
91 | }
92 | } else {
93 | shapes = new Shape[num_shapes];
94 | for (int i = 0; i < num_shapes; ++i)
95 | shapes[i] = new Shape();
96 | }
97 | count = tmpSources.size();
98 | shapeSources = new DataSource[count];
99 | for (int i = 0; i < count; ++i)
100 | shapeSources[i] = tmpSources.elementAt(i);
101 | patchFlags = new boolean[count];
102 | System.arraycopy(tmpPatch, 0, patchFlags, 0, count);
103 | shapeCnts = new int[count];
104 | System.arraycopy(tmpCnts, 0, shapeCnts, 0, count);
105 | return is_good;
106 | }
107 | protected boolean load(String nm, String nm2) {
108 | String src[] = new String[nm2 != null ? 2 : 1];
109 | src[0] = nm;
110 | if (nm2 != null)
111 | src[1] = nm2;
112 | return load(src, null);
113 | }
114 | public ShapeFrame getShape(int shapenum, int framenum) {
115 | ShapeFrame r;
116 | if (shapenum < 0 || shapenum >= shapes.length) {
117 | System.out.println("getShape outofbounds: " + shapenum + ", size = " + shapes.length);
118 | return null;
119 | }
120 | r = (shapes[shapenum].get(shapeSources, patchFlags, shapeCnts, shapenum, framenum, -1));
121 | return r;
122 | }
123 | public ShapeFrame getShape(int shapenum) {
124 | return getShape(shapenum, 0);
125 | }
126 | public int getNumFrames(int shapenum) {
127 | getShape(shapenum, 0); // Force it into memory.
128 | return shapes[shapenum].getNumFrames();
129 | }
130 |
131 | /*
132 | * A shape file just has one shape with multiple frames. They're all
133 | * read in during construction.
134 | */
135 | public static class ShapeFile extends Shape {
136 | public ShapeFile(byte data[]) {
137 | super.load(data);
138 | }
139 | public ShapeFile(String nm) {
140 | try {
141 | load(nm);
142 | } catch (IOException e) {
143 | System.out.println("ERROR loading " + nm);
144 | }
145 | }
146 | public ShapeFile(ShapeFrame fr) {
147 | super(fr);
148 | }
149 | /*
150 | ShapeFile(const char *nm);
151 |
152 | Shape_file(DataSource* out);
153 | */
154 | public void load(String nm) throws IOException {
155 | RandomAccessFile src = EUtil.U7open(nm, true);
156 | super.load(src);
157 | }
158 | public void load(RandomAccessFile src) throws IOException {
159 | super.load(src);
160 | }
161 | /* UNUSED
162 | private int getSize() {
163 | int size = 4;
164 | for (int i=0; i/" + fileName);
42 | if (EUtil.U7exists(fullName) == null) {
43 | ExultActivity.showToast("Can't find " + fullName);
44 | } else {
45 | tqueue.pause();
46 | mainView.setVisibility(View.INVISIBLE);
47 | gameView.setVisibility(View.INVISIBLE);
48 | video.setVisibility(View.VISIBLE);
49 | video.setVideoPath(fullName);
50 | video.start();
51 | }
52 | }
53 | public static boolean closeIfPlaying() {
54 | if (instance == null)
55 | return false;
56 | else {
57 | instance.close();
58 | return true;
59 | }
60 | }
61 | public void close() {
62 | instance = null;
63 | System.out.println("VideoPlayer.close");
64 | mainView.setVisibility(View.VISIBLE);
65 | gameView.setVisibility(View.VISIBLE);
66 | video.setVisibility(View.GONE);
67 | if (onCompleteThread != null)
68 | onCompleteThread.start();
69 | tqueue.resume();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/com/exult/android/VirtueStoneObject.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.io.OutputStream;
3 | import java.io.IOException;
4 |
5 | /*
6 | * A virtue stone can be set to a position on the map.
7 | */
8 | public class VirtueStoneObject extends IregGameObject {
9 | private Tile pos; // Position it teleports to.
10 | private int map; // Map to teleport to.
11 |
12 | public VirtueStoneObject(int shapenum, int framenum, int tilex,
13 | int tiley, int lft) {
14 | super(shapenum, framenum, tilex, tiley, lft);
15 | pos = new Tile();
16 | }
17 | public void setTargetPos(Tile t) // Set/get position.
18 | { pos.set(t); }
19 | // Set position from IREG data.
20 | public void setTargetPos(byte tilex, byte tiley, byte schunk, byte lft) {
21 | pos.tx = (short)((schunk%12)*EConst.c_tiles_per_schunk + tilex);
22 | pos.ty = (short)((schunk/12)*EConst.c_tiles_per_schunk + tiley);
23 | pos.tz = lift;
24 | }
25 | public Tile getTargetPos()
26 | { return pos; }
27 | public final int getTargetMap() // Get/set map.
28 | { return map; }
29 | public final void setTargetMap(int m)
30 | { map = m; }
31 | @Override // Write out to IREG file.
32 | public void writeIreg(OutputStream out) throws IOException {
33 | byte buf[] = new byte[20]; // 12-byte entry.
34 | int ind = writeCommonIreg(12, buf);
35 | // Write tilex, tiley.
36 | buf[ind++] = (byte)(pos.tx%EConst.c_tiles_per_schunk);
37 | buf[ind++] = (byte)(pos.ty%EConst.c_tiles_per_schunk);
38 | // Get superchunk index.
39 | int sx = pos.tx/EConst.c_tiles_per_schunk,
40 | sy = pos.ty/EConst.c_tiles_per_schunk;
41 | buf[ind++] = (byte)(sy*12 + sx); // Write superchunk #.
42 | buf[ind++] = (byte) pos.tz; // Finally, lift in entry[7].??Guess+++
43 | buf[ind++] = 0; // Entry[8] unknown.
44 | buf[ind++] = (byte)((getLift()&15)<<4); // Stone's lift in entry[9].
45 | buf[ind++] = (byte)map; // Entry[10]. Unknown; using to store map.
46 | buf[ind++] = 0; // Entry[11]. Unknown.
47 | out.write(buf, 0, ind);
48 | }
49 | @Override // Get size of IREG. Returns -1 if can't write to buffer
50 | public int getIregSize() {
51 | // These shouldn't ever happen, but you never know
52 | if (gumpman.findGump(this) != null || UsecodeScript.find(this) != null)
53 | return -1;
54 |
55 | return 8 + getCommonIregSize();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/com/exult/android/YesNoGump.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 | import java.util.Observable;
3 | import java.util.Observer;
4 | import android.view.KeyEvent;
5 |
6 | public class YesNoGump extends Gump.Modal {
7 | private static final short yesx = 63, yesnoy = 45, nox = 84; // Coords. of the buttons.
8 | private static final short areax = 6, areay = 5, areaw = 116, areah = 32;
9 | private Reporter reporter;
10 | private String text; // Text of question.
11 | private int font; // Font #.
12 | private boolean answer; // 1 for yes, 0 for no.
13 | public void setAnswer(boolean y) { // Done from 'yes'/'no' button.
14 | answer = y;
15 | reporter.setChanged();
16 | reporter.notifyObservers(this);
17 | close();
18 | }
19 | private static class Reporter extends Observable {
20 | public void setChanged() { super.setChanged(); }
21 | }
22 | private void init(String txt, String fontname) {
23 | text = txt;
24 | font = 2; // FOR NOW. Lookup fontname. Default is "SMALL_BLACK_FONT".
25 | }
26 | private YesNoGump(String txt) {
27 |
28 | super(game.getShape("gumps/yesnobox"));
29 | init(txt, null);
30 | addElem(new YesNoButton(this, yesx, yesnoy, true));
31 | addElem(new YesNoButton(this, nox, yesnoy, false));
32 | reporter = new Reporter();
33 | }
34 | boolean getAnswer()
35 | { return answer; }
36 | // Paint it and its contents.
37 | public void paint() {
38 | super.paint();
39 | // Paint text.
40 | fonts.paintTextBox(gwin.getWin(), font, text,
41 | x + areax, y + areay, areaw, areah, 2, false, false);
42 | gwin.setPainted();
43 | }
44 | // Clicktracker
45 | @Override
46 | public void onDown(int x, int y) {
47 | pushed = onButton(x, y);
48 | if (pushed != null)
49 | pushed.push(true); // Show it.
50 | }
51 | public void onUp(int mx, int my) {
52 | if (pushed != null) { // Pushing a button?
53 | pushed.unpush(true);
54 | if (pushed.onButton(mx, my) != null)
55 | pushed.activate(true);
56 | pushed = null;
57 | }
58 | }
59 | public void keyDown(int chr) { // Character typed.
60 | if (chr == 'y' || chr == 'Y' || chr == KeyEvent.KEYCODE_ENTER)
61 | setAnswer(true);
62 | else if (chr == 'n' || chr == 'N' || chr == KeyEvent.KEYCODE_BACK)
63 | setAnswer(false);
64 | }
65 | public static void ask(Observer c, String txt) { // Ask question, get answer.
66 | YesNoGump g = new YesNoGump(txt);
67 | g.reporter.addObserver(c);
68 | g.track(Mouse.hand);
69 | }
70 | /*
71 | * A 'yes' or 'no' button.
72 | */
73 | private class YesNoButton extends GumpWidget.Button {
74 | boolean isyes; // 1 for 'yes', 0 for 'no'.
75 | public YesNoButton(Gump par, int px, int py, boolean yes) {
76 | super(par, yes ?
77 | game.getShape("gumps/yesbtn")
78 | : game.getShape("gumps/nobtn"), px, py);
79 | isyes = yes;
80 | }
81 | // What to do when 'clicked':
82 | public boolean activate(boolean button) {
83 | if (!button)
84 | return false;
85 | ((YesNoGump) parent).setAnswer(isyes);
86 | return true;
87 | }
88 | };
89 | }
90 |
--------------------------------------------------------------------------------
/src/com/exult/android/ZombiePathFinder.java:
--------------------------------------------------------------------------------
1 | package com.exult.android;
2 |
3 | public class ZombiePathFinder extends PathFinder {
4 | private int major_distance; // Distance in tiles to go.
5 | private int major_frame_incr; // # steps to take in faster dir.
6 | private int cur[] = new int[3]; // Current pos. within world (x, y, z).
7 | private static final int X = 0, Y = 1, Z = 2;
8 | // Indices to cur.tx, cur.ty.
9 | int major_coord, minor_coord1, minor_coord2;
10 | // 1 or -1 for dir. along each axis.
11 | private int major_dir, minor_dir1, minor_dir2;
12 | private int major_delta, minor_delta1, minor_delta2;
13 | // For each tile we move along major
14 | // axis, we add 'minor_delta'. When
15 | // the sum >= 'major_delta', we move
16 | // 1 tile along minor axis, and
17 | // subtract 'major_delta' from sum.
18 | private int sum1, sum2; // Sum of 'minor_delta''s.
19 |
20 | public ZombiePathFinder() {
21 | major_frame_incr = 1;
22 | }
23 | @Override
24 | public boolean NewPath(Tile s, Tile d, Client ignored) {
25 | if (src == null)
26 | src = new Tile();
27 | if (dest == null)
28 | dest = new Tile();
29 | src.set(s);
30 | dest.set(d);
31 | cur[X] = s.tx; cur[Y] = s.ty; cur[Z] = s.tz;
32 | sum1 = sum2 = 0; // Clear accumulators.
33 | int deltax = Tile.delta(s.tx, d.tx);
34 | int deltay = Tile.delta(s.ty, d.ty);
35 | int deltaz = Tile.delta(s.tz, d.tz);
36 | if (deltax == 0 && deltay == 0 && deltaz == 0) { // Going nowhere?
37 | major_distance = 0;
38 | return false;
39 | }
40 | int abs_deltax, abs_deltay, abs_deltaz;
41 | int x_dir, y_dir, z_dir; // Figure directions.
42 | if (deltax >= 0) {
43 | abs_deltax = deltax; x_dir = 1;
44 | } else {
45 | abs_deltax = -deltax; x_dir = -1;
46 | }
47 | if (deltay >= 0) {
48 | abs_deltay = deltay; y_dir = 1;
49 | } else {
50 | abs_deltay = -deltay; y_dir = -1;
51 | }
52 | if (deltaz >= 0) {
53 | abs_deltaz = deltaz; z_dir = 1;
54 | } else {
55 | abs_deltaz = -deltaz; z_dir = -1;
56 | }
57 | if (abs_deltaz >= abs_deltax && // Moving fastest along z?
58 | abs_deltaz >= abs_deltay)
59 | {
60 | major_coord = Z;
61 | minor_coord1 = X;
62 | minor_coord2 = Y;
63 | major_dir = z_dir;
64 | minor_dir1 = x_dir;
65 | minor_dir2 = y_dir;
66 | major_delta = abs_deltaz;
67 | minor_delta1 = abs_deltax;
68 | minor_delta2 = abs_deltay;
69 | }
70 | else if (abs_deltay >= abs_deltax && // Moving fastest along y?
71 | abs_deltay >= abs_deltaz)
72 | {
73 | major_coord = Y;
74 | minor_coord1 = X;
75 | minor_coord2 = Z;
76 | major_dir = y_dir;
77 | minor_dir1 = x_dir;
78 | minor_dir2 = z_dir;
79 | major_delta = abs_deltay;
80 | minor_delta1 = abs_deltax;
81 | minor_delta2 = abs_deltaz;
82 | }
83 | else // Moving fastest along x?
84 | {
85 | major_coord = X;
86 | minor_coord1 = Y;
87 | minor_coord2 = Z;
88 | major_dir = x_dir;
89 | minor_dir1 = y_dir;
90 | minor_dir2 = z_dir;
91 | major_delta = abs_deltax;
92 | minor_delta1 = abs_deltay;
93 | minor_delta2 = abs_deltaz;
94 | }
95 | major_distance = major_delta; // How far to go.
96 | return true;
97 | }
98 | @Override
99 | public boolean getNextStep(Tile n) {
100 | if (major_distance <= 0) {
101 | return false;
102 | }
103 | // Subtract from distance to go.
104 | major_distance -= major_frame_incr;
105 | // Accumulate change.
106 | sum1 += major_frame_incr * minor_delta1;
107 | sum2 += major_frame_incr * minor_delta2;
108 | // Figure change in slower axes.
109 | int minor_frame_incr1 = sum1/major_delta;
110 | int minor_frame_incr2 = sum2/major_delta;
111 | sum1 = sum1 % major_delta; // Remove what we used.
112 | sum2 = sum2 % major_delta; // Remove what we used.
113 | // Update coords. within world.
114 | cur[major_coord] += major_dir*major_frame_incr;
115 | cur[minor_coord1] += minor_dir1*minor_frame_incr1;
116 | cur[minor_coord2] += minor_dir2*minor_frame_incr2;
117 | // Watch for wrapping.
118 | cur[major_coord] = (cur[major_coord] + EConst.c_num_tiles)%EConst.c_num_tiles;
119 | cur[minor_coord1] = (cur[minor_coord1] + EConst.c_num_tiles)%EConst.c_num_tiles;
120 | cur[minor_coord2] = (cur[minor_coord2] + EConst.c_num_tiles)%EConst.c_num_tiles;
121 | if (cur[Z] < 0) { // We are below ground level.
122 | cur[Z] = 0;
123 | major_distance = 0;
124 | return false;
125 | }
126 | n.set(cur[X], cur[Y], cur[Z]);
127 | return true;
128 | }
129 | @Override
130 | public int getNumSteps() {
131 | return major_distance/major_frame_incr;
132 | }
133 | @Override
134 | public boolean isDone() {
135 | return major_distance <= 0;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/AmmoInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.InputStream;
3 | import java.io.IOException;
4 | import com.exult.android.*;
5 |
6 | public class AmmoInfo extends BaseInfo implements DataUtils.ReaderFunctor {
7 | private static AmmoInfo defaultInfo; // For shapes not found.
8 | private int familyShape; // I.e., burst-arrow's is 'arrow'.
9 | private int sprite; // What the missile should look like.
10 | private byte damage; // Extra damage points.
11 | private byte powers; // Same as for weapons.
12 | private byte damageType; // Same as for weapons.
13 | private boolean m_no_blocking; // Can move through walls.
14 | private byte dropType; // What to do to missile when it hits/misses
15 | private boolean m_autohit; // Weapon always hits.
16 | private boolean m_lucky; // Easier to hit with.
17 | private boolean m_returns; // Boomerang, magic axe.
18 | private boolean homing; // For Energy Mist/Death Vortex.
19 | private boolean m_explodes; // Burst arrows.
20 | public static final int // Drop_types // Determines what happens when the missile misses
21 | drop_normally = 0,
22 | never_drop = 1,
23 | always_drop = 2
24 | ;
25 | public static final int is_binary = 1, entry_size = 13;
26 | public static AmmoInfo getDefault() {
27 | if (defaultInfo == null) {
28 | defaultInfo = new AmmoInfo();
29 | defaultInfo.familyShape =
30 | defaultInfo.sprite = -1;
31 | defaultInfo.damage =
32 | defaultInfo.powers =
33 | defaultInfo.damageType =
34 | defaultInfo.dropType = 0;
35 | defaultInfo.m_no_blocking =
36 | defaultInfo.m_autohit =
37 | defaultInfo.m_lucky =
38 | defaultInfo.m_returns =
39 | defaultInfo.homing =
40 | defaultInfo.m_explodes = false;
41 | }
42 | return defaultInfo;
43 | }
44 | public int getFamilyShape()
45 | { return familyShape; }
46 | public int getSpriteShape()
47 | { return sprite; }
48 | public int getDamage()
49 | { return damage; }
50 | public int getDamageType()
51 | { return damageType; }
52 | public byte getPowers()
53 | { return powers; }
54 | public boolean no_blocking()
55 | { return m_no_blocking; }
56 | public byte getDropType()
57 | { return dropType; }
58 | public boolean autohits()
59 | { return m_autohit; }
60 | public boolean lucky()
61 | { return m_lucky; }
62 | public boolean returns()
63 | { return m_returns; }
64 | public boolean isHoming()
65 | { return homing; }
66 | public boolean explodes()
67 | { return m_explodes; }
68 | public static int get_info_flag()
69 | { return 2; }
70 | public int getBaseStrength() {
71 | int strength = damage;
72 | // These 4 get picked with about the same odds.
73 | strength += (powers & WeaponInfo.no_damage) != 0 ? 10 : 0;
74 | strength += (powers & WeaponInfo.sleep) != 0 ? 10 : 0;
75 | strength += (powers & WeaponInfo.paralyze) != 0 ? 10 : 0;
76 | strength += (powers & WeaponInfo.charm) != 0 ? 10 : 0;
77 | // These have slightly lower odds.
78 | strength += (powers & WeaponInfo.poison) != 0 ? 5 : 0;
79 | strength += (powers & WeaponInfo.curse) != 0 ? 5 : 0;
80 | strength += (powers & WeaponInfo.magebane) != 0 ? 5 : 0;
81 | strength += m_lucky ? 5 : 0;
82 | strength += damageType != WeaponInfo.normal_damage ? 5 : 0;
83 | if (m_autohit)
84 | strength *= 2; // These are almost unfair...
85 | if (m_no_blocking)
86 | strength *= 2; // ... and these get picked a lot more often.
87 | return strength;
88 | }
89 | private boolean readNew(InputStream in, int version,
90 | boolean patch, int game, ShapeInfo info) {
91 | byte buf[] = new byte[entry_size-2]; // Entry length.
92 | try {
93 | in.read(buf);
94 | } catch (IOException e) {
95 | setInvalid(true);
96 | System.out.println("Error reading AMMO info");
97 | return false;
98 | }
99 | int ind = 0;
100 | if (buf[entry_size-3] == 0xff) { // means delete entry.
101 | setInvalid(true);
102 | info.setAmmoInfo(null);
103 | return true;
104 | }
105 | familyShape = EUtil.Read2(buf, ind);
106 | sprite = EUtil.Read2(buf, ind + 2); // How the missile looks like
107 | ind += 4;
108 | damage = buf[ind++];
109 | byte flags0 = buf[ind++];
110 | m_lucky = ((flags0)&1) != 0;
111 | m_autohit = ((flags0>>1)&1) != 0;
112 | m_returns = ((flags0>>2)&1) != 0;
113 | m_no_blocking = ((flags0>>3)&1) != 0;
114 | homing = ((flags0>>4)&3)==3;
115 | dropType = (byte)(homing ? 0 : (flags0>>4)&3);
116 | m_explodes = ((flags0>>6)&1) != 0;
117 | ind++; // 1 unknown.
118 | byte flags1 = buf[ind++];
119 | damageType = (byte)((flags1>>4)&15);
120 | powers = buf[ind++];
121 | info.setAmmoInfo(this);
122 | // Last 2 unknown.
123 | return true;
124 | }
125 | @Override
126 | public boolean read(InputStream in, int version,
127 | boolean patch, int game, ShapeInfo info) {
128 | return (new AmmoInfo()).readNew(in, version, patch, game, info);
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/AnimationInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import com.exult.android.*;
3 | import java.io.PushbackInputStream;
4 | import java.io.InputStream;
5 |
6 | import com.exult.android.ShapeInfo;
7 | /*
8 | * Information about shape animations.
9 | */
10 | public class AnimationInfo extends BaseInfo {
11 | public static final int // AniType // Type of animation
12 | FA_TIMESYNCHED = 0, // Frame based on current game ticks.
13 | FA_HOURLY = 1, // Frame based on game hour.
14 | FA_NON_LOOPING = 2, // Stop at last frame.
15 | FA_LOOPING = 3, // Generic loop.
16 | FA_RANDOM_FRAMES = 4 // Frames completely random.
17 | ;
18 | private int type;
19 | private int frameCount; // Frame count of each animation cycle
20 | private int frameDelay; // Delay multiplier between frames.
21 | private int sfxDelay; // Extra sfx delay, in frames.
22 | private int freezeFirst; // % chance of advancing first frame of animation.
23 | private int recycle; // Repeat the last recycle frames when wrapping;
24 | // all frames if zero.
25 | public static AnimationInfo createFromTfa(int type, int nframes) {
26 | AnimationInfo inf = new AnimationInfo();
27 | switch (type) {
28 | case 0:
29 | case 1:
30 | inf.set(FA_TIMESYNCHED, nframes, 0);
31 | break;
32 | case 5:
33 | inf.set(FA_LOOPING, nframes, 0, 20, 1, -1);
34 | break;
35 | case 6:
36 | inf.set(FA_RANDOM_FRAMES, nframes, 0);
37 | break;
38 | case 8:
39 | inf.set(FA_HOURLY, nframes, 0);
40 | break;
41 | case 9:
42 | inf.set(FA_LOOPING, nframes, 8);
43 | break;
44 | case 10:
45 | inf.set(FA_LOOPING, nframes, 6);
46 | break;
47 | case 11:
48 | inf.set(FA_LOOPING, nframes, 1, 0);
49 | break;
50 | case 12: // Slow advance.
51 | case 14: // Grandfather clock.
52 | inf.set(FA_TIMESYNCHED, nframes, 0, 100, 4, -1);
53 | break;
54 | case 13:
55 | inf.set(FA_NON_LOOPING, nframes, 0);
56 | break;
57 | case 15:
58 | inf.set(FA_TIMESYNCHED, 6, 0, 100, 4, 0);
59 | break;
60 | default:
61 | // Not handled yet. These would be cases 2, 3, 4, 7 and 12:
62 | // case 2 seems to be equal to case 0/1 except that
63 | // frames advance randomly (maybe 1 in 4 chance)
64 | // case 3 is very strange. I have noted no pattern yet.
65 | // case 4 seems to be for case 3 what case 2 is for case 0/1.
66 | // case 7 toggles bit 0 of the frame (i.e., new_frame == frame ^ 1)
67 | // None of these are used for any animated shape, which is why
68 | // I haven't bothered implementing them.
69 | return null;
70 | }
71 | inf.infoFlags = 0;
72 | return inf;
73 | }
74 | private void set(int t, int count, int rec, int freeze, int delay, int sfxi) {
75 | type = t;
76 | frameCount = count;
77 | frameDelay = delay;
78 | sfxDelay = sfxi;
79 | freezeFirst = freeze;
80 | recycle = rec;
81 | }
82 | private void set(int t, int count, int rec, int freeze) {
83 | set(t, count, rec, freeze, 1, 0);
84 | }
85 | private void set(int t, int count, int rec) {
86 | set(t, count, rec, 100, 1, 0);
87 | }
88 | public int getType()
89 | { return type; }
90 | public int getFrameCount()
91 | { return frameCount; }
92 | public int getFrameDelay()
93 | { return frameDelay; }
94 | public int getSfxDelay()
95 | { return sfxDelay; }
96 | public int getFreezeFirstChance()
97 | { return freezeFirst; }
98 | public int get_recycle()
99 | { return recycle; }
100 | public static int getInfoFlag()
101 | { return 0x40; }
102 | public static final int is_binary = 0, entry_size = 0;
103 | /*
104 | * Read in a animation-cycle-info entry from 'shape_inf.txt'.
105 | */
106 | public boolean readnew(InputStream in, int version, boolean patch, int game,
107 | ShapeInfo info) {
108 | PushbackInputStream txtin = (PushbackInputStream)in;
109 | if (version < 5) // Not compatible with old system.
110 | return false;
111 | int ty = EUtil.ReadInt(txtin);
112 | if (ty == -0xff) { // means delete entry.
113 | setInvalid(true);
114 | return true;
115 | }
116 | set(ty, EUtil.ReadInt(txtin), 0); // Sensible defaults.
117 | if (type != FA_HOURLY) { // We still have things to read.
118 | frameDelay = EUtil.ReadInt(txtin);
119 | sfxDelay = EUtil.ReadInt(txtin);
120 | if (type == FA_LOOPING) {
121 | freezeFirst = EUtil.ReadInt(txtin);
122 | recycle = EUtil.ReadInt(txtin);
123 | }
124 | }
125 | return true;
126 | }
127 | @Override
128 | public boolean read(InputStream in, int version, boolean patch, int game,
129 | ShapeInfo info) {
130 | return new AnimationInfo().readnew(in, version, patch, game, info);
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/ArmorInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.InputStream;
3 | import java.io.IOException;
4 | import com.exult.android.*;
5 |
6 | public class ArmorInfo extends BaseInfo implements DataUtils.ReaderFunctor {
7 | private byte prot; // Protection value.
8 | private byte immune; // Weapon_data::damage_type bits.
9 | public static final int is_binary = 1, entry_size = 10;
10 | public int getProt() {
11 | return ((int)prot)&0xff;
12 | }
13 | public int getImmune() {
14 | return ((int)immune)&0xff;
15 | }
16 | static int getInfoFlag() {
17 | return 4;
18 | }
19 | public int getBaseStrength() {
20 | int strength = prot;
21 | if (immune != 0) // Double strength for any immunities? Give bonus for each?
22 | strength *= 2;
23 | return strength;
24 | }
25 | public int getBaseXpValue() {
26 | return ((int)prot)&0xff;
27 | }
28 | private boolean readNew(InputStream in, int version,
29 | boolean patch, int game, ShapeInfo info) {
30 | byte buf[] = new byte[entry_size-2]; // Entry length.
31 | try {
32 | in.read(buf);
33 | } catch (IOException e) {
34 | setInvalid(true);
35 | System.out.println("Error reading ARMOR info");
36 | return false;
37 | }
38 | int ind = 0;
39 | if (buf[entry_size-3] == 0xff) { // means delete entry.
40 | setInvalid(true);
41 | info.setArmorInfo(null);
42 | return true;
43 | }
44 | prot = buf[ind++]; // Protection value.
45 | ind++; // Unknown.
46 | immune = buf[ind++]; // Immunity flags.
47 | // Last 5 are unknown/unused.
48 | return true;
49 | }
50 | @Override
51 | public boolean read(InputStream in, int version,
52 | boolean patch, int game, ShapeInfo info) {
53 | return (new ArmorInfo()).readNew(in, version, patch, game, info);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/BaseInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import com.exult.android.*;
3 | import java.io.InputStream;
4 | import java.util.Collections;
5 | import java.util.Vector;
6 |
7 | public abstract class BaseInfo implements DataUtils.ReaderFunctor {
8 | public final static int // Flags.
9 | nfo_modified = 1,
10 | From_patch = 2,
11 | Have_static = 4,
12 | Is_invalid = 8;
13 | protected int infoFlags;
14 | protected void setFlag(boolean tf, int flag)
15 | {
16 | if (tf)
17 | infoFlags |= flag;
18 | else
19 | infoFlags &= (~flag);
20 | }
21 | public boolean isInvalid() {
22 | return (infoFlags&Is_invalid) != 0;
23 | }
24 | public void setInvalid(boolean tf) {
25 | setFlag(tf, Is_invalid);
26 | }
27 | public static class OneKeyInfo extends BaseInfo
28 | implements Comparable {
29 | private static OneKeyInfo search;
30 | protected int keyval; // Shape or frame.
31 | @Override
32 | public int compareTo(OneKeyInfo i2) {
33 | return keyval - i2.keyval;
34 | }
35 | @Override
36 | public boolean read(InputStream in, int version,
37 | boolean patch, int game, ShapeInfo info) {
38 | return false;
39 | }
40 | public static Vector addVectorInfo(T inf, Vector vec) {
41 | if (vec == null)
42 | vec = new Vector(4);
43 | int ind = Collections.binarySearch(vec, inf);
44 | if (ind < 0) // Not found?
45 | vec.insertElementAt(inf, -ind - 1);
46 | else // Found, so replace.
47 | vec.setElementAt(inf, ind);
48 | return vec;
49 | }
50 | public static T searchSingleWildCard(Vector vec,
51 | int keyval) {
52 | if (vec == null)
53 | return null;
54 | //System.out.println("searchSingleWildCard: keyval " + keyval);
55 | T found;
56 | if (search == null)
57 | search = new OneKeyInfo();
58 | search.keyval = keyval;
59 | int ind = Collections.binarySearch(vec, search);
60 | //System.out.println("searchSingleWildCard: first try: ind = " + ind);
61 | if (ind >= 0) {
62 | found = vec.elementAt(ind);
63 | if (!found.isInvalid())
64 | return found;
65 | }
66 | search.keyval = -1; // Try wildcard.
67 | ind = Collections.binarySearch(vec, search);
68 | if (ind >= 0 && !vec.elementAt(ind).isInvalid())
69 | return vec.elementAt(ind);
70 | return null;
71 | }
72 | }
73 | public static class FrameInfo extends BaseInfo
74 | implements Comparable {
75 | protected int frame; // Frame for which this applies or -1 for any.
76 | protected int quality; // Quality for which this applies or -1 for any.
77 | private static FrameInfo search = null;
78 |
79 | public int getFrame()
80 | { return frame; }
81 | public int getQuality()
82 | { return quality; }
83 | @Override
84 | public boolean read(InputStream in, int version,
85 | boolean patch, int game, ShapeInfo info) {
86 | return false;
87 | }
88 | @Override
89 | public int compareTo(FrameInfo i2) {
90 | int v = frame - i2.frame;
91 | if (v == 0)
92 | v = quality - i2.quality;
93 | return v;
94 | }
95 | public static Vector addVectorInfo(T inf, Vector vec) {
96 | if (vec == null)
97 | vec = new Vector(4);
98 | int ind = Collections.binarySearch(vec, inf);
99 | //System.out.println("addVectorInfo: ind = " + ind + ", frame = " + inf.frame
100 | // + ", qual = " + inf.quality + ", vec.size = " + vec.size());
101 | if (ind < 0) { // Not found?
102 | ind = -ind - 1;
103 | vec.insertElementAt(inf, ind);
104 | } else // Found, so replace.
105 | vec.setElementAt(inf, ind);
106 | return vec;
107 | }
108 | public static T searchDoubleWildCards(Vector vec,
109 | int frame, int quality) {
110 | if (vec == null)
111 | return null;
112 | //System.out.println("searchDoubleWildCard: frame " + frame + ", qual = " + quality);
113 | T found;
114 | if (search == null)
115 | search = new FrameInfo();
116 | search.frame = frame; search.quality = quality;
117 | int ind = Collections.binarySearch(vec, search);
118 | //System.out.println("searchDoubleWildCard: first try: ind = " + ind);
119 | if (ind >= 0) {
120 | found = vec.elementAt(ind);
121 | if (!found.isInvalid())
122 | return found;
123 | }
124 | int sz = vec.size();
125 | if (quality != -1) {
126 | //System.out.println("ind = " + ind + ", size = " + vec.size());
127 | ind = -ind - 1;
128 | if (ind < sz) {
129 |
130 | found = vec.elementAt(-ind + 1);
131 | if (found.frame == frame) {
132 | // Maybe quality is to blame. Try wildcard qual.
133 | search.quality = -1;
134 | ind = Collections.binarySearch(vec, search);
135 | //System.out.println("searchDoubleWildCard: with qual=-1, ind = " +ind);
136 | if (ind >= 0 && !vec.elementAt(ind).isInvalid())
137 | return vec.elementAt(ind);
138 | }
139 | }
140 | // Maybe frame is to blame? Try search for specific
141 | // quality with wildcard frame.
142 | search.quality = quality;
143 | search.frame = -1;
144 | ind = Collections.binarySearch(vec, search);
145 | if (ind >= 0 && !vec.elementAt(ind).isInvalid())
146 | return vec.elementAt(ind);
147 | }
148 | // *Still* haven't found it. Last try: wildcard frame *and* quality.
149 | search.frame = search.quality = -1;
150 | ind = Collections.binarySearch(vec, search);
151 | if (ind >= 0 && !vec.elementAt(ind).isInvalid())
152 | return vec.elementAt(ind);
153 | return null;
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/BodyInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import com.exult.android.*;
3 | import java.io.PushbackInputStream;
4 |
5 | import java.io.InputStream;
6 |
7 | import com.exult.android.ShapeInfo;
8 |
9 | public class BodyInfo extends BaseInfo {
10 | private int bshape; // Body shape.
11 | private int bframe; // Body frame.
12 | public int getBodyShape()
13 | { return bshape; }
14 | public int getBodyFrame()
15 | { return bframe; }
16 | public static int getInfoFlag()
17 | { return 0x100; }
18 | private boolean readNew(InputStream in, int version, boolean patch, int game,
19 | ShapeInfo info) {
20 | PushbackInputStream txtin = (PushbackInputStream) in;
21 | bshape = EUtil.ReadInt(txtin);
22 | if (bshape == -0xff) { // means delete entry.
23 | setInvalid(true);
24 | return true;
25 | }
26 | bframe = EUtil.ReadInt(txtin);
27 | //System.out.println("BodyInfo: shape = " + bshape + ", frame = " + bframe);
28 | info.setBodyInfo(this);
29 | return true;
30 | }
31 | @Override
32 | public boolean read(InputStream in, int version, boolean patch, int game,
33 | ShapeInfo info) {
34 | return (new BodyInfo()).readNew(in, version, patch, game, info);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/ContentRules.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.ShapeInfo;
5 | import com.exult.android.EUtil;
6 | /*
7 | * Information about shapes accepted/rejected by containers.
8 | * This is meant to be stored in a totally ordered vector.
9 | */
10 | public class ContentRules extends BaseInfo.OneKeyInfo {
11 | // Key is the shape;
12 | private boolean accept;
13 |
14 | public int getShape()
15 | { return keyval; }
16 | public boolean acceptsShape()
17 | { return accept; }
18 | private boolean readNew(InputStream in, int version, boolean patch, int game,
19 | ShapeInfo info) {
20 | PushbackInputStream txtin = (PushbackInputStream)in;
21 | keyval = EUtil.ReadInt(txtin);
22 | if (keyval < 0)
23 | keyval = -1;
24 | accept = EUtil.ReadInt(txtin)!= 0;
25 | System.out.println("ContentRules: keyval = " + keyval + ", accept = " + accept);
26 | info.setContentRules(addVectorInfo(this, info.getContentRules()));
27 | return true;
28 | }
29 | @Override
30 | public boolean read(InputStream in, int version, boolean patch, int game,
31 | ShapeInfo info) {
32 | return (new ContentRules()).readNew(in, version, patch, game, info);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/EffectiveHpInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.ShapeInfo;
5 | import com.exult.android.EUtil;
6 |
7 | /*
8 | * Information about effective HPs.
9 | * This is meant to be stored in a totally ordered vector.
10 | */
11 | public class EffectiveHpInfo extends BaseInfo.FrameInfo {
12 | private byte hps;
13 |
14 | public int getHps()
15 | { return hps; }
16 | private boolean readNew(InputStream in, int version, boolean patch, int game,
17 | ShapeInfo info) {
18 | PushbackInputStream txtin = (PushbackInputStream)in;
19 | frame = EUtil.ReadInt(txtin);
20 | if (frame < 0)
21 | frame = -1;
22 | else
23 | frame &= 0xff;
24 | quality = EUtil.ReadInt(txtin);
25 | if (quality < 0)
26 | quality = -1;
27 | else
28 | quality &= 255;
29 | hps = (byte)((int)EUtil.ReadInt(txtin) & 0xff);
30 | info.setEffectiveHpInfo(addVectorInfo(this, info.getEffectiveHpInfo()));
31 | return true;
32 | }
33 | @Override
34 | public boolean read(InputStream in, int version, boolean patch, int game,
35 | ShapeInfo info) {
36 | return (new EffectiveHpInfo()).readNew(in, version, patch, game, info);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/ExplosionInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import com.exult.android.*;
3 | import java.io.PushbackInputStream;
4 | import java.io.InputStream;
5 | import com.exult.android.ShapeInfo;
6 |
7 | public class ExplosionInfo extends BaseInfo {
8 | private int sprite; // Explosion sprite.
9 | private int sfxnum; // SFX to play or 255 for none.
10 | public int getSprite()
11 | { return sprite; }
12 | public int getSfx()
13 | { return sfxnum; }
14 | public static int getInfoFlag()
15 | { return 0x10; }
16 | private boolean readNew(InputStream in, int version, boolean patch, int game,
17 | ShapeInfo info) {
18 | PushbackInputStream txtin = (PushbackInputStream) in;
19 | sprite = EUtil.ReadInt(txtin);
20 | if (sprite == -0xff) { // means delete entry.
21 | setInvalid(true);
22 | return true;
23 | }
24 | sfxnum = EUtil.ReadInt(txtin, -1);
25 | if (sfxnum == 255)
26 | sfxnum = -1;
27 | return true;
28 | }
29 | @Override
30 | public boolean read(InputStream in, int version, boolean patch, int game,
31 | ShapeInfo info) {
32 | return (new ExplosionInfo()).readNew(in, version, patch, game, info);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/FrameFlagsInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.ShapeInfo;
5 | import com.exult.android.EUtil;
6 | import com.exult.android.DataUtils;
7 | /*
8 | * Information about frame names.
9 | * This is meant to be stored in a totally ordered vector.
10 | */
11 | public class FrameFlagsInfo extends BaseInfo.FrameInfo {
12 | public static final int // enum Enum_Frame_power_flags
13 | fp_poison_safe = 0,
14 | fp_charm_safe = 1,
15 | fp_sleep_safe = 2,
16 | fp_paralysis_safe = 3,
17 | fp_curse_safe = 4,
18 | fp_power_safe = 5,
19 | fp_death_safe = 6,
20 | fp_cant_die = 7,
21 | fp_cold_immune = 8,
22 | fp_doesnt_eat = 9,
23 | fp_swamp_safe = 10,
24 | fp_force_usecode = 11,
25 | fp_infinite_reagents = 12;
26 | public static final int // enum Enum_Frame_Flags
27 | poison_safe = (1 << fp_poison_safe),
28 | charm_safe = (1 << fp_charm_safe),
29 | sleep_safe = (1 << fp_sleep_safe),
30 | paralysis_safe = (1 << fp_paralysis_safe),
31 | curse_safe = (1 << fp_curse_safe),
32 | power_safe = (1 << fp_power_safe),
33 | death_safe = (1 << fp_death_safe),
34 | cant_die = (1 << fp_cant_die),
35 | cold_immune = (1 << fp_cold_immune),
36 | doesnt_eat = (1 << fp_doesnt_eat),
37 | swamp_safe = (1 << fp_swamp_safe),
38 | force_usecode = (1 << fp_force_usecode),
39 | infinite_reagents = (1 << fp_infinite_reagents);
40 | private int m_flags; // Bit field with the relevant flags.
41 |
42 | public boolean getFlag(int tf)
43 | { return (m_flags & (1 << tf)) != 0; }
44 | public int getFlags()
45 | { return m_flags; }
46 | private boolean readNew(InputStream in, int version, boolean patch, int game,
47 | ShapeInfo info) {
48 | PushbackInputStream txtin = (PushbackInputStream)in;
49 | frame = EUtil.ReadInt(txtin);
50 | if (frame < 0)
51 | frame = -1;
52 | else
53 | frame &= 0xff;
54 |
55 | if (version >= 6)
56 | quality = EUtil.ReadInt(txtin);
57 | else
58 | quality = -1;
59 | if (quality < 0)
60 | quality = -1;
61 | else
62 | quality &= 0xff;
63 | final int size = 32; // Bit count for m_flags.
64 | m_flags = DataUtils.readBitFlags(txtin, size);
65 | //System.out.println("frameFlagsInfo for frame " + frame + ", quality = " + quality);
66 | info.setFrameFlagsInfo(addVectorInfo(this, info.getFrameFlagsInfo()));
67 | return true;
68 | }
69 | @Override
70 | public boolean read(InputStream in, int version, boolean patch, int game,
71 | ShapeInfo info) {
72 | return (new FrameFlagsInfo()).readNew(in, version, patch, game, info);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/FrameNameInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.EUtil;
5 | import com.exult.android.ShapeInfo;
6 | /*
7 | * Information about frame names.
8 | * This is meant to be stored in a totally ordered vector.
9 | */
10 | public class FrameNameInfo extends BaseInfo.FrameInfo {
11 | private short type; // How the entry is used.
12 | private int msgid; // Item name index in misc_names.
13 | private int othermsg; // Suffix/prefix or default message, depending on type
14 |
15 | public int getType() {
16 | return type;
17 | }
18 | public int getMsgid() {
19 | return msgid;
20 | }
21 | public int getOthermsg() {
22 | return othermsg;
23 | }
24 | private boolean readNew(InputStream in, int version, boolean patch, int game,
25 | ShapeInfo info) {
26 | PushbackInputStream txtin = (PushbackInputStream) in;
27 | frame = EUtil.ReadInt(txtin);
28 | if (frame < 0)
29 | frame = -1;
30 | else
31 | frame &= 0xff;
32 | quality = EUtil.ReadInt(txtin);
33 | if (quality < 0)
34 | quality = -1;
35 | else
36 | quality &= 255;
37 | type = (short)EUtil.ReadInt(txtin);
38 | if (type >= 0) {
39 | msgid = EUtil.ReadInt(txtin);
40 | othermsg = EUtil.ReadInt(txtin, -255);
41 | }
42 | //System.out.println("frameNameInfo for frame " + frame + ", quality = " + quality);
43 | info.setFrameNameInfo(addVectorInfo(this, info.getFrameNameInfo()));
44 | return true;
45 | }
46 | @Override
47 | public boolean read(InputStream in, int version, boolean patch, int game,
48 | ShapeInfo info) {
49 | return (new FrameNameInfo()).readNew(in, version, patch, game, info);
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/FrameUsecodeInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.EUtil;
5 | import com.exult.android.ShapeInfo;
6 |
7 | public class FrameUsecodeInfo extends BaseInfo.FrameInfo {
8 | private int usecode; // Usecode function of the frame/quality at hand,
9 | // or -1 for default shape usecode.
10 | private String usecodeName; // Name of usecode fun explicitly assigned.
11 | public int getUsecode()
12 | { return usecode; }
13 | public String getUsecodeName()
14 | { return usecodeName; }
15 | public boolean readNew(InputStream in, int version, boolean patch, int game,
16 | ShapeInfo info) {
17 | PushbackInputStream txtin = (PushbackInputStream) in;
18 | frame = EUtil.ReadInt(txtin);
19 | if (frame < 0)
20 | frame = -1;
21 | else
22 | frame &= 0xff;
23 | quality = EUtil.ReadInt(txtin);
24 | if (quality < 0)
25 | quality = -1;
26 | else
27 | quality &= 255;
28 | boolean type = EUtil.ReadInt(txtin) != 0;
29 | if (type) {
30 | usecodeName = EUtil.ReadStr(in);
31 | usecode = -1;
32 | } else {
33 | usecode = EUtil.ReadInt(txtin, -1);
34 | }
35 | info.setFrameUsecodeInfo(addVectorInfo(this, info.getFrameUsecodeInfo()));
36 | return true;
37 | }
38 | @Override
39 | public boolean read(InputStream in, int version, boolean patch, int game,
40 | ShapeInfo info) {
41 | return new FrameUsecodeInfo().readNew(in, version, patch, game, info);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/PaperdollItem.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.ShapeInfo;
5 | import com.exult.android.EUtil;
6 |
7 | /*
8 | * Information about an object's paperdoll.
9 | * This is meant to be stored in a totally ordered vector.
10 | */
11 | public class PaperdollItem extends BaseInfo.FrameInfo {
12 | // FrameInfo.frame is the frame in the world (-1 for all)
13 | // FrameInfo.quality is the spot placed in.
14 | private short type; // For weapons, the arm frame type to use.
15 | // For headgear, head frame to use.
16 | // Meaningless for all others.
17 | private boolean translucent; // If the paperdoll should be drawn translucently or not
18 | private boolean gender; // Is this object gender specific
19 |
20 | private short shape; // The shape (if -1 use world shape and frame)
21 | private short frames[] = new short[4]; // The paperdoll frame and alternates.
22 |
23 | private boolean readNew(InputStream in, int version, boolean patch, int game,
24 | ShapeInfo info) {
25 | PushbackInputStream txtin = (PushbackInputStream)in;
26 | frame = (short)EUtil.ReadInt(txtin);
27 | translucent = EUtil.ReadInt(txtin) != 0;
28 | quality = EUtil.ReadInt(txtin);
29 | int ty = EUtil.ReadInt(txtin);
30 | if (ty == -255) { // 'Invalid' marker.
31 | setInvalid(true);
32 | return true; // Ignore remainder of the line.
33 | }
34 | if (quality != 0 && quality != 3) // Field only valid for these spots.
35 | type = 0; // Ignore it.
36 | else if (version == 1) {
37 | switch (ty) // Convert old data.
38 | {
39 | case 2:
40 | case 7:
41 | type = 1; break;
42 | case 3:
43 | type = 2; break;
44 | default:
45 | type = 0; break;
46 | }
47 | } else
48 | type = (short)ty;
49 | gender = EUtil.ReadInt(txtin) != 0;
50 | shape = (short)EUtil.ReadInt(txtin);
51 | frames[0] = (short)EUtil.ReadInt(txtin);
52 | // Not all items have all entries; those that need, do, though.
53 | frames[1] = (short)EUtil.ReadInt(txtin, -1);
54 | frames[2] = (short)EUtil.ReadInt(txtin, -1);
55 | frames[3] = (short)EUtil.ReadInt(txtin, -1);
56 | //System.out.println("PaperDollItem: shape = " + shape +
57 | // ", frame = " + frame + ", spot = " + quality);
58 | info.setPaperdollInfo(addVectorInfo(this, info.getPaperdollInfo()));
59 | return true;
60 | }
61 | @Override
62 | public boolean read(InputStream in, int version, boolean patch, int game,
63 | ShapeInfo info) {
64 | return (new PaperdollItem()).readNew(in, version, patch, game, info);
65 | }
66 | public void invalidate()
67 | { type = -255; setInvalid(true); }
68 | public int getWorldFrame()
69 | { return frame; }
70 | public int getObjectSpot()
71 | { return quality; }
72 | public short getSpotFrame()
73 | { return type; }
74 | public boolean isTranslucent()
75 | { return translucent; }
76 | public boolean isGenderBased()
77 | { return gender; }
78 | public int getPaperdollShape()
79 | { return shape; }
80 | public int getPaperdollBaseframe() {
81 | return frames[0];
82 | }
83 | public int getPaperdollFrame(int num) {
84 | if (num < 4)
85 | return frames[num];
86 | return num;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/PaperdollNpc.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.ShapeInfo;
5 | import com.exult.android.EUtil;
6 |
7 |
8 | public class PaperdollNpc extends BaseInfo {
9 | boolean isFemale; // Is the NPC Female (or more specifically not male)
10 | boolean translucent; // If the paperdoll should be drawn translucently or not
11 |
12 | // Body info
13 | short bodyShape; // Body Shape
14 | short bodyFrame; // Body Frame
15 |
16 | short headShape; // Head Shape
17 | short headFrame; // Normal Head Frame
18 | short headFrameHelm; // Frame when wearing a helm
19 |
20 | short armsShape; // Shape for Arms
21 | short armsFrame[] = new short[3]; // Frames for arms.
22 |
23 | private boolean readNew(InputStream in, int version, boolean patch, int game,
24 | ShapeInfo info) {
25 | PushbackInputStream txtin = (PushbackInputStream)in;
26 | int sexflag = EUtil.ReadInt(txtin);
27 | if (sexflag == -0xff) { // means delete entry.
28 | info.setNpcPaperdollInfo(null);
29 | setInvalid(true);
30 | return true;
31 | }
32 | isFemale = sexflag != 0;
33 | translucent = EUtil.ReadInt(txtin) != 0;
34 | bodyShape = (short)EUtil.ReadInt(txtin);
35 | bodyFrame = (short)EUtil.ReadInt(txtin);
36 | headShape = (short)EUtil.ReadInt(txtin);
37 | headFrame = (short)EUtil.ReadInt(txtin);
38 | headFrameHelm = (short)EUtil.ReadInt(txtin);
39 | armsShape = (short)EUtil.ReadInt(txtin);
40 | armsFrame[0] = (short)EUtil.ReadInt(txtin);
41 | armsFrame[1] = (short)EUtil.ReadInt(txtin);
42 | armsFrame[2] = (short)EUtil.ReadInt(txtin);
43 | if (version < 3)
44 | // We need this for backward compatibility.
45 | // We use the setter methods sp that the info
46 | // will get saved by ES if that is needed.
47 | info.setGumpData(EUtil.ReadInt(txtin, -1), -1);
48 |
49 | info.setNpcPaperdollInfo(this);
50 | return true;
51 | }
52 | @Override
53 | public boolean read(InputStream in, int version, boolean patch, int game,
54 | ShapeInfo info) {
55 | return (new PaperdollNpc()).readNew(in, version, patch, game, info);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/SFXInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.EUtil;
5 | import com.exult.android.ShapeInfo;
6 |
7 | public class SFXInfo extends BaseInfo {
8 | private int sfxnum;
9 | private boolean random; // sfx in range are to be randomly chosen.
10 | private int range; // # of sequential sfx to be used.
11 | private int chance; // % chance of playing the SFX.
12 | private int extra; // For grandfather clock.
13 |
14 | public int getSfx()
15 | { return sfxnum; }
16 | public boolean playSequentially()
17 | { return !random; }
18 | public boolean playRandomly()
19 | { return random; }
20 | public int getChance()
21 | { return chance; }
22 | public boolean playHourlyTicks()
23 | { return extra > -1; }
24 | public int getExtraSfx()
25 | { return extra; }
26 | public int getSfxRange()
27 | { return range; }
28 | public boolean timeToPlay() {
29 | return EUtil.rand()%100 < chance;
30 | }
31 | // Get next. If prev == -1, we get the first.
32 | public int getNextSfx(int prev) {
33 | if (range > 1) {
34 | if (random)
35 | return sfxnum + (EUtil.rand() % range);
36 | else {
37 | if (prev == -1)
38 | return sfxnum;
39 | int ind = (prev - sfxnum + 1) % range;
40 | return sfxnum + ind;
41 | }
42 | }
43 | return sfxnum;
44 | }
45 | public static int getInfoFlag()
46 | { return 0x20; }
47 | private boolean readNew(InputStream in, int version, boolean patch, int game,
48 | ShapeInfo info) {
49 | PushbackInputStream txtin = (PushbackInputStream) in;
50 | sfxnum = EUtil.ReadInt(txtin);
51 | if (sfxnum == -0xff) { // means delete entry.
52 | setInvalid(true);
53 | return true;
54 | }
55 | if (version >= 2) {
56 | chance = EUtil.ReadInt(txtin, 100);
57 | if (chance < 1 || chance > 100)
58 | chance = 100;
59 | range = EUtil.ReadInt(txtin, 1);
60 | if (range < 1)
61 | range = 1; // Sensible default.
62 | random = EUtil.ReadInt(txtin, 0) != 0;
63 | extra = EUtil.ReadInt(txtin, -1);
64 | }
65 | //System.out.printf("SFXInfo: chance = %1$d, range = %2$d\n", chance, range);
66 | info.setSfxInfo(this);
67 | return true;
68 | }
69 | @Override
70 | public boolean read(InputStream in, int version, boolean patch, int game,
71 | ShapeInfo info) {
72 | return (new SFXInfo()).readNew(in, version, patch, game, info);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/com/exult/android/shapeinf/WarmthInfo.java:
--------------------------------------------------------------------------------
1 | package com.exult.android.shapeinf;
2 | import java.io.PushbackInputStream;
3 | import java.io.InputStream;
4 | import com.exult.android.ShapeInfo;
5 | import com.exult.android.EUtil;
6 | /*
7 | * Information about shapes accepted/rejected by containers.
8 | * This is meant to be stored in a totally ordered vector.
9 | */
10 | public class WarmthInfo extends BaseInfo.OneKeyInfo {
11 | // Key is the frame.
12 | private byte warmth;
13 | public final int getFrame()
14 | { return keyval; }
15 | public int getWarmth()
16 | { return warmth; }
17 | private boolean readNew(InputStream in, int version, boolean patch, int game,
18 | ShapeInfo info) {
19 | PushbackInputStream txtin = (PushbackInputStream)in;
20 | keyval = (short) EUtil.ReadInt(txtin);
21 | if (keyval < 0)
22 | keyval = -1;
23 | else
24 | keyval &= 0xff;
25 | warmth = (byte)(EUtil.ReadInt(txtin) & 0xff);
26 | info.setWarmthInfo(addVectorInfo(this, info.getWarmthInfo()));
27 | return true;
28 | }
29 |
30 | @Override
31 | public boolean read(InputStream in, int version, boolean patch, int game,
32 | ShapeInfo info) {
33 | return new WarmthInfo().readNew(in, version, patch, game, info);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------