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