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