1 /*
2  * Holotz's Castle
3  * Copyright (C) 2004 Juan Carlos Seijo P�rez
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc., 59
17  * Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Juan Carlos Seijo P�rez
20  * jacob@mainreactor.net
21  */
22 
23 /** Holotz's Castle main character definition file.
24  * @file    HCCharacter.cpp
25  * @author  Juan Carlos Seijo P�rez
26  * @date    30/04/2004
27  * @version 0.0.1 - 30/04/2004 - First version.
28  */
29 
30 #include <HCCharacter.h>
31 
HCCharacter()32 HCCharacter::HCCharacter()
33 {
34 	state = HCCS_STOP;
35 	actions = 0;
36 	lastAction = 0;
37 	maxFallRows = 2;
38 	startJumpRow = -1;
39 	maxJumpRows = 0;
40 	maxJumpCols = 0;
41 	v.x = v.y = 0.0f;
42 	a.x = a.y = 0.0f;
43 	vMax.x = 5.0f;
44 	vMax.y = 9.0f;
45 	vJumpMax.x = vMax.x;
46 	vJumpMax.y = 0.0f;
47 	aMax.x = vMax.x;
48 	aMax.y = vMax.y;
49 
50 	breakRow = -1;
51 	trackRope = 0;
52 	dialog = 0;
53 	subtype = 0;
54 }
55 
Init(JImageSprite * sprites,HCMap * _map,HCRope ** _ropes,s32 nRopes)56 bool HCCharacter::Init(JImageSprite *sprites, HCMap *_map, HCRope **_ropes, s32 nRopes)
57 {
58 	if (0 == sprites)
59 	{
60 		fprintf(stderr, "No sprites for character.\n");
61 
62 		return false;
63 	}
64 
65 	if (0 == _map)
66 	{
67 		fprintf(stderr, "No map for character.\n");
68 
69 		return false;
70 	}
71 
72 	// References the themes' sprites
73 	for (s32 i = 0; i < HCCS_COUNT; ++i)
74 	{
75 		states[i].Ref(sprites[i]);
76 	}
77 
78 	a.x = v.x = a.y = v.y = 0.0f;
79 	map = _map;
80 	ropes = _ropes;
81 	numRopes = nRopes;
82 
83 	// Sets the number of rows for jump and computes the jump velocitty
84 	MaxJumpRows(maxJumpRows);
85 
86 	// Sets hanging parameters depending on the largest frame of the jump left sprites
87 	// Sets the hang hotspot at the middle of the largest frame, the width and height
88 	// are half the maximun of either the width or the height
89 	s32 max = 0;
90 	for (u32 i = 0; i < sprites[HCCS_JUMPLEFT].NumFrames(); ++i)
91 	{
92 		max = (s32)JMax(max, ((JImage *)sprites[HCCS_JUMPLEFT].Frame(i))->Width());
93 		max = (s32)JMax(max, ((JImage *)sprites[HCCS_JUMPLEFT].Frame(i))->Height());
94 	}
95 
96 	hangCheckYOffset = max/2;
97 	hangCheckSize = max/2;
98 
99 	return true;
100 }
101 
MaxJumpRows(s32 newMaxJumpRows)102 void HCCharacter::MaxJumpRows(s32 newMaxJumpRows)
103 {
104 	maxJumpRows = newMaxJumpRows;
105 	JClamp(maxJumpRows, 0, map->Rows());
106 
107 	// Simulates a jump to determine the veloccity in Y.
108 	s32 curJumpRows = 0;
109 	vJumpMax.y = 0.0f;
110 	float vx = vJumpMax.x, x = 0.0f, firstVy = 0.0f, lastVy = 0.0f, dy = float(map->CellHeight())/200.0f;
111 	bool first = true;
112 
113 	while (curJumpRows <= maxJumpRows)
114 	{
115 		vJumpMax.y += dy;
116 		float vy = -vJumpMax.y, y = 0.0f;
117 		vx = vJumpMax.x;
118 		x = 0.0f;
119 		maxJumpCols = curJumpRows = 0;
120 
121 		while (y <= 0.0f)
122 		{
123 			vy += map->Gravity();
124 
125 			if (vy > vJumpMax.y)
126 			{
127 				vy = vJumpMax.y;
128 			}
129 
130 			x += vx;
131 			y += vy;
132 			curJumpRows = (s32)JMax(curJumpRows, -y/map->CellHeight());
133 		}
134 
135 		// Check the first and last v.y's that allow a vertical jump of maxJumpRows cells.
136 		if (curJumpRows == maxJumpRows)
137 		{
138 			if (first)
139 			{
140 				first = false;
141 				firstVy = vJumpMax.y;
142 			}
143 
144 			lastVy = vJumpMax.y;
145 		}
146 	}
147 
148 	vJumpMax.y = firstVy + ((lastVy - firstVy)/2.0f);
149 
150 	// This is only informative for, perhaps, the child classes but includes it also
151 	maxJumpCols = (s32)x/map->CellWidth();
152 
153 	// This is the maximum number of rows before starting to fall (and before the player
154 	// has no control over the character, except if it hangs to a rope during the fall).
155 	// If falling and the floor is reached, the character dies.
156 	maxFallRows = maxJumpCols * 2;
157 }
158 
Draw()159 void HCCharacter::Draw()
160 {
161 	states[state].Draw();
162 
163 	if (dialog != 0)
164 	{
165 		dialog->Draw();
166 	}
167 
168 // 	SDL_Rect rc;
169 // 	rc.x = map->ToX(map->ToCol((s32)pos.x)) - 1;
170 // 	rc.y = map->ToY(map->ToRow((s32)pos.y)) - (map->CellHeight()/2 - 1);
171 // 	rc.w = 3;
172 // 	rc.h = 3;
173 
174 // 	SDL_FillRect(SDL_GetVideoSurface(), &rc, 0xffffffff);
175 }
176 
Update()177 s32 HCCharacter::Update()
178 {
179 	states[state].Update();
180 
181 	if (state == HCCS_HANG)
182 	{
183 		UpdateHang();
184 	}
185 	else
186 	{
187 		UpdateVeloccity();
188 		CheckHang();
189 	}
190 
191 	// Collisions
192 	UpdateCollisions();
193 	CheckBrokenFloor();
194 
195 	Pos(pos.x + v.x, pos.y + v.y);
196 
197 	// Updates dialogs
198 	UpdateDialog();
199 
200 	return 0;
201 }
202 
UpdateVeloccity()203 void HCCharacter::UpdateVeloccity()
204 {
205 	v.x += a.x;
206 	v.y += a.y + map->Gravity();
207 
208 	if (v.x > vMax.x)
209 	{
210 		v.x = vMax.x;
211 	}
212 	else
213 	if (v.x < -vMax.x)
214 	{
215 		v.x = -vMax.x;
216 	}
217 
218 	switch (state)
219 	{
220 	case HCCS_JUMPLEFT:
221 	case HCCS_JUMPRIGHT:
222 	case HCCS_JUMP:
223 		// Falling veloccity limited to the cell height - 1
224 		if (v.y > 0.0f)
225 		{
226 			if (v.y > map->CellHeight() - 1)
227 			{
228 				v.y = map->CellHeight() - 1;
229 			}
230 		}
231 		else
232 		if (v.y < -vJumpMax.y)
233 		{
234 			v.y = -vJumpMax.y;
235 		}
236 		break;
237 
238 	case HCCS_DIE:
239 		v.x = a.x = 0.0f;
240 		if (v.y > vMax.y)
241 		{
242 			v.y = vMax.y;
243 		}
244 		else
245 		if (v.y < -vMax.y)
246 		{
247 			v.y = -vMax.y;
248 		}
249 		break;
250 
251 	default:
252 		if (v.y > vMax.y)
253 		{
254 			v.y = vMax.y;
255 		}
256 		else
257 		if (v.y < -vMax.y)
258 		{
259 			v.y = -vMax.y;
260 		}
261 		break;
262 	}
263 }
264 
UpdateCollisions()265 void HCCharacter::UpdateCollisions()
266 {
267 	float newX = pos.x + v.x;
268 	float newY = pos.y + v.y;
269 	s32 row = map->ToRow((s32)pos.y), col = map->ToCol((s32)pos.x);
270 	s32 newCol = map->ToCol((s32)(newX));
271 	s32 newRow = map->ToRow((s32)(newY));
272 
273 	switch (map->Cell(row, newCol)->Type())
274 	{
275 	case HCCELLTYPE_FLOOR:
276 	case HCCELLTYPE_CONTFLOOR:
277 		v.x = 0.0f;
278 		break;
279 
280 	case HCCELLTYPE_BREAK:
281 		if (((HCBreak *)map->Cell(row, newCol))->State() == HCBREAKSTATE_NORMAL)
282 		{
283 			v.x = 0.0f;
284 		}
285 		break;
286 
287 	default:
288 		col = newCol;
289 		break;
290 	}
291 
292 	switch (map->Cell(newRow, col)->Type())
293 	{
294 	case HCCELLTYPE_LADDER:
295 	case HCCELLTYPE_BAR:
296 
297 		// New cell is a ladder or a bar
298 		switch (state)
299 		{
300 		case HCCS_UP:
301 		case HCCS_DOWN:
302 		case HCCS_SLIDE:
303 			// In this states do nothing
304 			break;
305 
306 		case HCCS_JUMPLEFT:
307 		case HCCS_JUMPRIGHT:
308 		case HCCS_JUMP:
309 			if (newRow > row && map->Cell(row, col)->Type() == HCCELLTYPE_BLANK)
310 			{
311 				// Falls over a ladder or bar, must stop
312 				v.y = 0.0f;
313 				state = HCCS_STOP;
314 				FixY(row);
315 			}
316 			break;
317 
318 		case HCCS_DIE:
319 			if (newRow > row && map->Cell(row, col)->Type() == HCCELLTYPE_BLANK)
320 			{
321 				// Falls over a ladder or bar, must stop
322 				v.y = 0.0f;
323 			}
324 			break;
325 
326 		default:
327 			// In any other state, stops the character
328 			v.y = 0.0f;
329 			break;
330 		}
331 		break;
332 
333 	default:
334 		if ((map->Cell(newRow, col)->Actions() & HCACTION_FALL) == 0)
335 		{
336 			v.y = 0.0f;
337 
338 			switch (state)
339 			{
340 				// If jumping, must stop
341 			case HCCS_JUMPLEFT:
342 			case HCCS_JUMPRIGHT:
343 			case HCCS_JUMP:
344 				if (newRow > row)
345 				{
346 					// Stands over the floor
347 					state = HCCS_STOP;
348 					FixY(row);
349 				}
350 				else
351 				if (newRow == row)
352 				{
353 					// Stands over the floor above
354 					state = HCCS_STOP;
355 					FixY(row - 1);
356 				}
357 				break;
358 
359 			case HCCS_DOWN:
360 			case HCCS_SLIDE:
361 				state = HCCS_STOP;
362 				FixY(row);
363 				break;
364 
365 			case HCCS_DIE:
366 				if (newRow > row)
367 				{
368 					// Stands over the floor
369 					FixY(row);
370 				}
371 				break;
372 
373 			default:
374 				break;
375 			}
376 		}
377 		else
378 		{
379 			if (newRow > row &&
380 					state != HCCS_JUMP &&
381 					state != HCCS_JUMPLEFT &&
382 					state != HCCS_JUMPRIGHT &&
383 					state != HCCS_DIE)
384 			{
385 				State(HCCS_JUMP);
386 			}
387 		}
388 		break;
389 	}
390 }
391 
UpdateDialog()392 void HCCharacter::UpdateDialog()
393 {
394 	if (dialog != 0)
395 	{
396 		dialog->Update();
397 	}
398 }
399 
CheckBrokenFloor()400 void HCCharacter::CheckBrokenFloor()
401 {
402 	// Checks for broken floor
403 	if (breakRow != -1)
404 	{
405 		s32 row = map->ToRow((s32)pos.y + map->CellHeight()/2);
406 		s32 col = map->ToCol((s32)pos.x);
407 
408 		// Inside a break, got out?
409 		if (map->Cell(row, col)->Type() != HCCELLTYPE_BREAK || ((HCBreak *)map->Cell(row, col))->State() != HCBREAKSTATE_NORMAL)
410 		{
411 			// Got out!
412 			((HCBreak *)map->Cell(breakRow, breakCol))->Break();
413 			breakRow = -1;
414 		}
415 	}
416 	else
417 	{
418 		s32 row = map->ToRow((s32)pos.y + map->CellHeight()/2);
419 		s32 col = map->ToCol((s32)pos.x);
420 
421 		if (state == HCCS_STOP ||
422 				state == HCCS_LEFT ||
423 				state == HCCS_RIGHT)
424 		{
425 			// Outside a break, got in?
426 			if (row < map->Rows() - 1 &&
427 					map->Cell(row, col)->Type() == HCCELLTYPE_BREAK &&
428 					((HCBreak *)map->Cell(row, col))->State() == HCBREAKSTATE_NORMAL)
429 			{
430 				// Got in!
431 				breakRow = row;
432 				breakCol = col;
433 			}
434 		}
435 	}
436 }
437 
CheckHang()438 void HCCharacter::CheckHang()
439 {
440 	if (ropes == 0)
441 		return;
442 
443 	if (state != HCCS_HANG &&
444 			state != HCCS_DIE)
445 	{
446 		JImage *edge;
447 		for (s32 i = 0; i < numRopes; ++i)
448 		{
449 			edge = &ropes[i]->Edge();
450 			s32 cx = (s32)edge->X() + (edge->Width()/2);
451 			s32 cy = (s32)edge->Y() + (edge->Height()/2);
452 
453 			if (cx > pos.x - hangCheckSize &&
454 					cx < pos.x + hangCheckSize &&
455 					cy > pos.y - hangCheckYOffset - hangCheckSize &&
456 					cy < pos.y - hangCheckYOffset + hangCheckSize)
457 			{
458 				state = HCCS_HANG;
459 				v.x = v.y = a.x = 0.0f;
460 				a.y = -map->Gravity();
461 				trackRope = ropes[i];
462 				Pos(trackRope->Edge().X(), trackRope->Edge().Y());
463 				break;
464 			}
465 		}
466 	}
467 }
468 
UpdateStop()469 s32 HCCharacter::UpdateStop()
470 {
471   return 0;
472 }
473 
UpdateRight()474 s32 HCCharacter::UpdateRight()
475 {
476   return 0;
477 }
478 
UpdateLeft()479 s32 HCCharacter::UpdateLeft()
480 {
481   return 0;
482 }
483 
UpdateUp()484 s32 HCCharacter::UpdateUp()
485 {
486   return 0;
487 }
488 
UpdateDown()489 s32 HCCharacter::UpdateDown()
490 {
491 	return 0;
492 }
493 
UpdateSlide()494 s32 HCCharacter::UpdateSlide()
495 {
496 	return 0;
497 }
498 
UpdateJump()499 s32 HCCharacter::UpdateJump()
500 {
501 	return 0;
502 }
503 
UpdateJumpLeft()504 s32 HCCharacter::UpdateJumpLeft()
505 {
506 	return 0;
507 }
508 
UpdateJumpRight()509 s32 HCCharacter::UpdateJumpRight()
510 {
511 	return 0;
512 }
513 
UpdateFall()514 s32 HCCharacter::UpdateFall()
515 {
516 	return 0;
517 }
518 
UpdateDie()519 s32 HCCharacter::UpdateDie()
520 {
521   return 0;
522 }
523 
UpdateHang()524 s32 HCCharacter::UpdateHang()
525 {
526 	// Move with the rope!
527 	Pos(trackRope->Edge().X() + trackRope->Edge().Width()/2,
528 			trackRope->Edge().Y() + trackRope->Edge().Height());
529 
530   return 0;
531 }
532 
Pos(float x,float y)533 void HCCharacter::Pos(float x, float y)
534 {
535 	//	fprintf(stderr, "En Pos() antes pos.x: %f pos.y: %f  v.x: %f v.y: %f  x:%f y:%f  px+vx:%f py+vy:%f\n", pos.x, pos.y, v.x, v.y, x, y, pos.x + v.x, pos.y + v.y);
536 	pos.x = x;
537 	pos.y = y;
538 	//	fprintf(stderr, "En Pos() despu�s pos.x: %f pos.y: %f  v.x: %f v.y: %f  x:%f y:%f\n", pos.x, pos.y, v.x, v.y, x, y);
539 	states[state].Pos(x, y);
540 }
541 
Row()542 s32 HCCharacter::Row()
543 {
544 	return map->ToRow((s32)pos.y);
545 }
546 
Col()547 s32 HCCharacter::Col()
548 {
549 	return map->ToCol((s32)pos.x);
550 }
551 
552 
FixPos(s32 col,s32 row)553 void HCCharacter::FixPos(s32 col, s32 row)
554 {
555 	Pos(map->ToX(col), map->ToY(row));
556 }
557 
FixX(s32 col)558 void HCCharacter::FixX(s32 col)
559 {
560 	Pos(map->ToX(col), (s32)pos.y);
561 }
562 
FixY(s32 row)563 void HCCharacter::FixY(s32 row)
564 {
565 	Pos(pos.x, map->ToY(row));
566 }
567 
Act(u32 act)568 bool HCCharacter::Act(u32 act)
569 {
570 	lastAction = actions;
571 	actions = act;
572 
573 	s32 row = map->ToRow((s32)pos.y);
574 	s32 col = map->ToCol((s32)pos.x);
575 
576   if (state == HCCS_DIE)
577 	{
578 		return false;
579 	}
580 
581 	// Nothing
582 	if (actions == 0)
583 	{
584 		// Stop moving aside
585 		v.x = a.x = 0.0f;
586 
587 		switch (state)
588 		{
589 		case HCCS_JUMP:
590 		case HCCS_JUMPLEFT:
591 		case HCCS_JUMPRIGHT:
592 			{
593 				// Vertical jump
594 				State(HCCS_JUMP);
595 
596 				if (v.y < 0.0f)
597 				{
598 					// Stop going up but not down
599 					v.y = 0.0f;
600 				}
601 			}
602 			break;
603 
604 		case HCCS_UP:
605 		case HCCS_DOWN:
606 			{
607 				v.y = 0.0f;
608 				a.y = -map->Gravity();
609 				states[state].Paused(true);
610 			}
611 			break;
612 
613 		case HCCS_SLIDE:
614 			break;
615 
616 		case HCCS_LEFT:
617 		case HCCS_RIGHT:
618 			State(HCCS_STOP);
619 			break;
620 
621 		default:
622 			break;
623 		}
624 
625 		return true;
626 	}
627 
628 	/////////////////////////////////////////////////////////////////////
629 	// Side movement
630 	if ((actions & HCCA_LEFT) && (map->Cell(row, col)->Actions() & HCACTION_LEFT))
631 	{
632 		// Goes left
633 		a.x = -aMax.x;
634 
635 		if (actions & HCCA_JUMP)
636 		{
637 			a.y = 0.0f;
638 			// Jump requested
639 			if (state != HCCS_JUMP &&
640 					state != HCCS_JUMPLEFT &&
641 					state != HCCS_JUMPRIGHT)
642 			{
643 				// Not jumping, make it jump
644 				v.y = -vJumpMax.y;
645 			}
646 
647 			// Jumps facing left
648 			State(HCCS_JUMPLEFT);
649 
650 			// Jump processed, clean it from the pending actions
651 			actions &= ~HCCA_JUMP;
652 		}
653 		else
654 		{
655 			a.y = 0.0f;
656 
657 			// Jump not requested
658 			if (state == HCCS_JUMPLEFT ||
659 					state == HCCS_JUMPRIGHT ||
660 					state == HCCS_JUMP)
661 			{
662 				State(HCCS_JUMPLEFT);
663 			}
664 			else
665 			if (state != HCCS_HANG)
666 			{
667 				if (map->Cell(row + 1, col)->Actions() & HCACTION_FALL)
668 				{
669 					// Falls facing right if not climbing or hanging
670 					State(HCCS_JUMPLEFT);
671 					v.y = 0.0f;
672 				}
673 				else
674 				{
675 					// Walks facing right if not climbing or hanging
676 					State(HCCS_LEFT);
677 				}
678 			}
679 		}
680 	}
681 	else
682 	if ((actions & HCCA_RIGHT) && (map->Cell(row, col)->Actions() & HCACTION_RIGHT))
683 	{
684 		// Goes right
685 		a.x = aMax.x;
686 
687 		if (actions & HCCA_JUMP)
688 		{
689 			a.y = 0.0f;
690 			// Jump requested
691 			if (state != HCCS_JUMP &&
692 					state != HCCS_JUMPLEFT &&
693 					state != HCCS_JUMPRIGHT)
694 			{
695 				// Not jumping, make it jump
696 				v.y = -vJumpMax.y;
697 			}
698 
699 			// Jumps facing right
700 			State(HCCS_JUMPRIGHT);
701 
702 			// Jump processed, clean it from the pending actions
703 			actions &= ~HCCA_JUMP;
704 		}
705 		else
706 		{
707 			a.y = 0.0f;
708 			if (state == HCCS_JUMPLEFT ||
709 					state == HCCS_JUMPRIGHT ||
710 					state == HCCS_JUMP)
711 			{
712 				State(HCCS_JUMPRIGHT);
713 			}
714 			else
715 			// Jump not requested
716 			if (state != HCCS_HANG)
717 			{
718 				if (map->Cell(row + 1, col)->Actions() & HCACTION_FALL)
719 				{
720 					// Falls facing right if not climbing or hanging
721 					State(HCCS_JUMPRIGHT);
722 					v.y = 0.0f;
723 				}
724 				else
725 				{
726 					// Walks facing right if not climbing or hanging
727 					State(HCCS_RIGHT);
728 				}
729 			}
730 		}
731 	}
732 	else
733 	{
734 		v.x = a.x = 0.0f;
735 	}
736 
737 	/////////////////////////////////////////////////////////////////////
738 	// Vertical movement
739 	if (actions & HCCA_UP && state != HCCS_HANG)
740 	{
741 		// Up requested
742 		if (map->Cell(row, col)->Actions() & HCACTION_UP != 0)
743 		{
744 			State(HCCS_UP);
745 			// Can go up in the current cell
746 			if (map->Cell(row - 1, col)->Actions() & HCACTION_UP ||
747 					map->Cell(row - 1, col)->Actions() & HCACTION_FALL)
748 			{
749 				// Can go up in the upper cell or cell above empty, continue
750 				a.y = -map->Gravity() - aMax.y;
751 				states[state].Paused(false);
752 				FixX(col);
753 			}
754 			else
755 			{
756 				// Cannot go up in the upper cell, stops
757 				a.y = -map->Gravity();
758 				v.y = 0.0f;
759 				states[state].Paused(true);
760 			}
761 		}
762 		else
763 		{
764 			a.y = 0.0f;
765 
766 			if (state == HCCS_UP)
767 			{
768 				// Cannot go up, wait
769 				State(HCCS_STOP);
770 				v.y = 0.0f;
771 			}
772 		}
773 	}
774 	else
775 	if (actions & HCCA_DOWN)
776 	{
777 		// Down requested
778 		if (state == HCCS_HANG)
779 		{
780 			// If hanging, falls
781 			v.x = v.y = a.y = 0.0f;
782 			state = HCCS_JUMP;
783 			trackRope = 0;
784 			Pos(pos.x, pos.y + states[state].MaxH());
785 		}
786 		else
787 		if (map->Cell(row + 1, col)->Actions() & HCACTION_SLIDE)
788 		{
789 			// Bar like object bellow
790 			a.y = -map->Gravity() + aMax.y;
791 			state = HCCS_SLIDE;
792 			FixX(col);
793 		}
794 		else
795 		if (map->Cell(row + 1, col)->Actions() & HCACTION_DOWN)
796 		{
797 			// Ladder like object bellow
798 			a.y = -map->Gravity() + aMax.y;
799 			state = HCCS_DOWN;
800 			states[state].Paused(false);
801 			FixX(col);
802 		}
803 		else
804 		{
805 			// Not a ladder or a bar bellow
806 			if (map->Cell(row, col)->Actions() & HCACTION_DOWN ||
807 					map->Cell(row, col)->Actions() & HCACTION_SLIDE)
808 			{
809 				// If still over the ladder or bar, keep going on
810 				a.y = -map->Gravity() + aMax.y;
811 				states[state].Paused(false);
812 			}
813 			else
814 			if (map->Cell(row + 1, col)->Actions() & HCACTION_FALL)
815 			{
816 				// There is no bar or ladder either in the current cell or the cell bellow
817 				// and the cell bellow is empty
818 				if (state != HCCS_JUMP &&
819 						state != HCCS_JUMPLEFT &&
820 						state != HCCS_JUMPRIGHT &&
821 						!(actions & HCCA_JUMP))
822 				{
823 					// Jump not requested, normal fall
824 					v.y = a.y = 0.0f;
825 					State(HCCS_JUMP);
826 				}
827 			}
828 			else
829 			{
830 				a.y = 0.0f;
831 
832 				if (state == HCCS_DOWN)
833 				{
834 					// Cannot go down, wait
835 					state = HCCS_STOP;
836 					FixY(row);
837 				}
838 			}
839 		}
840 	}
841 
842 	// Jumps only if not sliding and the current cell and the cell above are empty or
843 	// it's hanging
844 	if ((actions & HCCA_JUMP) &&
845 			state != HCCS_SLIDE &&
846 			(!(map->Cell(row + 1, col)->Actions() & HCACTION_FALL) ||
847 			 //!(map->Cell(row, col)->Actions() & HCACTION_FALL) ||
848 			 state == HCCS_HANG))
849 	{
850 		// Cell bellow or this cell are not empty or the character is hanging
851 		v.x = a.x = 0.0f;
852 
853 		if (state != HCCS_JUMP &&
854 				state != HCCS_JUMPLEFT &&
855 				state != HCCS_JUMPRIGHT)
856 		{
857 			a.y = 0.0f;
858 			v.y = -vJumpMax.y;
859 			State(HCCS_JUMP);
860 		}
861 	}
862 
863 	return true;
864 }
865 
State(HCCharacterState newState)866 void HCCharacter::State(HCCharacterState newState)
867 {
868 	// Gets the current row and col
869 	state = newState;
870 	states[state].Pos(pos.x, pos.y);
871 }
872 
Load(JRW & file)873 u32 HCCharacter::Load(JRW &file)
874 {
875 	if (0 == file.ReadLE32(&subtype) ||
876 			0 == file.ReadLE32((u32 *)&pos.x) ||
877 			0 == file.ReadLE32((u32 *)&pos.y) ||
878 			0 == file.ReadLE32((u32 *)&vMax.x) ||
879 			0 == file.ReadLE32((u32 *)&vMax.y) ||
880 			0 == file.ReadLE32(&maxJumpRows))
881 	{
882 		fprintf(stderr, "Error reading character's common parameters.\n");
883 		return 1;
884 	}
885 
886 	Pos(pos.x, pos.y);
887 
888 	return 0;
889 }
890 
Save(JRW & file)891 u32 HCCharacter::Save(JRW &file)
892 {
893 	if (0 == file.WriteLE32(&subtype) ||
894 			0 == file.WriteLE32((u32 *)&pos.x) ||
895 			0 == file.WriteLE32((u32 *)&pos.y) ||
896 			0 == file.WriteLE32((u32 *)&vMax.x) ||
897 			0 == file.WriteLE32((u32 *)&vMax.y) ||
898 			0 == file.WriteLE32(&maxJumpRows))
899 	{
900 		fprintf(stderr, "Error writing character's common parameters.\n");
901 		return 1;
902 	}
903 
904 	return 0;
905 }
906 
Destroy()907 void HCCharacter::Destroy()
908 {
909 	for (s32 i = 0; i < HCCS_COUNT; ++i)
910 	{
911 		states[i].Destroy();
912 	}
913 
914 	dialog = 0;
915 	breakCol = breakRow = -1;
916 }
917 
918