1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/ultima8/world/actors/avatar_mover_process.h"
24 #include "ultima/ultima8/world/actors/actor.h"
25 #include "ultima/ultima8/kernel/kernel.h"
26 #include "ultima/ultima8/world/actors/targeted_anim_process.h"
27 #include "ultima/ultima8/world/get_object.h"
28 #include "ultima/ultima8/misc/direction_util.h"
29
30 namespace Ultima {
31 namespace Ultima8 {
32
AvatarMoverProcess()33 AvatarMoverProcess::AvatarMoverProcess() : Process(),
34 _lastAttack(0), _idleTime(0), _movementFlags(0) {
35 _type = 1; // CONSTANT! (type 1 = persistent)
36 }
37
38
~AvatarMoverProcess()39 AvatarMoverProcess::~AvatarMoverProcess() {
40 }
41
run()42 void AvatarMoverProcess::run() {
43 Actor *avatar = getControlledActor();
44 assert(avatar);
45
46 // busy, so don't move
47 if (avatar->isBusy()) {
48 _idleTime = 0;
49 return;
50 }
51
52 if (avatar->getLastAnim() == Animation::hang) {
53 handleHangingMode();
54 return;
55 }
56
57 // falling, so don't move
58 if (avatar->getGravityPID() != 0) {
59 Process *proc = Kernel::get_instance()->getProcess(avatar->getGravityPID());
60 if (!proc || !proc->is_active()) {
61 warning("FIXME: Removing stale gravity pid %d from Avatar.", avatar->getGravityPID());
62 avatar->setGravityPID(0);
63 } else {
64 _idleTime = 0;
65 return;
66 }
67 }
68
69 // not in fast area, don't move (can happen for some death sequences
70 // in Crusader)
71 if (!avatar->hasFlags(Item::FLG_FASTAREA))
72 return;
73
74 bool combatRun = avatar->hasActorFlags(Actor::ACT_COMBATRUN);
75 if (avatar->isInCombat() && !combatRun)
76 handleCombatMode();
77 else
78 handleNormalMode();
79 }
80
81
checkTurn(Direction direction,bool moving)82 bool AvatarMoverProcess::checkTurn(Direction direction, bool moving) {
83 Actor *avatar = getControlledActor();
84 Direction curdir = avatar->getDir();
85 bool combat = avatar->isInCombat() && !avatar->hasActorFlags(Actor::ACT_COMBATRUN);
86
87 // Note: don't need to turn if moving backward in combat stance
88 // CHECKME: currently, first turn in the right direction
89 if (direction != curdir && !(combat && Direction_Invert(direction) == curdir)) {
90 Animation::Sequence lastanim = avatar->getLastAnim();
91
92 if (moving &&
93 (lastanim == Animation::walk || lastanim == Animation::run ||
94 lastanim == Animation::combatStand ||
95 (GAME_IS_CRUSADER && (lastanim == Animation::startRunSmallWeapon ||
96 lastanim == Animation::combatRunSmallWeapon))) &&
97 (ABS(direction - curdir) + 2) % 16 <= 4) {
98 // don't need to explicitly do a turn animation
99 return false;
100 }
101
102 if (moving && lastanim == Animation::run) {
103 // slow down to a walk first
104 waitFor(avatar->doAnim(Animation::walk, curdir));
105 return true;
106 }
107
108 turnToDirection(direction);
109 return true;
110 }
111
112 return false;
113 }
114
turnToDirection(Direction direction)115 void AvatarMoverProcess::turnToDirection(Direction direction) {
116 Actor *avatar = getControlledActor();
117 uint16 turnpid = avatar->turnTowardDir(direction);
118 if (turnpid)
119 waitFor(turnpid);
120 }
121
slowFromRun(Direction direction)122 void AvatarMoverProcess::slowFromRun(Direction direction) {
123 Actor *avatar = getControlledActor();
124 ProcId walkpid = avatar->doAnim(Animation::walk, direction);
125 ProcId standpid = avatar->doAnimAfter(Animation::stand, direction, walkpid);
126 waitFor(standpid);
127 }
128
putAwayWeapon(Direction direction)129 void AvatarMoverProcess::putAwayWeapon(Direction direction) {
130 Actor *avatar = getControlledActor();
131 ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
132 ProcId anim2 = avatar->doAnimAfter(Animation::stand, direction, anim1);
133 waitFor(anim2);
134 }
135
standUpIfNeeded(Direction direction)136 bool AvatarMoverProcess::standUpIfNeeded(Direction direction) {
137 Actor *avatar = getControlledActor();
138 Animation::Sequence lastanim = avatar->getLastAnim();
139 bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
140
141 if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
142 if (!stasis) {
143 waitFor(avatar->doAnim(Animation::standUp, direction));
144 }
145 return true;
146 }
147 return false;
148 }
149
getMovementFlagAxes(int & x,int & y)150 void AvatarMoverProcess::getMovementFlagAxes(int &x, int &y) {
151 y = 0;
152 x = 0;
153 if (hasMovementFlags(MOVE_UP)) {
154 y++;
155 }
156 if (hasMovementFlags(MOVE_DOWN)) {
157 y--;
158 }
159 if (hasMovementFlags(MOVE_LEFT)) {
160 x--;
161 }
162 if (hasMovementFlags(MOVE_RIGHT)) {
163 x++;
164 }
165 }
166
getTurnDirForTurnFlags(Direction direction,DirectionMode dirmode)167 Direction AvatarMoverProcess::getTurnDirForTurnFlags(Direction direction, DirectionMode dirmode) {
168 if (hasMovementFlags(MOVE_TURN_LEFT | MOVE_PENDING_TURN_LEFT)) {
169 direction = Direction_OneLeft(direction, dirmode);
170 }
171
172 if (hasMovementFlags(MOVE_TURN_RIGHT | MOVE_PENDING_TURN_RIGHT)) {
173 direction = Direction_OneRight(direction, dirmode);
174 }
175 return direction;
176 }
177
onMouseDown(int button,int32 mx,int32 my)178 void AvatarMoverProcess::onMouseDown(int button, int32 mx, int32 my) {
179 int bid = 0;
180
181 switch (button) {
182 case Shared::BUTTON_LEFT: {
183 bid = 0;
184 break;
185 }
186 case Shared::BUTTON_RIGHT: {
187 bid = 1;
188 break;
189 }
190 default:
191 CANT_HAPPEN_MSG("invalid MouseDown passed to AvatarMoverProcess");
192 break;
193 };
194
195 _mouseButton[bid]._lastDown = _mouseButton[bid]._curDown;
196 _mouseButton[bid]._curDown = g_system->getMillis();
197 _mouseButton[bid].setState(MBS_DOWN);
198 _mouseButton[bid].clearState(MBS_HANDLED);
199 }
200
onMouseUp(int button)201 void AvatarMoverProcess::onMouseUp(int button) {
202 int bid = 0;
203
204 if (button == Shared::BUTTON_LEFT) {
205 bid = 0;
206 } else if (button == Shared::BUTTON_RIGHT) {
207 bid = 1;
208 } else {
209 CANT_HAPPEN_MSG("invalid MouseUp passed to AvatarMoverProcess");
210 }
211
212 _mouseButton[bid].clearState(MBS_DOWN);
213 }
214
215
saveData(Common::WriteStream * ws)216 void AvatarMoverProcess::saveData(Common::WriteStream *ws) {
217 Process::saveData(ws);
218
219 ws->writeUint32LE(_lastAttack);
220 ws->writeUint32LE(_idleTime);
221 }
222
loadData(Common::ReadStream * rs,uint32 version)223 bool AvatarMoverProcess::loadData(Common::ReadStream *rs, uint32 version) {
224 if (!Process::loadData(rs, version)) return false;
225
226 _lastAttack = rs->readUint32LE();
227 _idleTime = rs->readUint32LE();
228
229 return true;
230 }
231
232 } // End of namespace Ultima8
233 } // End of namespace Ultima
234