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 "sludge/floor.h"
24 #include "sludge/graphics.h"
25 #include "sludge/freeze.h"
26 #include "sludge/function.h"
27 #include "sludge/newfatal.h"
28 #include "sludge/objtypes.h"
29 #include "sludge/people.h"
30 #include "sludge/region.h"
31 #include "sludge/sludge.h"
32 #include "sludge/sludger.h"
33 #include "sludge/sound.h"
34 #include "sludge/speech.h"
35 #include "sludge/version.h"
36 
37 #define ANI_STAND 0
38 #define ANI_WALK 1
39 #define ANI_TALK 2
40 
41 namespace Sludge {
42 
43 extern VariableStack *noStack;
44 extern int ssgVersion;
45 
PersonaAnimation()46 PersonaAnimation::PersonaAnimation() {
47 	theSprites = nullptr;
48 	numFrames = 0;
49 	frames = nullptr;
50 }
51 
~PersonaAnimation()52 PersonaAnimation::~PersonaAnimation() {
53 	if (numFrames) {
54 		delete[] frames;
55 		frames = nullptr;
56 	}
57 }
58 
PersonaAnimation(int num,VariableStack * & stacky)59 PersonaAnimation::PersonaAnimation(int num, VariableStack *&stacky) {
60 	theSprites = nullptr;
61 	numFrames = num;
62 	frames = new AnimFrame[num];
63 	int a = num, frameNum = 0, howMany = 0;
64 
65 	while (a) {
66 		a--;
67 		frames[a].noise = 0;
68 		if (stacky->thisVar.varType == SVT_FILE) {
69 			frames[a].noise = stacky->thisVar.varData.intValue;
70 		} else if (stacky->thisVar.varType == SVT_FUNC) {
71 			frames[a].noise = -stacky->thisVar.varData.intValue;
72 		} else if (stacky->thisVar.varType == SVT_STACK) {
73 			stacky->thisVar.varData.theStack->first->thisVar.getValueType(frameNum, SVT_INT);
74 			stacky->thisVar.varData.theStack->first->next->thisVar.getValueType(howMany, SVT_INT);
75 		} else {
76 			stacky->thisVar.getValueType(frameNum, SVT_INT);
77 			howMany = 1;
78 		}
79 		trimStack(stacky);
80 		frames[a].frameNum = frameNum;
81 		frames[a].howMany = howMany;
82 	}
83 }
84 
PersonaAnimation(PersonaAnimation * orig)85 PersonaAnimation::PersonaAnimation(PersonaAnimation *orig) {
86 	int num = orig->numFrames;
87 
88 	// Copy the easy bits...
89 	theSprites = orig->theSprites;
90 	numFrames = num;
91 
92 	if (num) {
93 		// Argh! Frames! We need a whole NEW array of AnimFrame  structures...
94 		frames = new AnimFrame[num];
95 
96 		for (int a = 0; a < num; a++) {
97 			frames[a].frameNum = orig->frames[a].frameNum;
98 			frames[a].howMany = orig->frames[a].howMany;
99 			frames[a].noise = orig->frames[a].noise;
100 		}
101 	} else {
102 		frames = nullptr;
103 	}
104 }
105 
getTotalTime()106 int PersonaAnimation::getTotalTime() {
107 	int total = 0;
108 	for (int a = 0; a < numFrames; a++) {
109 		total += frames[a].howMany;
110 	}
111 	return total;
112 }
113 
save(Common::WriteStream * stream)114 bool PersonaAnimation::save(Common::WriteStream *stream) {
115 	stream->writeUint16BE(numFrames);
116 	if (numFrames) {
117 		stream->writeUint32LE(theSprites->ID);
118 
119 		for (int a = 0; a < numFrames; a++) {
120 			stream->writeUint32LE(frames[a].frameNum);
121 			stream->writeUint32LE(frames[a].howMany);
122 			stream->writeUint32LE(frames[a].noise);
123 		}
124 	}
125 	return true;
126 }
127 
load(Common::SeekableReadStream * stream)128 bool PersonaAnimation::load(Common::SeekableReadStream *stream) {
129 	numFrames = stream->readUint16BE();
130 
131 	if (numFrames) {
132 		int a = stream->readUint32LE();
133 		frames = new AnimFrame [numFrames];
134 		if (!checkNew(frames))
135 			return false;
136 		theSprites = g_sludge->_gfxMan->loadBankForAnim(a);
137 
138 		for (a = 0; a < numFrames; a++) {
139 			frames[a].frameNum = stream->readUint32LE();
140 			frames[a].howMany = stream->readUint32LE();
141 			if (ssgVersion >= VERSION(2, 0)) {
142 				frames[a].noise = stream->readUint32LE();
143 			} else {
144 				frames[a].noise = 0;
145 			}
146 		}
147 	} else {
148 		theSprites = NULL;
149 		frames = NULL;
150 	}
151 	return true;
152 }
153 
save(Common::WriteStream * stream)154 bool Persona::save(Common::WriteStream *stream) {
155 	int a;
156 	stream->writeUint16BE(numDirections);
157 	for (a = 0; a < numDirections * 3; a++) {
158 		if (!animation[a]->save(stream))
159 			return false;
160 	}
161 	return true;
162 }
163 
load(Common::SeekableReadStream * stream)164 bool Persona::load(Common::SeekableReadStream *stream) {
165 	int a;
166 	numDirections = stream->readUint16BE();
167 	animation = new PersonaAnimation *[numDirections * 3];
168 	if (!checkNew(animation))
169 		return false;
170 	for (a = 0; a < numDirections * 3; a++) {
171 		animation[a] = new PersonaAnimation;
172 		if (!checkNew(animation[a]))
173 			return false;
174 
175 		if (!animation[a]->load(stream))
176 			return false;
177 	}
178 	return true;
179 }
180 
setFrames(int a)181 void OnScreenPerson::setFrames(int a) {
182 	myAnim = myPersona->animation[(a * myPersona->numDirections) + direction];
183 }
184 
makeTalker()185 void OnScreenPerson::makeTalker() {
186 	setFrames(ANI_TALK);
187 }
188 
makeSilent()189 void OnScreenPerson::makeSilent() {
190 	setFrames(ANI_STAND);
191 }
192 
PeopleManager(SludgeEngine * vm)193 PeopleManager::PeopleManager(SludgeEngine *vm) {
194 	_vm = vm;
195 	_allPeople = new OnScreenPersonList;
196 	_scaleHorizon = 75;
197 	_scaleDivide = 150;
198 	_personRegion = new ScreenRegion;
199 }
200 
~PeopleManager()201 PeopleManager::~PeopleManager() {
202 	kill();
203 
204 	delete _personRegion;
205 	_personRegion = nullptr;
206 
207 	delete _allPeople;
208 	_allPeople = nullptr;
209 }
210 
turnMeAngle(OnScreenPerson * thisPerson,int direc)211 void PeopleManager::turnMeAngle(OnScreenPerson *thisPerson, int direc) {
212 	int d = thisPerson->myPersona->numDirections;
213 	thisPerson->angle = direc;
214 	direc += (180 / d) + 180 + thisPerson->angleOffset;
215 	while (direc >= 360)
216 		direc -= 360;
217 	thisPerson->direction = (direc * d) / 360;
218 }
219 
init()220 bool PeopleManager::init() {
221 	_personRegion->sX = 0;
222 	_personRegion->sY = 0;
223 	_personRegion->di = -1;
224 	return true;
225 }
226 
spinStep(OnScreenPerson * thisPerson)227 void PeopleManager::spinStep(OnScreenPerson *thisPerson) {
228 	int diff = (thisPerson->angle + 360) - thisPerson->wantAngle;
229 	int eachSlice = thisPerson->spinSpeed ? thisPerson->spinSpeed : (360 / thisPerson->myPersona->numDirections);
230 	while (diff > 180) {
231 		diff -= 360;
232 	}
233 
234 	if (diff >= eachSlice) {
235 		turnMeAngle(thisPerson, thisPerson->angle - eachSlice);
236 	} else if (diff <= -eachSlice) {
237 		turnMeAngle(thisPerson, thisPerson->angle + eachSlice);
238 	} else {
239 		turnMeAngle(thisPerson, thisPerson->wantAngle);
240 		thisPerson->spinning = false;
241 	}
242 }
243 
rethinkAngle(OnScreenPerson * thisPerson)244 void PeopleManager::rethinkAngle(OnScreenPerson *thisPerson) {
245 	int d = thisPerson->myPersona->numDirections;
246 	int direc = thisPerson->angle + (180 / d) + 180 + thisPerson->angleOffset;
247 	while (direc >= 360)
248 		direc -= 360;
249 	thisPerson->direction = (direc * d) / 360;
250 }
251 
turnPersonToFace(int thisNum,int direc)252 bool PeopleManager::turnPersonToFace(int thisNum, int direc) {
253 	OnScreenPerson *thisPerson = findPerson(thisNum);
254 	if (thisPerson) {
255 		if (thisPerson->continueAfterWalking)
256 			abortFunction(thisPerson->continueAfterWalking);
257 		thisPerson->continueAfterWalking = NULL;
258 		thisPerson->walking = false;
259 		thisPerson->spinning = false;
260 		turnMeAngle(thisPerson, direc);
261 		_vm->_speechMan->isCurrentTalker(thisPerson) ?
262 				thisPerson->makeTalker() : thisPerson->makeSilent();
263 		return true;
264 	}
265 	return false;
266 }
267 
setPersonExtra(int thisNum,int extra)268 bool PeopleManager::setPersonExtra(int thisNum, int extra) {
269 	OnScreenPerson *thisPerson = findPerson(thisNum);
270 	if (thisPerson) {
271 		thisPerson->extra = extra;
272 		if (extra & EXTRA_NOSCALE)
273 			thisPerson->scale = 1;
274 		return true;
275 	}
276 	return false;
277 }
278 
setScale(int16 h,int16 d)279 void PeopleManager::setScale(int16 h, int16 d) {
280 	_scaleHorizon = h;
281 	_scaleDivide = d;
282 }
283 
moveAndScale(OnScreenPerson & me,float x,float y)284 void PeopleManager::moveAndScale(OnScreenPerson &me, float x, float y) {
285 	me.x = x;
286 	me.y = y;
287 	if (!(me.extra & EXTRA_NOSCALE) && _scaleDivide)
288 		me.scale = (me.y - _scaleHorizon) / _scaleDivide;
289 }
290 
findPerson(int v)291 OnScreenPerson *PeopleManager::findPerson(int v) {
292 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
293 		if (v == (*it)->thisType->objectNum) {
294 			return (*it);
295 		}
296 	}
297 	return nullptr;
298 }
299 
movePerson(int x,int y,int objNum)300 void PeopleManager::movePerson(int x, int y, int objNum) {
301 	OnScreenPerson *moveMe = findPerson(objNum);
302 	if (moveMe)
303 		moveAndScale(*moveMe, x, y);
304 }
305 
setShown(bool h,int ob)306 void PeopleManager::setShown(bool h, int ob) {
307 	OnScreenPerson *moveMe = findPerson(ob);
308 	if (moveMe)
309 		moveMe->show = h;
310 }
311 
312 enum drawModes {
313 	drawModeNormal,
314 	drawModeTransparent1,
315 	drawModeTransparent2,
316 	drawModeTransparent3,
317 	drawModeDark1,
318 	drawModeDark2,
319 	drawModeDark3,
320 	drawModeBlack,
321 	drawModeShadow1,
322 	drawModeShadow2,
323 	drawModeShadow3,
324 	drawModeFoggy1,
325 	drawModeFoggy2,
326 	drawModeFoggy3,
327 	drawModeFoggy4,
328 	drawModeGlow1,
329 	drawModeGlow2,
330 	drawModeGlow3,
331 	drawModeGlow4,
332 	drawModeInvisible,
333 	numDrawModes
334 };
335 
setMyDrawMode(OnScreenPerson * moveMe,int h)336 void PeopleManager::setMyDrawMode(OnScreenPerson *moveMe, int h) {
337 	switch (h) {
338 	case drawModeTransparent3:
339 		moveMe->r = moveMe->g = moveMe->b = 0;
340 		moveMe->colourmix = 0;
341 		moveMe->transparency = 64;
342 		break;
343 	case drawModeTransparent2:
344 		moveMe->r = moveMe->g = moveMe->b = 0;
345 		moveMe->colourmix = 0;
346 		moveMe->transparency = 128;
347 		break;
348 	case drawModeTransparent1:
349 		moveMe->r = moveMe->g = moveMe->b = 0;
350 		moveMe->colourmix = 0;
351 		moveMe->transparency = 192;
352 		break;
353 	case drawModeInvisible:
354 		moveMe->r = moveMe->g = moveMe->b = 0;
355 		moveMe->colourmix = 0;
356 		moveMe->transparency = 254;
357 		break;
358 	case drawModeDark1:
359 		moveMe->r = moveMe->g = moveMe->b = 0;
360 		moveMe->colourmix = 192;
361 		moveMe->transparency = 0;
362 		break;
363 	case drawModeDark2:
364 		moveMe->r = moveMe->g = moveMe->b = 0;
365 		moveMe->colourmix = 128;
366 		moveMe->transparency = 0;
367 		break;
368 	case drawModeDark3:
369 		moveMe->r = moveMe->g = moveMe->b = 0;
370 		moveMe->colourmix = 64;
371 		moveMe->transparency = 0;
372 		break;
373 	case drawModeBlack:
374 		moveMe->r = moveMe->g = moveMe->b = 0;
375 		moveMe->colourmix = 255;
376 		moveMe->transparency = 0;
377 		break;
378 	case drawModeShadow1:
379 		moveMe->r = moveMe->g = moveMe->b = 0;
380 		moveMe->colourmix = 255;
381 		moveMe->transparency = 64;
382 		break;
383 	case drawModeShadow2:
384 		moveMe->r = moveMe->g = moveMe->b = 0;
385 		moveMe->colourmix = 255;
386 		moveMe->transparency = 128;
387 		break;
388 	case drawModeShadow3:
389 		moveMe->r = moveMe->g = moveMe->b = 0;
390 		moveMe->colourmix = 255;
391 		moveMe->transparency = 192;
392 		break;
393 	case drawModeFoggy3:
394 		moveMe->r = moveMe->g = moveMe->b = 128;
395 		moveMe->colourmix = 192;
396 		moveMe->transparency = 0;
397 		break;
398 	case drawModeFoggy2:
399 		moveMe->r = moveMe->g = moveMe->b = 128;
400 		moveMe->colourmix = 128;
401 		moveMe->transparency = 0;
402 		break;
403 	case drawModeFoggy1:
404 		moveMe->r = moveMe->g = moveMe->b = 128;
405 		moveMe->colourmix = 64;
406 		moveMe->transparency = 0;
407 		break;
408 	case drawModeFoggy4:
409 		moveMe->r = moveMe->g = moveMe->b = 128;
410 		moveMe->colourmix = 255;
411 		moveMe->transparency = 0;
412 		break;
413 	case drawModeGlow3:
414 		moveMe->r = moveMe->g = moveMe->b = 255;
415 		moveMe->colourmix = 192;
416 		moveMe->transparency = 0;
417 		break;
418 	case drawModeGlow2:
419 		moveMe->r = moveMe->g = moveMe->b = 255;
420 		moveMe->colourmix = 128;
421 		moveMe->transparency = 0;
422 		break;
423 	case drawModeGlow1:
424 		moveMe->r = moveMe->g = moveMe->b = 255;
425 		moveMe->colourmix = 64;
426 		moveMe->transparency = 0;
427 		break;
428 	case drawModeGlow4:
429 		moveMe->r = moveMe->g = moveMe->b = 255;
430 		moveMe->colourmix = 255;
431 		moveMe->transparency = 0;
432 		break;
433 	default:
434 		moveMe->r = moveMe->g = moveMe->b = 0;
435 		moveMe->colourmix = 0;
436 		moveMe->transparency = 0;
437 		break;
438 	}
439 }
440 
setDrawMode(int h,int ob)441 void PeopleManager::setDrawMode(int h, int ob) {
442 	OnScreenPerson *moveMe = findPerson(ob);
443 	if (!moveMe)
444 		return;
445 
446 	setMyDrawMode(moveMe, h);
447 }
448 
setPersonTransparency(int ob,byte x)449 void PeopleManager::setPersonTransparency(int ob, byte x) {
450 	OnScreenPerson *moveMe = findPerson(ob);
451 	if (!moveMe)
452 		return;
453 
454 	if (x > 254)
455 		x = 254;
456 	moveMe->transparency = x;
457 }
458 
setPersonColourise(int ob,byte r,byte g,byte b,byte colourmix)459 void PeopleManager::setPersonColourise(int ob, byte r, byte g, byte b, byte colourmix) {
460 	OnScreenPerson *moveMe = findPerson(ob);
461 	if (!moveMe)
462 		return;
463 
464 	moveMe->r = r;
465 	moveMe->g = g;
466 	moveMe->b = b;
467 	moveMe->colourmix = colourmix;
468 }
469 
470 struct PeopleYComperator {
operator ()Sludge::PeopleYComperator471 	bool operator()(const OnScreenPerson *p1, const OnScreenPerson *p2) {
472 		float y1 = p1->extra & EXTRA_FRONT ? p1->y + 1000 : p1->y;
473 		float y2 = p2->extra & EXTRA_FRONT ? p2->y + 1000 : p2->y;
474 		return y1 < y2;
475 	}
476 };
477 
shufflePeople()478 void PeopleManager::shufflePeople() {
479 	if (_allPeople->empty())
480 		return;
481 
482 	Common::sort(_allPeople->begin(), _allPeople->end(), PeopleYComperator());
483 }
484 
drawPeople()485 void PeopleManager::drawPeople() {
486 	shufflePeople();
487 
488 	PersonaAnimation *myAnim = NULL;
489 	_vm->_regionMan->resetOverRegion();
490 
491 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
492 		OnScreenPerson * thisPerson = (*it);
493 		if (thisPerson->show) {
494 			myAnim = thisPerson->myAnim;
495 			if (myAnim != thisPerson->lastUsedAnim) {
496 				thisPerson->lastUsedAnim = myAnim;
497 				thisPerson->frameNum = 0;
498 				thisPerson->frameTick = myAnim->frames[0].howMany;
499 				if (myAnim->frames[thisPerson->frameNum].noise > 0) {
500 					_vm->_soundMan->startSound(myAnim->frames[thisPerson->frameNum].noise, false);
501 					thisPerson->frameNum++;
502 					thisPerson->frameNum %= thisPerson->myAnim->numFrames;
503 					thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
504 				} else if (myAnim->frames[thisPerson->frameNum].noise) {
505 					startNewFunctionNum(-myAnim->frames[thisPerson->frameNum].noise, 0,
506 					NULL, noStack);
507 					thisPerson->frameNum++;
508 					thisPerson->frameNum %= thisPerson->myAnim->numFrames;
509 					thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
510 				}
511 			}
512 			int fNumSign = myAnim->frames[thisPerson->frameNum].frameNum;
513 			int m = fNumSign < 0;
514 			int fNum = ABS(fNumSign);
515 			if (fNum >= myAnim->theSprites->bank.total) {
516 				fNum = 0;
517 				m = 2 - m;
518 			}
519 			if (m != 2) {
520 				bool r = false;
521 				r = _vm->_gfxMan->scaleSprite(myAnim->theSprites->bank.sprites[fNum], myAnim->theSprites->bank.myPalette, thisPerson, m);
522 				if (r) {
523 					if (!thisPerson->thisType->screenName.empty()) {
524 						if (_personRegion->thisType != thisPerson->thisType)
525 							_vm->_regionMan->resetLastRegion();
526 						_personRegion->thisType = thisPerson->thisType;
527 						_vm->_regionMan->setOverRegion(_personRegion);
528 					}
529 				}
530 			}
531 		}
532 		if (!--thisPerson->frameTick) {
533 			thisPerson->frameNum++;
534 			thisPerson->frameNum %= thisPerson->myAnim->numFrames;
535 			thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
536 			if (thisPerson->show && myAnim && myAnim->frames) {
537 				if (myAnim->frames[thisPerson->frameNum].noise > 0) {
538 					_vm->_soundMan->startSound(myAnim->frames[thisPerson->frameNum].noise, false);
539 					thisPerson->frameNum++;
540 					thisPerson->frameNum %= thisPerson->myAnim->numFrames;
541 					thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
542 				} else if (myAnim->frames[thisPerson->frameNum].noise) {
543 					startNewFunctionNum(-myAnim->frames[thisPerson->frameNum].noise, 0,
544 					NULL, noStack);
545 					thisPerson->frameNum++;
546 					thisPerson->frameNum %= thisPerson->myAnim->numFrames;
547 					thisPerson->frameTick = thisPerson->myAnim->frames[thisPerson->frameNum].howMany;
548 				}
549 			}
550 		}
551 	}
552 }
553 
walkMe(OnScreenPerson * thisPerson,bool move)554 bool PeopleManager::walkMe(OnScreenPerson *thisPerson, bool move) {
555 	float xDiff, yDiff, maxDiff, s;
556 
557 	for (;;) {
558 		xDiff = thisPerson->thisStepX - thisPerson->x;
559 		yDiff = (thisPerson->thisStepY - thisPerson->y) * 2;
560 		s = thisPerson->scale * thisPerson->walkSpeed;
561 		if (s < 0.2)
562 			s = (float)0.2;
563 
564 		maxDiff = (ABS(xDiff) >= ABS(yDiff)) ? ABS(xDiff) : ABS(yDiff);
565 
566 		if (ABS(maxDiff) > s) {
567 			if (thisPerson->spinning) {
568 				spinStep(thisPerson);
569 				thisPerson->setFrames(ANI_WALK);
570 			}
571 			s = maxDiff / s;
572 			if (move)
573 				moveAndScale(*thisPerson, thisPerson->x + xDiff / s, thisPerson->y + yDiff / (s * 2));
574 			return true;
575 		}
576 
577 		if (thisPerson->inPoly == -1) {
578 			if (thisPerson->directionWhenDoneWalking != -1) {
579 				thisPerson->wantAngle = thisPerson->directionWhenDoneWalking;
580 				thisPerson->spinning = true;
581 				spinStep(thisPerson);
582 			}
583 			break;
584 		}
585 		if (!_vm->_floorMan->doBorderStuff(thisPerson))
586 			break;
587 	}
588 
589 	thisPerson->walking = false;
590 	thisPerson->setFrames(ANI_STAND);
591 	moveAndScale(*thisPerson, thisPerson->walkToX, thisPerson->walkToY);
592 	return false;
593 }
594 
makeWalkingPerson(int x,int y,int objNum,LoadedFunction * func,int di)595 bool PeopleManager::makeWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
596 	if (x == 0 && y == 0)
597 		return false;
598 	if (_vm->_floorMan->isFloorNoPolygon())
599 		return false;
600 	OnScreenPerson *moveMe = findPerson(objNum);
601 	if (!moveMe)
602 		return false;
603 
604 	if (moveMe->continueAfterWalking)
605 		abortFunction(moveMe->continueAfterWalking);
606 	moveMe->continueAfterWalking = NULL;
607 	moveMe->walking = true;
608 	moveMe->directionWhenDoneWalking = di;
609 
610 	moveMe->walkToX = x;
611 	moveMe->walkToY = y;
612 	moveMe->walkToPoly = _vm->_floorMan->inFloor(x, y);
613 	if (moveMe->walkToPoly == -1) {
614 		if (!_vm->_floorMan->handleClosestPoint(moveMe->walkToX, moveMe->walkToY, moveMe->walkToPoly))
615 			return false;
616 	}
617 
618 	moveMe->inPoly = _vm->_floorMan->inFloor(moveMe->x, moveMe->y);
619 	if (moveMe->inPoly == -1) {
620 		int xxx = moveMe->x, yyy = moveMe->y;
621 		if (!_vm->_floorMan->handleClosestPoint(xxx, yyy, moveMe->inPoly))
622 			return false;
623 	}
624 
625 	_vm->_floorMan->doBorderStuff(moveMe);
626 	if (walkMe(moveMe, false) || moveMe->spinning) {
627 		moveMe->continueAfterWalking = func;
628 		return true;
629 	} else {
630 		return false;
631 	}
632 }
633 
stopPerson(int o)634 bool PeopleManager::stopPerson(int o) {
635 	OnScreenPerson *moveMe = findPerson(o);
636 	if (moveMe)
637 		if (moveMe->continueAfterWalking) {
638 			abortFunction(moveMe->continueAfterWalking);
639 			moveMe->continueAfterWalking = NULL;
640 			moveMe->walking = false;
641 			moveMe->spinning = false;
642 			moveMe->setFrames(ANI_STAND);
643 			return true;
644 		}
645 	return false;
646 }
647 
forceWalkingPerson(int x,int y,int objNum,LoadedFunction * func,int di)648 bool PeopleManager::forceWalkingPerson(int x, int y, int objNum, LoadedFunction *func, int di) {
649 	if (x == 0 && y == 0)
650 		return false;
651 	OnScreenPerson *moveMe = findPerson(objNum);
652 	if (!moveMe)
653 		return false;
654 
655 	if (moveMe->continueAfterWalking)
656 		abortFunction(moveMe->continueAfterWalking);
657 	moveMe->walking = true;
658 	moveMe->continueAfterWalking = NULL;
659 	moveMe->directionWhenDoneWalking = di;
660 
661 	moveMe->walkToX = x;
662 	moveMe->walkToY = y;
663 
664 	// Let's pretend the start and end points are both in the same
665 	// polygon (which one isn't important)
666 	moveMe->inPoly = 0;
667 	moveMe->walkToPoly = 0;
668 
669 	_vm->_floorMan->doBorderStuff(moveMe);
670 	if (walkMe(moveMe) || moveMe->spinning) {
671 		moveMe->continueAfterWalking = func;
672 		return true;
673 	} else {
674 		return false;
675 	}
676 }
677 
jumpPerson(int x,int y,int objNum)678 void PeopleManager::jumpPerson(int x, int y, int objNum) {
679 	if (x == 0 && y == 0)
680 		return;
681 	OnScreenPerson *moveMe = findPerson(objNum);
682 	if (!moveMe)
683 		return;
684 	if (moveMe->continueAfterWalking)
685 		abortFunction(moveMe->continueAfterWalking);
686 	moveMe->continueAfterWalking = NULL;
687 	moveMe->walking = false;
688 	moveMe->spinning = false;
689 	moveAndScale(*moveMe, x, y);
690 }
691 
floatCharacter(int f,int objNum)692 bool PeopleManager::floatCharacter(int f, int objNum) {
693 	OnScreenPerson *moveMe = findPerson(objNum);
694 	if (!moveMe)
695 		return false;
696 	moveMe->floaty = f;
697 	return true;
698 }
699 
setCharacterWalkSpeed(int f,int objNum)700 bool PeopleManager::setCharacterWalkSpeed(int f, int objNum) {
701 	if (f <= 0)
702 		return false;
703 	OnScreenPerson *moveMe = findPerson(objNum);
704 	if (!moveMe)
705 		return false;
706 	moveMe->walkSpeed = f;
707 	return true;
708 }
709 
walkAllPeople()710 void PeopleManager::walkAllPeople() {
711 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
712 		OnScreenPerson *thisPerson = (*it);
713 		if (thisPerson->walking) {
714 			walkMe(thisPerson);
715 		} else if (thisPerson->spinning) {
716 			spinStep(thisPerson);
717 			thisPerson->setFrames(ANI_STAND);
718 		}
719 		if ((!thisPerson->walking) && (!thisPerson->spinning) && thisPerson->continueAfterWalking) {
720 			restartFunction(thisPerson->continueAfterWalking);
721 			thisPerson->continueAfterWalking = NULL;
722 		}
723 	}
724 }
725 
addPerson(int x,int y,int objNum,Persona * p)726 bool PeopleManager::addPerson(int x, int y, int objNum, Persona *p) {
727 	OnScreenPerson *newPerson = new OnScreenPerson;
728 	if (!checkNew(newPerson))
729 		return false;
730 
731 	// Init newPerson
732 	newPerson->thisType = _vm->_objMan->loadObjectType(objNum);
733 	newPerson->scale = 1;
734 	newPerson->extra = 0;
735 	newPerson->continueAfterWalking = NULL;
736 	moveAndScale(*newPerson, x, y);
737 	newPerson->frameNum = 0;
738 	newPerson->walkToX = x;
739 	newPerson->walkToY = y;
740 	newPerson->walking = false;
741 	newPerson->spinning = false;
742 	newPerson->show = true;
743 	newPerson->direction = 0;
744 	newPerson->angle = 180;
745 	newPerson->wantAngle = 180;
746 	newPerson->angleOffset = 0;
747 	newPerson->floaty = 0;
748 	newPerson->walkSpeed = newPerson->thisType->walkSpeed;
749 	newPerson->myAnim = NULL;
750 	newPerson->spinSpeed = newPerson->thisType->spinSpeed;
751 	newPerson->r = 0;
752 	newPerson->g = 0;
753 	newPerson->b = 0;
754 	newPerson->colourmix = 0;
755 	newPerson->transparency = 0;
756 	newPerson->myPersona = p;
757 	newPerson->lastUsedAnim = 0;
758 	newPerson->frameTick = 0;
759 
760 	newPerson->setFrames(ANI_STAND);
761 
762 	// HEIGHT (BASED ON 1st FRAME OF 1st ANIMATION... INC. SPECIAL CASES)
763 	int fNumSigned = p->animation[0]->frames[0].frameNum;
764 	int fNum = abs(fNumSigned);
765 	if (fNum >= p->animation[0]->theSprites->bank.total) {
766 		if (fNumSigned < 0) {
767 			newPerson->height = 5;
768 		} else {
769 			newPerson->height = p->animation[0]->theSprites->bank.sprites[0].yhot + 5;
770 		}
771 	} else {
772 		newPerson->height = p->animation[0]->theSprites->bank.sprites[fNum].yhot + 5;
773 	}
774 
775 	// NOW INSERT IT IN THE RIGHT PLACE
776 	bool inserted = false;
777 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
778 		if ((*it)->y >= y) {
779 			_allPeople->insert(it, newPerson);
780 			inserted = true;
781 			break;
782 		}
783 	}
784 	if (!inserted) {
785 		_allPeople->push_back(newPerson);
786 	}
787 
788 	return (bool)(newPerson->thisType != NULL);
789 }
790 
animatePerson(int obj,PersonaAnimation * fram)791 void PeopleManager::animatePerson(int obj, PersonaAnimation *fram) { // Set a new SINGLE animation
792 	OnScreenPerson *moveMe = findPerson(obj);
793 	if (moveMe) {
794 		if (moveMe->continueAfterWalking)
795 			abortFunction(moveMe->continueAfterWalking);
796 		moveMe->continueAfterWalking = NULL;
797 		moveMe->walking = false;
798 		moveMe->spinning = false;
799 		moveMe->myAnim = fram;
800 	}
801 }
802 
animatePerson(int obj,Persona * per)803 void PeopleManager::animatePerson(int obj, Persona *per) {             // Set a new costume
804 	OnScreenPerson *moveMe = findPerson(obj);
805 	if (moveMe) {
806 		moveMe->spinning = false;
807 		moveMe->myPersona = per;
808 		rethinkAngle(moveMe);
809 		if (moveMe->walking) {
810 			moveMe->setFrames(ANI_WALK);
811 		} else {
812 			moveMe->setFrames(ANI_STAND);
813 		}
814 	}
815 }
816 
kill()817 void PeopleManager::kill() {
818 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
819 		if ((*it)->continueAfterWalking)
820 			abortFunction((*it)->continueAfterWalking);
821 		(*it)->continueAfterWalking = NULL;
822 		_vm->_objMan->removeObjectType((*it)->thisType);
823 		delete (*it);
824 		(*it) = nullptr;
825 	}
826 	_allPeople->clear();
827 }
828 
killMostPeople()829 void PeopleManager::killMostPeople() {
830 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
831 		if (!((*it)->extra & EXTRA_NOREMOVE)) {
832 			OnScreenPerson *killPeople = (*it);
833 			it = _allPeople->reverse_erase(it);
834 
835 			// Gone from the list... now free some memory
836 			if (killPeople->continueAfterWalking)
837 				abortFunction(killPeople->continueAfterWalking);
838 			killPeople->continueAfterWalking = NULL;
839 			_vm->_objMan->removeObjectType(killPeople->thisType);
840 			delete killPeople;
841 		}
842 	}
843 }
844 
removeOneCharacter(int i)845 void PeopleManager::removeOneCharacter(int i) {
846 	OnScreenPerson *removePerson = findPerson(i);
847 	if (removePerson) {
848 		ScreenRegion *overRegion = _vm->_regionMan->getOverRegion();
849 		if (overRegion == _personRegion && overRegion->thisType == removePerson->thisType) {
850 			overRegion = nullptr;
851 		}
852 
853 		if (removePerson->continueAfterWalking)
854 			abortFunction(removePerson->continueAfterWalking);
855 		removePerson->continueAfterWalking = NULL;
856 
857 		_allPeople->remove(removePerson);
858 		_vm->_objMan->removeObjectType(removePerson->thisType);
859 		delete removePerson;
860 		removePerson = nullptr;
861 	}
862 }
863 
savePeople(Common::WriteStream * stream)864 bool PeopleManager::savePeople(Common::WriteStream* stream) {
865 	stream->writeSint16LE(_scaleHorizon);
866 	stream->writeSint16LE(_scaleDivide);
867 	int countPeople = _allPeople->size();
868 	stream->writeUint16BE(countPeople);
869 	for (OnScreenPersonList::iterator it = _allPeople->begin(); it != _allPeople->end(); ++it) {
870 		stream->writeFloatLE((*it)->x);
871 		stream->writeFloatLE((*it)->y);
872 		(*it)->myPersona->save(stream);
873 		(*it)->myAnim->save(stream);
874 		stream->writeByte((*it)->myAnim == (*it)->lastUsedAnim);
875 		stream->writeFloatLE((*it)->scale);
876 		stream->writeUint16BE((*it)->extra);
877 		stream->writeUint16BE((*it)->height);
878 		stream->writeUint16BE((*it)->walkToX);
879 		stream->writeUint16BE((*it)->walkToY);
880 		stream->writeUint16BE((*it)->thisStepX);
881 		stream->writeUint16BE((*it)->thisStepY);
882 		stream->writeUint16BE((*it)->frameNum);
883 		stream->writeUint16BE((*it)->frameTick);
884 		stream->writeUint16BE((*it)->walkSpeed);
885 		stream->writeUint16BE((*it)->spinSpeed);
886 		stream->writeSint16LE((*it)->floaty);
887 		stream->writeByte((*it)->show);
888 		stream->writeByte((*it)->walking);
889 		stream->writeByte((*it)->spinning);
890 		if ((*it)->continueAfterWalking) {
891 			stream->writeByte(1);
892 			saveFunction((*it)->continueAfterWalking, stream);
893 		} else {
894 			stream->writeByte(0);
895 		}
896 		stream->writeUint16BE((*it)->direction);
897 		stream->writeUint16BE((*it)->angle);
898 		stream->writeUint16BE((*it)->angleOffset);
899 		stream->writeUint16BE((*it)->wantAngle);
900 		stream->writeSint16LE((*it)->directionWhenDoneWalking);
901 		stream->writeSint16LE((*it)->inPoly);
902 		stream->writeSint16LE((*it)->walkToPoly);
903 		stream->writeByte((*it)->r);
904 		stream->writeByte((*it)->g);
905 		stream->writeByte((*it)->b);
906 		stream->writeByte((*it)->colourmix);
907 		stream->writeByte((*it)->transparency);
908 		_vm->_objMan->saveObjectRef((*it)->thisType, stream);
909 	}
910 	return true;
911 }
912 
loadPeople(Common::SeekableReadStream * stream)913 bool PeopleManager::loadPeople(Common::SeekableReadStream *stream) {
914 	kill();
915 
916 	_scaleHorizon = stream->readSint16LE();
917 	_scaleDivide = stream->readSint16LE();
918 
919 	int countPeople = stream->readUint16BE();
920 	int a;
921 
922 	for (a = 0; a < countPeople; a++) {
923 		OnScreenPerson *me = new OnScreenPerson;
924 		if (!checkNew(me))
925 			return false;
926 
927 		me->myPersona = new Persona;
928 		if (!checkNew(me->myPersona))
929 			return false;
930 
931 		me->myAnim = new PersonaAnimation;
932 		if (!checkNew(me->myAnim))
933 			return false;
934 
935 		me->x = stream->readFloatLE();
936 		me->y = stream->readFloatLE();
937 
938 		me->myPersona->load(stream);
939 		me->myAnim->load(stream);
940 
941 		me->lastUsedAnim = stream->readByte() ? me->myAnim : NULL;
942 
943 		me->scale = stream->readFloatLE();
944 
945 		me->extra = stream->readUint16BE();
946 		me->height = stream->readUint16BE();
947 		me->walkToX = stream->readUint16BE();
948 		me->walkToY = stream->readUint16BE();
949 		me->thisStepX = stream->readUint16BE();
950 		me->thisStepY = stream->readUint16BE();
951 		me->frameNum = stream->readUint16BE();
952 		me->frameTick = stream->readUint16BE();
953 		me->walkSpeed = stream->readUint16BE();
954 		me->spinSpeed = stream->readUint16BE();
955 		me->floaty = stream->readSint16LE();
956 		me->show = stream->readByte();
957 		me->walking = stream->readByte();
958 		me->spinning = stream->readByte();
959 		if (stream->readByte()) {
960 			me->continueAfterWalking = loadFunction(stream);
961 			if (!me->continueAfterWalking)
962 				return false;
963 		} else {
964 			me->continueAfterWalking = NULL;
965 		}
966 		me->direction = stream->readUint16BE();
967 		me->angle = stream->readUint16BE();
968 		if (ssgVersion >= VERSION(2, 0)) {
969 			me->angleOffset = stream->readUint16BE();
970 		} else {
971 			me->angleOffset = 0;
972 		}
973 		me->wantAngle = stream->readUint16BE();
974 		me->directionWhenDoneWalking = stream->readSint16LE();
975 		me->inPoly = stream->readSint16LE();
976 		me->walkToPoly = stream->readSint16LE();
977 		if (ssgVersion >= VERSION(2, 0)) {
978 			me->r = stream->readByte();
979 			me->g = stream->readByte();
980 			me->b = stream->readByte();
981 			me->colourmix = stream->readByte();
982 			me->transparency = stream->readByte();
983 		} else {
984 			setMyDrawMode(me, stream->readUint16BE());
985 		}
986 		me->thisType = _vm->_objMan->loadObjectRef(stream);
987 
988 		// Anti-aliasing settings
989 		if (ssgVersion >= VERSION(1, 6)) {
990 			if (ssgVersion < VERSION(2, 0)) {
991 				// aaLoad
992 				stream->readByte();
993 				stream->readFloatLE();
994 				stream->readFloatLE();
995 			}
996 		}
997 		_allPeople->push_back(me);
998 	}
999 	return true;
1000 }
1001 
freeze(FrozenStuffStruct * frozenStuff)1002 void PeopleManager::freeze(FrozenStuffStruct *frozenStuff) {
1003 	frozenStuff->allPeople = _allPeople;
1004 	_allPeople = nullptr;
1005 	_allPeople = new OnScreenPersonList;
1006 }
1007 
resotre(FrozenStuffStruct * frozenStuff)1008 void PeopleManager::resotre(FrozenStuffStruct *frozenStuff) {
1009 	kill();
1010 	delete _allPeople;
1011 	_allPeople = nullptr;
1012 	_allPeople = frozenStuff->allPeople;
1013 }
1014 
1015 } // End of namespace Sludge
1016