scummvm/engines/mm/mm1/game/encounter.cpp

186 lines
4.9 KiB
C++

/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "mm/mm1/game/encounter.h"
#include "mm/mm1/data/monsters.h"
#include "mm/mm1/maps/maps.h"
#include "mm/mm1/events.h"
#include "mm/mm1/globals.h"
#include "mm/mm1/mm1.h"
namespace MM {
namespace MM1 {
namespace Game {
void Encounter::execute() {
if (!g_globals->_encountersOn)
return;
Maps::Map &map = *g_maps->_currentMap;
int comp, maxRand, maxVal;
const Monster *monsterP;
_bribeFleeCtr = _bribeAlignmentCtr = 0;
_alignmentsChanged = 0;
// In manual mode, the scripts have already set up
// a list of monsters to use
if (!_manual) {
_monsterSummaries.clear();
_levelIndex = 0;
}
_totalLevels = _highestLevel = 0;
_levelOffset = _monsterImgNum = _maxLevelForImg = _fleeThreshold = 0;
for (uint i = 0; i < g_globals->_party.size(); ++i) {
const Character &c = g_globals->_party[i];
_highestLevel = MAX(_highestLevel, (int)c._level._current);
if (!(c._condition & (BAD_CONDITION | PARALYZED | UNCONSCIOUS)))
_totalLevels = MIN(_totalLevels + c._level._current, 255);
}
_totalLevels /= 2;
_highestLevel /= 2;
bool firstLoop = !_manual;
_manual = false;
while (firstLoop || _levelIndex < _totalLevels) {
randomAdjust();
firstLoop = false;
maxRand = _levelOffset + _highestLevel;
if (maxRand >= 2) {
int highestRand = map[Maps::MAP_33];
maxRand = MIN(maxRand, highestRand);
comp = getRandomNumber(maxRand);
} else {
comp = 1;
}
maxVal = map[Maps::MAP_47];
if (comp < maxVal) {
comp = MIN(maxVal, 10);
}
assert(_monsterSummaries.size() < MAX_COMBAT_MONSTERS);
_monsterNum = getRandomNumber(16);
_monsterSummaries.push_back(MonsterSummary(_monsterNum, comp));
_monsterLevel = comp;
_levelIndex += comp;
if (_monsterSummaries.size() < MAX_COMBAT_MONSTERS) {
if (_monsterSummaries.size() >= map[Maps::MAP_MAX_MONSTERS])
goto exit_loop;
monsterP = getMonster();
maxVal = getRandomNumber(monsterP->_count);
for (int i = 0; i < maxVal; ++i) {
assert(!_monsterSummaries.empty());
_monsterSummaries.push_back(_monsterSummaries.back());
_levelIndex += _monsterSummaries.back()._level;
if (_monsterSummaries.size() >= MAX_COMBAT_MONSTERS)
goto exit_loop;
if (_monsterSummaries.size() >= map[Maps::MAP_MAX_MONSTERS])
goto exit_loop;
}
} else {
goto exit_loop;
}
}
exit_loop:
_monsterList.clear();
for (uint i = 0; i < _monsterSummaries.size(); ++i) {
maxVal = (_monsterSummaries[i]._level - 1) * 16 +
_monsterSummaries[i]._num;
if (_monsterSummaries[i]._level < 1 || _monsterSummaries[i]._level > 12
|| maxVal >= 196) {
_monsterSummaries[i]._level = 10;
_monsterSummaries[i]._num = getRandomNumber(15);
}
// Add monster details to list
_monsterLevel = _monsterSummaries[i]._level;
const Monster &srcMons = (*g_globals->_monsters)[_monsterSummaries[i]._num];
_monsterList.push_back(srcMons);
Monster &mons = _monsterList.back();
mons._level = _monsterSummaries[i]._level;
if (_monsterLevel > _maxLevelForImg) {
_maxLevelForImg = _monsterLevel;
_fleeThreshold = mons._fleeThreshold;
_monsterImgNum = mons._imgNum;
}
}
g_events->addView("Encounter");
}
void Encounter::randomAdjust() {
int rval = getRandomNumber(100);
_levelOffset = 0;
if (rval < 51) {
} else if (rval < 71)
_levelOffset += 1;
else if (rval < 86)
_levelOffset += 2;
else if (rval < 96)
_levelOffset += 3;
else
_levelOffset += 4;
}
const Monster *Encounter::getMonster() {
assert(_monsterNum > 0 && _monsterLevel > 0);
return &(*g_globals->_monsters)[_monsterNum + ((_monsterLevel - 1) * 16)];
}
bool Encounter::checkSurroundParty() const {
return getRandomNumber(100) > _fleeThreshold;
}
void Encounter::changeCharAlignment(Alignment align) {
if (g_globals->_currCharacter->_alignment != align) {
g_globals->_currCharacter->_alignment = align;
++_alignmentsChanged;
}
}
void Encounter::clearMonsters() {
_monsterSummaries.clear();
}
void Encounter::addMonster(byte id, byte level) {
_monsterSummaries.push_back(MonsterSummary(id, level));
}
} // namespace Game
} // namespace MM1
} // namespace MM