diff options
Diffstat (limited to 'engines/avalanche/shootemup.cpp')
| -rw-r--r-- | engines/avalanche/shootemup.cpp | 517 | 
1 files changed, 458 insertions, 59 deletions
| diff --git a/engines/avalanche/shootemup.cpp b/engines/avalanche/shootemup.cpp index 79720fcb8c..bf041b5ad8 100644 --- a/engines/avalanche/shootemup.cpp +++ b/engines/avalanche/shootemup.cpp @@ -1,24 +1,24 @@  /* ScummVM - Graphic Adventure Engine -* -* ScummVM is the legal property of its developers, whose names -* are too numerous to list here. Please refer to the COPYRIGHT -* file distributed with this source distribution. -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. - -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -* GNU General Public License for more details. - -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -*/ + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */  /*  * This code is based on the original source code of Lord Avalot d'Argent version 1.3. @@ -32,13 +32,65 @@  namespace Avalanche { -const byte ShootEmUp::kFacingRight = 87;  const byte ShootEmUp::kStocks = 27; +const byte ShootEmUp::kAvvyShoots = 86; +const byte ShootEmUp::kFacingRight = 87; +const byte ShootEmUp::kFacingLeft = 93; +const long int ShootEmUp::kFlag = -20047; +const byte ShootEmUp::kFrameDelayMax = 2; +const byte ShootEmUp::kAvvyY = 150; +const byte ShootEmUp::kShooting[7] = { 86, 79, 80, 81, 80, 79, 86 }; +const byte ShootEmUp::kTimesASecond = 18; +const byte ShootEmUp::kFlashTime = 20; // If flash_time is <= this, the word "time" will flash. Should be about 20.  ShootEmUp::ShootEmUp(AvalancheEngine *vm) {  	_vm = vm; -	_time = 0; +	_time = 120; +	for (int i = 0; i < 7; i++) +		_stockStatus[i] = 0; +	for (int i = 0; i < 99; i++) { +		_sprites[i]._ix = 0; +		_sprites[i]._iy = 0; +		_sprites[i]._x = kFlag; +		_sprites[i]._y = 0; +		_sprites[i]._p = 0; +		_sprites[i]._timeout = 0; +		_sprites[i]._cameo = false; +		_sprites[i]._cameoFrame = 0; +		_sprites[i]._missile = false; +		_sprites[i]._wipe = false; +	} +	_rectNum = 0; +	_avvyWas = 320; +	_avvyPos = 320; +	_avvyAnim = 1; +	_avvyFacing = kFacingLeft; +	_altWasPressedBefore = false; +	_throwNext = 74; +	_firing = false; +	for (int i = 0; i < 4; i++) { +		_running[i]._x = kFlag; +		_running[i]._y = 0; +		_running[i]._frame = 0; +		_running[i]._tooHigh = 0; +		_running[i]._lowest = 0; +		_running[i]._ix = 0; +		_running[i]._iy = 0; +		_running[i]._frameDelay = 0; +	} +	for (int i = 0; i < 7; i++) +		_hasEscaped[i] = false; +	_count321 = 255; // Counting down. +	_howManyHaveEscaped = 0; +	_escapeCount = 0; +	_escaping = false; +	_timeThisSecond = 0; +	_cp = false; +	_wasFacing = 0; +	_score = 0; +	_escapeStock = 0; +	_gotOut = false;  }  void ShootEmUp::run() { @@ -62,11 +114,10 @@ void ShootEmUp::run() {  	}  	setup(); -	initRunner(20, 70, 48, 54, _vm->_rnd->getRandomNumber(4) + 1, _vm->_rnd->getRandomNumber(3) - 2); -	initRunner(600, 70, 48, 54, _vm->_rnd->getRandomNumber(4) + 1, _vm->_rnd->getRandomNumber(3) - 2); -	initRunner(600, 100, 61, 67, -(_vm->_rnd->getRandomNumber(4)) + 1, _vm->_rnd->getRandomNumber(3) - 2); -	initRunner(20, 100, 61, 67, -(_vm->_rnd->getRandomNumber(4)) + 1, _vm->_rnd->getRandomNumber(3) - 2); +	  	do { +		uint32 beginLoop = _vm->_system->getMillis(); +  		blankIt();  		hitPeople();  		plotThem(); @@ -80,6 +131,15 @@ void ShootEmUp::run() {  		updateTime();  		check321();  		readKbd(); + +		_cp = !_cp; + +		_vm->_graphics->refreshScreen(); + +		uint32 delay = _vm->_system->getMillis() - beginLoop; +		if (delay <= 55) +			_vm->_system->delayMillis(55 - delay); // Replaces slowdown(); 55 comes from 18.2 Hz (B Flight). +  	} while (_time != 0);  	_vm->fadeOut(); @@ -90,53 +150,142 @@ void ShootEmUp::run() {  }  bool ShootEmUp::overlap(uint16 a1x, uint16 a1y, uint16 a2x, uint16 a2y, uint16 b1x, uint16 b1y, uint16 b2x, uint16 b2y) { -	warning("STUB: ShootEmUp::overlap()"); -	return false; +	// By De Morgan's law: +	return (a2x >= b1x) && (b2x >= a1x) && (a2y >= b1y) && (b2y >= a1y);  } -byte ShootEmUp::getStockNumber(byte x) { -	warning("STUB: ShootEmUp::getStockNumber()"); -	return 0; +byte ShootEmUp::getStockNumber(byte index) { +	while (_hasEscaped[index]) { +		index++; +		if (index == 7) +			index = 0; +	} +	return index;  }  void ShootEmUp::blankIt() { -	warning("STUB: ShootEmUp::blankIt()"); +	for (int i = 0; i < _rectNum; i++) +		_vm->_graphics->drawFilledRectangle(_rectangles[i], kColorBlack); +	_rectNum = 0;  }  void ShootEmUp::moveThem() { -	warning("STUB: ShootEmUp::moveThem()"); +	for (int i = 0; i < 99; i++) { +		if (_sprites[i]._x != kFlag) { +			_sprites[i]._x += _sprites[i]._ix; +			_sprites[i]._y += _sprites[i]._iy; +		} +	} +} + +void ShootEmUp::blank(Common::Rect rect) { +	_rectangles[_rectNum++] = rect;  }  void ShootEmUp::plotThem() { -	warning("STUB: ShootEmUp::plotThem()"); +	for (int i = 0; i < 99; i++) { +		if (_sprites[i]._x != kFlag) { +			if (_sprites[i]._cameo) { +				_vm->_graphics->seuDrawCameo(_sprites[i]._x, _sprites[i]._y, _sprites[i]._p, _sprites[i]._cameoFrame); +				if (!_cp) { +					_sprites[i]._cameoFrame += 2; +					_sprites[i]._p += 2; +				} +			} else +				_vm->_graphics->seuDrawPicture(_sprites[i]._x, _sprites[i]._y, _sprites[i]._p); + +			if (_sprites[i]._wipe) +				blank(Common::Rect(_sprites[i]._x, _sprites[i]._y, _sprites[i]._x + _vm->_graphics->seuGetPicWidth(_sprites[i]._p), _sprites[i]._y + _vm->_graphics->seuGetPicHeight(_sprites[i]._p))); + +			if (_sprites[i]._timeout > 0) { +				_sprites[i]._timeout--; +				if (_sprites[i]._timeout == 0) +					_sprites[i]._x = kFlag; +			} +		} +	}  } -void ShootEmUp::define(int16 xx, int16 yy, byte pp, int8 ixx, int8 iyy, int16 time, bool isAMissile, bool doWeWipe) { -	warning("STUB: ShootEmUp::define()"); +void ShootEmUp::define(int16 x, int16 y, int8 p, int8 ix, int8 iy, int16 time, bool isAMissile, bool doWeWipe) { +	for (int i = 0; i < 99; i++) { +		if (_sprites[i]._x == kFlag) { +			_sprites[i]._x = x; +			_sprites[i]._y = y; +			_sprites[i]._p = p; +			_sprites[i]._ix = ix; +			_sprites[i]._iy = iy; +			_sprites[i]._timeout = time; +			_sprites[i]._cameo = false; +			_sprites[i]._missile = isAMissile; +			_sprites[i]._wipe = doWeWipe; +			return; +		} +	}  } -void ShootEmUp::defineCameo(int16 xx, int16 yy, byte pp, int16 time) { -	warning("STUB: ShootEmUp::defineCameo()"); +void ShootEmUp::defineCameo(int16 x, int16 y, int8 p, int16 time) { +	for (int i = 0; i < 99; i++) { +		if (_sprites[i]._x == kFlag) { +			_sprites[i]._x = x; +			_sprites[i]._y = y; +			_sprites[i]._p = p; +			_sprites[i]._ix = 0; +			_sprites[i]._iy = 0; +			_sprites[i]._timeout = time; +			_sprites[i]._cameo = true; +			_sprites[i]._cameoFrame = p + 1; +			_sprites[i]._missile = false; +			_sprites[i]._wipe = false; +			return; +		} +	}  } -void ShootEmUp::showStock(byte x) { -	warning("STUB: ShootEmUp::showStock()"); +void ShootEmUp::showStock(byte index) { +	if (_escaping && (index == _escapeStock)) { +		_vm->_graphics->seuDrawPicture(index * 90 + 20, 30, kStocks + 2); +		return; +	} + +	if (_stockStatus[index] > 5) +		return; + +	_vm->_graphics->seuDrawPicture(index * 90 + 20, 30, kStocks + _stockStatus[index]); +	_stockStatus[index] = 1 - _stockStatus[index]; +} + +void ShootEmUp::drawNumber(int number, int size, int x) { +	for (int i = 0; i < size - 1; i++) { +		int divisor = 10; +		for (int j = 0; j < size - 2 - i; j++) +			divisor *= 10; +		char value = number / divisor; +		_vm->_graphics->seuDrawPicture(x + i * 10, 0, value); +		number -= value * divisor; +	} +	_vm->_graphics->seuDrawPicture(x + (size - 1) * 10, 0, number % 10);  }  void ShootEmUp::showScore() { -	warning("STUB: ShootEmUp::showScore()"); +	drawNumber(_score, 5, 40);  }  void ShootEmUp::showTime() { -	warning("STUB: ShootEmUp::showTime()"); +	drawNumber(_time, 3, 140);  }  void ShootEmUp::gain(int8 howMuch) { -	warning("STUB: ShootEmUp::gain()"); +	if ((_score + howMuch) < 0) // howMuch can be negative! +		_score = 0; +	else +		_score += howMuch; + +	showScore();  }  void ShootEmUp::newEscape() { -	warning("STUB: ShootEmUp::newEscape()"); +	_escapeCount = _vm->_rnd->getRandomNumber(17) * 20; +	_escaping = false;  }  void ShootEmUp::nextPage() { @@ -151,11 +300,11 @@ void ShootEmUp::nextPage() {  		}  	} -	_vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlack); +	_vm->_graphics->blackOutScreen();  }  void ShootEmUp::instructions() { -	_vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlack); // Black out the whole screen. +	_vm->_graphics->blackOutScreen();  	_vm->_graphics->seuDrawPicture(25, 25, kFacingRight);  	_vm->_graphics->drawNormalText("< Avvy, our hero, needs your help - you must move him around.", _vm->_font, 8, 60, 35, kColorWhite);  	_vm->_graphics->drawNormalText("(He''s too terrified to move himself!)", _vm->_font, 8, 80, 45, kColorWhite); @@ -195,15 +344,79 @@ void ShootEmUp::instructions() {  }  void ShootEmUp::setup() { -	warning("STUB: ShootEmUp::setup()"); +	_vm->_graphics->blackOutScreen(); + +	newEscape(); + +	for (int i = 0; i < 7; i++) { +		_stockStatus[i] = _vm->_rnd->getRandomNumber(1); +		showStock(i); +	} + +	// Set up status line: +	_vm->_graphics->seuDrawPicture(0, 0, 16); // Score: +	showScore(); // Value of score (00000 here). +	_vm->_graphics->seuDrawPicture(110, 0, 19); // Time: +	showTime(); // Value of time. + +	_vm->_graphics->refreshScreen(); + +	// From the original core cycle: +	initRunner(20, 70, 48, 54, _vm->_rnd->getRandomNumber(4) + 1, _vm->_rnd->getRandomNumber(3) - 2); +	initRunner(600, 70, 48, 54, _vm->_rnd->getRandomNumber(4) + 1, _vm->_rnd->getRandomNumber(3) - 2); +	initRunner(600, 100, 61, 67, (-(int8)_vm->_rnd->getRandomNumber(4)) + 1, _vm->_rnd->getRandomNumber(3) - 2); +	initRunner(20, 100, 61, 67, (-(int8)_vm->_rnd->getRandomNumber(4)) + 1, _vm->_rnd->getRandomNumber(3) - 2);  } -void ShootEmUp::initRunner(int16 xx, int16 yy, byte f1, byte f2, int8 ixx, int8 iyy) { -	warning("STUB: ShootEmUp::initRunner()"); +void ShootEmUp::initRunner(int16 x, int16 y, byte f1, byte f2, int8 ix, int8 iy) { +	for (int i = 0; i < 4; i++) { +		if (_running[i]._x == kFlag) { +			_running[i]._x = x; +			_running[i]._y = y; +			_running[i]._frame = f1; +			_running[i]._tooHigh = f2; +			_running[i]._lowest = f1; +			_running[i]._ix = ix; +			_running[i]._iy = iy; +			if ((ix == 0) && (iy == 0)) +				_running[i]._ix = 2; // To stop them running on the spot! +			_running[i]._frameDelay = kFrameDelayMax; +			return; +		} +	}  }  void ShootEmUp::moveAvvy() { -	warning("STUB: ShootEmUp::moveAvvy()"); +	if (_avvyWas < _avvyPos) +		_avvyFacing = kFacingRight; +	else if (_avvyWas > _avvyPos) +		_avvyFacing = kFacingLeft; + +	if (!_firing) { +		if (_avvyWas == _avvyPos) +			_avvyAnim = 1; +		else { +			_avvyAnim++; +			if (_avvyAnim == 6) +				_avvyAnim = 0; +		} +	} + +	if (_avvyFacing == kAvvyShoots) +		define(_avvyPos, kAvvyY, kShooting[_avvyAnim], 0, 0, 1, false, true); +	else +		define(_avvyPos, kAvvyY, _avvyAnim + _avvyFacing, 0, 0, 1, false, true); + +	_avvyWas = _avvyPos; + +	if (_avvyFacing == kAvvyShoots) { +		if (_avvyAnim == 6) { +			_avvyFacing = _wasFacing; +			_avvyAnim = 0; +			_firing = false; +		} else +			_avvyAnim++; +	}  }  void ShootEmUp::readKbd() { @@ -211,39 +424,225 @@ void ShootEmUp::readKbd() {  }  void ShootEmUp::animate() { -	warning("STUB: ShootEmUp::animate()"); +	if (_vm->_rnd->getRandomNumber(9) == 1) +		showStock(getStockNumber(_vm->_rnd->getRandomNumber(5))); +	for (int i = 0; i < 7; i++) { +		if (_stockStatus[i] > 5) { +			_stockStatus[i]--; +			if (_stockStatus[i] == 8) { +				_stockStatus[i] = 0; +				showStock(i); +			} +		} +	}  }  void ShootEmUp::collisionCheck() { -	warning("STUB: ShootEmUp::collisionCheck()"); +	for (int i = 0; i < 99; i++) { +		if ((_sprites[i]._x != kFlag) && (_sprites[i]._missile) && +			(_sprites[i]._y < 60) && (_sprites[i]._timeout == 1)) { +			int distFromSide = (_sprites[i]._x - 20) % 90; +			int thisStock = (_sprites[i]._x - 20) / 90; +			if ((!_hasEscaped[thisStock]) && (distFromSide > 17) && (distFromSide < 34)) { +				_vm->_sound->playNote(999, 3); +				_vm->_system->delayMillis(3); +				define(_sprites[i]._x + 20, _sprites[i]._y, 25 + _vm->_rnd->getRandomNumber(1), 3, 1, 12, false, true); // Well done! +				define(thisStock * 90 + 20, 30, 30, 0, 0, 7, false, false); // Face of man +				defineCameo(thisStock * 90 + 20 + 10, 35, 40, 7); // Splat! +				define(thisStock * 90 + 20 + 20, 50, 33 + _vm->_rnd->getRandomNumber(4), 0, 2, 9, false, true); // Oof! +				_stockStatus[thisStock] = 17; +				gain(3); // Score for hitting a face. + +				if (_escaping && (_escapeStock = thisStock)) { // Hit the escaper. +					_vm->_sound->playNote(1777, 1); +					_vm->_system->delayMillis(1); +					gain(5); // Bonus for hitting escaper. +					_escaping = false; +					newEscape(); +				} +			} else { +				define(_sprites[i]._x, _sprites[i]._y, 82 + _vm->_rnd->getRandomNumber(2), 2, 2, 17, false, true); // Missed! +				if ((!_hasEscaped[thisStock]) && (distFromSide > 3) && (distFromSide < 43)) { +					define(thisStock * 90 + 20, 30, 29, 0, 0, 7, false, false); // Face of man +					if (distFromSide > 35) +						defineCameo(_sprites[i]._x - 27, 35, 40, 7); // Splat! +					else +						defineCameo(_sprites[i]._x - 7, 35, 40, 7); +					_stockStatus[thisStock] = 17; +				} +			} +		} +	}  }  void ShootEmUp::turnAround(byte who, bool randomX) { -	warning("STUB: ShootEmUp::turnAround()"); +	if (randomX) { +		int8 ix = (_vm->_rnd->getRandomNumber(4) + 1); +		if (_running[who]._ix > 0) +			_running[who]._ix = -(ix); +		else +			_running[who]._ix = ix; +	} else +		_running[who]._ix = -(_running[who]._ix); + +	_running[who]._iy = -(_running[who]._iy);  }  void ShootEmUp::bumpFolk() { -	warning("STUB: ShootEmUp::bumpFolk()"); +	for (int i = 0; i < 4; i++) { +		if (_running[i]._x != kFlag) { +			for (int j = i + 1; j < 4; j++) { +				bool overlaps = overlap(_running[i]._x, _running[i]._y, _running[i]._x + 17, _running[i]._y + 24, +										_running[j]._x, _running[j]._y, _running[j]._x + 17, _running[j]._y + 24); +				if ((_running[i]._x != kFlag) && overlaps) { +					turnAround(i, false); // Opp. directions. +					turnAround(j, false); +				} +			} +		} +	}  }  void ShootEmUp::peopleRunning() { -	warning("STUB: ShootEmUp::peopleRunning()"); +	if (_count321 != 0) +		return; + +	for (int i = 0; i < 4; i++) { +		if (_running[i]._x != kFlag) { +			if (((_running[i]._y + _running[i]._iy) <= 53) || ((_running[i]._y + _running[i]._iy) >= 120)) +				_running[i]._iy = -(_running[i]._iy); + +			byte frame = 0; +			if (_running[i]._ix < 0) +				frame = _running[i]._frame - 1; +			else +				frame = _running[i]._frame + 6; +			define(_running[i]._x, _running[i]._y, frame, 0, 0, 1, false, true); + +			if (_running[i]._frameDelay == 0) { +				_running[i]._frame++; +				if (_running[i]._frame == _running[i]._tooHigh) +					_running[i]._frame = _running[i]._lowest; +				_running[i]._frameDelay = kFrameDelayMax; +				_running[i]._y += _running[i]._iy; +			} else +				_running[i]._frameDelay--; + +			if (((_running[i]._x + _running[i]._ix) <= 0) || ((_running[i]._x + _running[i]._ix) >= 620)) +				turnAround(i, true); + +			_running[i]._x += _running[i]._ix; +		} +	}  }  void ShootEmUp::updateTime() { -	warning("STUB: ShootEmUp::updateTime()"); +	if (_count321 != 0) +		return; + +	_timeThisSecond++; + +	if (_timeThisSecond < kTimesASecond) +		return; + +	_time--; +	showTime(); +	_timeThisSecond = 0; + +	if (_time <= kFlashTime) { +		int timeMode = 0; +		if ((_time % 2) == 1) +			timeMode = 19; // Normal 'Time:' +		else +			timeMode = 85; // Flash 'Time:' + +		_vm->_graphics->seuDrawPicture(110, 0, timeMode); +	}  }  void ShootEmUp::hitPeople() { -	warning("STUB: ShootEmUp::hitPeople()"); +	if (_count321 != 0) +		return; + +	for (int i = 0; i < 99; i++) { +		if ((_sprites[i]._missile) && (_sprites[i]._x != kFlag)) { +			for (int j = 0; j < 4; j++) { + +				bool overlaps = overlap(_sprites[i]._x, _sprites[i]._y, _sprites[i]._x + 7, _sprites[i]._y + 10, +					_running[j]._x, _running[j]._y, _running[j]._x + 17, _running[j]._y + 24); + +				if ((_running[j]._x != kFlag) && (overlaps)) { +					_vm->_sound->playNote(7177, 1); +					_sprites[i]._x = kFlag; +					gain(-5); +					define(_running[j]._x + 20, _running[j]._y + 3, 33 + _vm->_rnd->getRandomNumber(5), 1, 3, 9, false, true); // Oof! +					define(_sprites[i]._x, _sprites[i]._y, 82, 1, 0, 17, false, true); // Oops! +				} +			} +		} +	}  }  void ShootEmUp::escapeCheck() { -	warning("STUB: ShootEmUp::escapeCheck()"); +	if (_count321 != 0) +		return; + +	if (_escapeCount > 0) { +		_escapeCount--; +		return; +	} + +	// Escape_count = 0; now what ? + +	if (_escaping) { +		if (_gotOut) { +			newEscape(); +			_escaping = false; +			_vm->_graphics->seuDrawPicture(_escapeStock * 90 + 20, 30, kStocks + 4); +		} else { +			_vm->_graphics->seuDrawPicture(_escapeStock * 90 + 20, 30, kStocks + 5); +			_escapeCount = 20; +			_gotOut = true; +			define(_escapeStock * 90 + 20, 50, 24, 0, 2, 17, false, true); // Escaped! +			gain(-10); +			_hasEscaped[_escapeStock] = true; + +			_howManyHaveEscaped++; + +			if (_howManyHaveEscaped == 7) { +				_vm->_graphics->seuDrawPicture(266, 90, 23); +				_time = 0; +			} +		} +	} else { +		_escapeStock = getStockNumber(_vm->_rnd->getRandomNumber(6)); +		_escaping = true; +		_gotOut = false; +		_vm->_graphics->seuDrawPicture(_escapeStock * 90 + 20, 30, kStocks + 2); // Smiling! +		_escapeCount = 200; +	}  }  void ShootEmUp::check321() { -	warning("STUB: ShootEmUp::check321()"); +	if (_count321 == 0) +		return; + +	_count321--; + +	switch (_count321) { +	case 84: +		define(320, 60, 15, 2, 1, 94, false, true); +		break; +	case 169: +		define(320, 60, 14, 0, 1, 94, false, true); +		break; +	case 254: +		define(320, 60, 13, -2, 1, 94, false, true); +		define(0, 100, 17, 2, 0, 254, false, true); +		break; +	default: +		break; +	}  }  } // End of namespace Avalanche | 
