[Scummvm-git-logs] scummvm master -> 3b7bb9cfa92af9fe81344d60bc4e336003dc5f28

dreammaster noreply at scummvm.org
Sun Mar 26 05:26:41 UTC 2023


This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
b9fb7c9fca MM: MM1: Beginnings of enhanced mode combat view
bb220307f0 MM: MM1: Support inverse characters
a4e5e01414 MM: MM1: Adding initial combat info display
8b91aa90e1 MM: MM1: Adding combat options display
e8492022ef MM: MM1: Camel case the monster list
3b7bb9cfa9 MM: MM1: Fix display of combat party names


Commit: b9fb7c9fca8c32da66351c98c2a0beb73ece1b8f
    https://github.com/scummvm/scummvm/commit/b9fb7c9fca8c32da66351c98c2a0beb73ece1b8f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2023-03-25T22:21:37-07:00

Commit Message:
MM: MM1: Beginnings of enhanced mode combat view

Changed paths:
  A engines/mm/mm1/views_enh/combat.cpp
  A engines/mm/mm1/views_enh/combat.h
    engines/mm/mm1/views_enh/dialogs.h
    engines/mm/module.mk


diff --git a/engines/mm/mm1/views_enh/combat.cpp b/engines/mm/mm1/views_enh/combat.cpp
new file mode 100644
index 00000000000..2519702da29
--- /dev/null
+++ b/engines/mm/mm1/views_enh/combat.cpp
@@ -0,0 +1,854 @@
+/* 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/views_enh/combat.h"
+#include "mm/mm1/views/character_view_combat.h"
+#include "mm/mm1/game/encounter.h"
+#include "mm/mm1/globals.h"
+#include "mm/mm1/mm1.h"
+#include "mm/mm1/sound.h"
+
+namespace MM {
+namespace MM1 {
+namespace ViewsEnh {
+
+Combat::Combat() : ScrollView("Combat") {
+}
+
+void Combat::setMode(Mode newMode) {
+	_mode = newMode;
+
+	if (newMode == SELECT_OPTION) {
+		_option = OPTION_NONE;
+		MetaEngine::setKeybindingMode(KeybindingMode::KBMODE_COMBAT);
+	} else {
+		MetaEngine::setKeybindingMode(KeybindingMode::KBMODE_MENUS);
+	}
+
+	if (_mode == MONSTER_SPELL)
+		// Make a copy of monster spell 
+		_monsterSpellLines = getMonsterSpellMessage();
+
+	if (_mode != MONSTER_ADVANCES && _mode != MONSTER_ATTACK &&
+			_mode != MONSTER_SPELL)
+		_activeMonsterNum = -1;
+
+	redraw();
+}
+
+void Combat::disableAttacks() {
+	_allowFight = false;
+	_allowShoot = false;
+	_allowCast = false;
+	_allowAttack = false;
+}
+
+bool Combat::msgFocus(const FocusMessage &msg) {
+	g_globals->_currCharacter = g_globals->_combatParty[_currentChar];
+	MetaEngine::setKeybindingMode(KeybindingMode::KBMODE_COMBAT);
+
+	return true;
+}
+
+bool Combat::msgUnfocus(const UnfocusMessage &msg) {
+	MetaEngine::setKeybindingMode(KeybindingMode::KBMODE_MENUS);
+	return ScrollView::msgUnfocus(msg);
+}
+
+bool Combat::msgGame(const GameMessage &msg) {
+	if (msg._name == "COMBAT") {
+		// Clear combat data
+		clear();
+
+		loadMonsters();
+		setupCanAttacks();
+		setupHandicap();
+
+		addView();
+		combatLoop();
+		return true;
+
+	} else if (msg._name == "SPELL_RESULT") {
+		assert(msg._value >= 0 && msg._value < 40);
+		_spellResult._lines.clear();
+		_spellResult._lines.push_back(Line(msg._value, 1, msg._stringValue));
+		_spellResult._delaySeconds = 3;
+
+		setMode(SPELL_RESULT);
+		return true;
+	}
+
+	return false;
+}
+
+void Combat::draw() {
+	switch (_mode) {
+	case NEXT_ROUND:
+		writeMonsters();
+		resetBottom();
+		highlightNextRound();
+		delaySeconds(1);
+		return;
+	case MONSTER_ADVANCES:
+		writeString(0, 20, _monsterName);
+		writeString(STRING["dialogs.combat.advances"]);
+		writeSpaces(30);
+		writeRound();
+		writeMonsters();
+		delaySeconds(2);
+		return;
+	case MONSTERS_AFFECTED:
+		writeMonsterEffects();
+		delaySeconds(2);
+		return;
+	case MONSTER_SPELL:
+		writeMonsterSpell();
+		delaySeconds(2);
+		return;
+	case INFILTRATION:
+		writeInfiltration();
+		delaySeconds(3);
+		return;
+	case WAITS_FOR_OPENING:
+		writeWaitsForOpening();
+		delaySeconds(2);
+		return;
+	case CHAR_ATTACKS:
+		writeMonsters();
+		writeCharAttackDamage();
+		delaySeconds(3);
+		return;
+	case NO_EFFECT:
+		writeCharAttackNoEffect();
+		delaySeconds(3);
+		return;
+	case DEFEATED_MONSTERS:
+		writeDefeat();
+		Sound::sound2(SOUND_3);
+		delaySeconds(3);
+		return;
+	default:
+		break;
+	}
+
+	clearSurface();
+	writeStaticContent();
+	writeHandicap();
+	writeRound();
+	writePartyNumbers();
+	writeMonsters();
+	writeParty();
+
+	switch (_mode) {
+	case SELECT_OPTION:
+		writeOptions();
+		break;
+
+	case SPELL_RESULT:
+		writeSpellResult();
+		if (_spellResult._delaySeconds)
+			delaySeconds(_spellResult._delaySeconds);
+		break;
+
+	case MONSTER_ATTACK:
+		writeMonsterAttack();
+		delaySeconds(2);
+		break;
+
+	case MONSTER_FLEES:
+	case MONSTER_WANDERS:
+		writeMonsterAction(_mode == MONSTER_FLEES);
+		delaySeconds(2);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void Combat::timeout() {
+	switch (_mode) {
+	case NEXT_ROUND:
+		nextRound2();
+		break;
+	case MONSTER_ADVANCES:
+		nextRound3();
+		break;
+	case MONSTERS_AFFECTED:
+	case CHAR_ATTACKS:
+	case NO_EFFECT:
+	case MONSTER_FLEES:
+		removeDeadMonsters();
+		combatLoop();
+		break;
+	case MONSTER_WANDERS:
+	case INFILTRATION:
+	case MONSTER_ATTACK:
+		writeParty();
+		writeMonsters();
+		checkParty();
+		break;
+	case MONSTER_SPELL:
+		checkMonsterSpellDone();
+		break;
+	case WAITS_FOR_OPENING:
+		combatLoop(true);
+		break;
+	case DEFEATED_MONSTERS:
+		combatDone();
+		break;
+	case SPELL_RESULT:
+		if (_spellResult._timeoutCallback)
+			_spellResult._timeoutCallback();
+		else
+			// Character is done
+			block();
+		break;
+	default:
+		 break;
+	}
+}
+
+bool Combat::msgKeypress(const KeypressMessage &msg) {
+	if (endDelay())
+		return true;
+
+	if (_mode == SELECT_OPTION && _option != OPTION_NONE) {
+		switch (_option) {
+		case OPTION_FIGHT:
+		case OPTION_SHOOT:
+			if (msg.keycode >= Common::KEYCODE_a &&
+				msg.keycode < (int)(Common::KEYCODE_a + _attackableCount)) {
+				if (_option == OPTION_FIGHT)
+					fightMonster(msg.keycode - Common::KEYCODE_a);
+				else
+					shootMonster(msg.keycode - Common::KEYCODE_a);
+			}
+			break;
+
+		case OPTION_DELAY:
+			if (msg.keycode >= Common::KEYCODE_0 &&
+				msg.keycode <= Common::KEYCODE_9) {
+				g_globals->_delay = msg.keycode - Common::KEYCODE_0;
+				combatLoop();
+			}
+			break;
+
+		default:
+			break;
+		}
+	} else if (_mode == SPELL_RESULT && !isDelayActive()) {
+		// Displaying a spell result that required waiting for keypress
+		assert(_spellResult._timeoutCallback);
+		_spellResult._timeoutCallback();
+
+	} else if (isDelayActive()) {
+		// In all other modes, if a delay is active, any keypress
+		// will cause the delay to end immediately
+		endDelay();
+	}
+
+	return true;
+}
+
+bool Combat::msgAction(const ActionMessage &msg) {
+	if (endDelay())
+		return true;
+
+	if (_mode != SELECT_OPTION || (_option != OPTION_NONE &&
+			_option != OPTION_EXCHANGE))
+		return false;
+
+	switch (msg._action) {
+	case KEYBIND_VIEW_PARTY1:
+	case KEYBIND_VIEW_PARTY2:
+	case KEYBIND_VIEW_PARTY3:
+	case KEYBIND_VIEW_PARTY4:
+	case KEYBIND_VIEW_PARTY5:
+	case KEYBIND_VIEW_PARTY6: {
+		uint charNum = msg._action - KEYBIND_VIEW_PARTY1;
+		if (charNum < g_globals->_combatParty.size()) {
+			if (_option == OPTION_EXCHANGE) {
+				if (g_globals->_combatParty[charNum] != g_globals->_currCharacter)
+					exchangeWith(charNum);
+			} else {
+				g_globals->_currCharacter = g_globals->_combatParty[charNum];
+				addView("CharacterViewCombat");
+			}
+			return true;
+		}
+		break;
+	}
+
+	case KEYBIND_COMBAT_ATTACK:
+		attack();
+		break;
+	case KEYBIND_COMBAT_BLOCK:
+		block();
+		break;
+	case KEYBIND_COMBAT_CAST:
+		cast();
+		break;
+	case KEYBIND_DELAY:
+		delay();
+		break;
+	case KEYBIND_COMBAT_EXCHANGE:
+		exchange();
+		break;
+	case KEYBIND_COMBAT_FIGHT:
+		fight();
+		break;
+	case KEYBIND_PROTECT:
+		addView("Protect");
+		break;
+	case KEYBIND_QUICKREF:
+		addView("QuickRef");
+		break;
+	case KEYBIND_COMBAT_RETREAT:
+		retreat();
+		break;
+	case KEYBIND_COMBAT_SHOOT:
+		shoot();
+		break;
+	case KEYBIND_COMBAT_USE:
+		use();
+		break;
+	case KEYBIND_ESCAPE:
+		if (_mode == SELECT_OPTION) {
+			_option = OPTION_NONE;
+			combatLoop();
+		}
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
+
+void Combat::writeOptions() {
+	resetBottom();
+
+	switch (_option) {
+	case OPTION_NONE:
+		writeAllOptions();
+		break;
+	case OPTION_DELAY:
+		writeDelaySelect();
+		break;
+	case OPTION_EXCHANGE:
+		writeExchangeSelect();
+		break;
+	case OPTION_FIGHT:
+		writeFightSelect();
+		break;
+	case OPTION_SHOOT:
+		writeShootSelect();
+		break;
+	default:
+		break;
+	}
+}
+
+void Combat::writeAllOptions() {
+	assert(g_globals->_currCharacter &&
+		g_globals->_currCharacter == g_globals->_combatParty[_currentChar]);
+	const Character &c = *g_globals->_currCharacter;
+	writeString(0, 20, STRING["dialogs.combat.options_for"]);
+	writeString(0, 22, c._name);
+
+	// Highlight the currently active character
+	writeChar(3 + 4 * (_currentChar % 2), 3 + (_currentChar / 2),
+		(unsigned char)'1' + _currentChar + 0x80);
+
+	bool testShoot;
+	if (c._canAttack) {
+		writeAttackOptions();
+		_allowAttack = true;
+		_allowFight = true;
+
+		// Archers can always attack
+		testShoot = c._class == ARCHER;
+	} else {
+		testShoot = true;
+	}
+	if (testShoot && c._missileAttr._base) {
+		_allowShoot = true;
+		writeShootOption();
+	}
+
+	if (c._sp._current) {
+		writeCastOption();
+		_allowCast = true;
+	}
+
+	writeString(16, 22, STRING["dialogs.combat.exchange_use"]);
+	writeString(16, 23, STRING["dialogs.combat.retreat_block"]);
+}
+
+void Combat::writeDelaySelect() {
+	resetBottom();
+	writeString(0, 20, STRING["dialogs.combat.set_delay"]);
+	writeString(0, 23, Common::String::format(
+		STRING["dialogs.combat.delay_currently"].c_str(),
+		g_globals->_delay));
+	escToGoBack(0, 23);
+}
+
+void Combat::writeExchangeSelect() {
+	resetBottom();
+	writeString(7, 20, Common::String::format(
+		STRING["dialogs.combat.exchange_places"].c_str(),
+		'0' + g_globals->_combatParty.size()));
+	escToGoBack(12, 23);
+}
+
+void Combat::writeFightSelect() {
+	_attackableCount = MIN(_attackersCount, (int)_remainingMonsters.size());
+
+	writeString(10, 20, Common::String::format(
+		STRING["dialogs.combat.fight_which"].c_str(), 'A' + _attackableCount - 1));
+	escToGoBack(12, 23);
+}
+
+void Combat::writeShootSelect() {
+	_attackableCount = MIN(_attackersCount, (int)_remainingMonsters.size());
+
+	writeString(10, 20, Common::String::format(
+		STRING["dialogs.combat.shoot_which"].c_str(), 'A' + _attackableCount - 1));
+	escToGoBack(12, 23);
+}
+
+void Combat::writeAttackOptions() {
+	writeString(16, 20, STRING["dialogs.combat.attack"]);
+	writeString(16, 21, STRING["dialogs.combat.fight"]);
+}
+
+void Combat::writeCastOption() {
+	writeString(30, 21, STRING["dialogs.combat.cast"]);
+}
+
+void Combat::writeShootOption() {
+	writeString(30, 20, STRING["dialogs.combat.shoot"]);
+}
+
+void Combat::resetBottom() {
+	clearLines(20, 24);
+	_allowFight = _allowShoot = false;
+	_allowCast = _allowAttack = false;
+}
+
+void Combat::writeStaticContent() {
+	writeString(0, 0, STRING["dialogs.combat.combat"]);
+	writeString(0, 1, STRING["dialogs.combat.round"]);
+	writeString(0, 7, STRING["dialogs.combat.delay"]);
+	writeString(0, 8, STRING["dialogs.combat.protect"]);
+	writeString(0, 9, STRING["dialogs.combat.quickref"]);
+	writeString(0, 10, STRING["dialogs.combat.view_char"]);
+	writeString(0, 12, STRING["dialogs.combat.handicap"]);
+
+	_textPos = Common::Point(0, 15);
+	for (int i = 0; i < 40; ++i)
+		writeChar('-');
+}
+
+void Combat::writeHandicap() {
+	writeString(0, 13, "          ");
+	_textPos.x = 0;
+
+	switch (_handicap) {
+	case HANDICAP_EVEN:
+		writeString(STRING["dialogs.combat.even"]);
+		break;
+	case HANDICAP_PARTY:
+		writeString(STRING["dialogs.combat.party_plus"]);
+		writeNumber(_handicapDelta);
+		break;
+	case HANDICAP_MONSTER:
+		writeString(STRING["dialogs.combat.monster_plus"]);
+		writeNumber(_handicapDelta);
+		break;
+	}
+}
+
+void Combat::writeRound() {
+	writeNumber(7, 1, _roundNum);
+}
+
+void Combat::writePartyNumbers() {
+	for (uint i = 0; i < g_globals->_combatParty.size(); ++i) {
+		writeChar(2 + 4 * (i % 2), 3 + (i / 2),
+			g_globals->_combatParty[i]->_canAttack ? '+' : ' ');
+		writeChar('1' + i);
+	}
+}
+
+void Combat::writeMonsters() {
+	if (_remainingMonsters.empty()) {
+		_textPos = Common::Point(10, 0);
+		writeSpaces(30);
+	} else {
+		for (int i = 0; i < (int)_remainingMonsters.size(); ++i) {
+			_textPos = Common::Point(11, i);
+			writeChar(i < _attackersCount ? '+' : ' ');
+			unsigned char c = 'A' + i;
+			if ((i == _activeMonsterNum) && (_mode == MONSTER_ADVANCES ||
+				_mode == MONSTER_ATTACK || _mode == MONSTER_SPELL))
+				c |= 0x80;
+
+			writeChar(c);
+			writeString(") ");
+			writeString(_remainingMonsters[i]->_name);
+			writeMonsterStatus(i);
+		}
+	}
+
+	for (; _textPos.y < 15; _textPos.y++) {
+		_textPos.x = 10;
+		writeSpaces(30);
+	}
+}
+
+void Combat::writeMonsterStatus(int monsterNum) {
+	_monsterP = _remainingMonsters[monsterNum];
+	monsterIndexOf();
+	byte statusBits = _remainingMonsters[monsterNum]->_status;
+
+	if (statusBits) {
+		writeDots();
+
+		int status;
+		if (statusBits == MONFLAG_DEAD) {
+			status = MON_DEAD;
+		} else {	
+			for (status = MON_PARALYZED; !(statusBits & 0x80);
+					++status, statusBits <<= 1) {
+			}
+		}
+
+		writeString(STRING[Common::String::format("dialogs.combat.status.%d",
+			status)]);
+	} else if (_monsterP->_hp != _monsterP->_defaultHP) {
+		writeDots();
+		writeString(STRING["dialogs.combat.status.wounded"]);
+	} else {
+		writeSpaces(40 - _textPos.x);
+	}
+}
+
+void Combat::writeDots() {
+	while (_textPos.x < 30)
+		writeChar('.');
+}
+
+void Combat::writeParty() {
+	clearPartyArea();
+
+	for (uint i = 0; i < g_globals->_combatParty.size(); ++i) {
+		const Character &c = *g_globals->_combatParty[i];
+		writeString(21 * (i % 2), 16 + (i / 2),
+			Common::String::format("%c%c) %s",
+				(c._condition == 0) ? ' ' : '*',
+				'1' + i,
+				c._name
+			)
+		);
+	}
+}
+
+void Combat::clearPartyArea() {
+	clearLines(16, 18);
+}
+
+void Combat::writeDefeat() {
+	writeString(10, 0, "+----------------------------+");
+	for (int y = 1; y < 8; ++y)
+		writeString(10, y, "!                            !");
+	writeString(10, 8, "+----------------------------+");
+
+	writeString(10, 2, STRING["dialogs.combat.defeating1"]);
+	writeString(10, 4, STRING["dialogs.combat.defeating2"]);
+	writeNumber(14, 6, _totalExperience);
+	_textPos.x++;
+	writeString(STRING["dialogs.combat.xp"]);
+}
+
+void Combat::highlightNextRound() {
+	Common::String s = Common::String::format("%s%d",
+		STRING["dialogs.combat.round"].c_str(),
+		_roundNum);
+	
+	for (uint i = 0; i < s.size(); ++i)
+		s.setChar(s[i] | 0x80, i);
+
+	writeString(0, 1, s);
+}
+
+void Combat::writeMonsterEffects() {
+	if (_monstersRegenerate)
+		writeString(0, 21, STRING["dialogs.combat.regenerate"]);
+
+	if (_monstersResistSpells) {
+		if (_textPos.y != 21)
+			_textPos.y = 20;
+
+		writeString(0, _textPos.y + 1, STRING["dialogs.combat.overcome"]);
+	}
+
+	writeMonsters();
+}
+
+void Combat::writeMonsterAction(bool flees) {
+	resetBottom();
+	writeString(0, 20, _monsterName);
+	writeChar(' ');
+	writeString(STRING[flees ?
+		"dialogs.combat.monster_flees" : "dialogs.combat.monster_wanders"
+	]);
+}
+
+void Combat::writeMonsterSpell() {
+	resetBottom();
+
+	for (int i = 0, y = 0; i < (int)_monsterSpellLines.size() &&
+		_monsterSpellLines[i].y > y;
+		y = _monsterSpellLines[i].y, ++i) {
+		Common::String text = _monsterSpellLines[i]._text;
+		size_t idx;
+		while ((idx = text.findFirstOf(' ')) != Common::String::npos)
+			text.deleteChar(idx);
+
+		writeString(0, _monsterSpellLines[i].y, text);
+	}
+}
+
+void Combat::writeMonsterAttack() {
+	Common::String monsterName = _monsterP->_name;
+	Common::String attackStyle = STRING[Common::String::format(
+		"dialogs.combat.attack_types.%d", _monsterAttackStyle)];
+	Character &c = *g_globals->_currCharacter;
+
+	Common::String line = Common::String::format("%s %s %s",
+		monsterName.c_str(),
+		attackStyle.c_str(),
+		c._name
+	);
+	writeString(0, 20, line);
+	writeString(0, 21, getAttackString());
+
+	if (_damage) {
+		// Attacks wake up sleeping characters
+		if (!(c._condition & BAD_CONDITION))
+			c._condition &= ~ASLEEP;
+
+		// Also check for secondary monster touch action here
+		// This returns a text line to display, and can also
+		// adjust the damage amount. Another reason why we
+		// can't actually apply damage until here
+		int yp = 22;
+		if (monsterTouch(line))
+			writeString(0, yp++, line);
+
+		Common::String damageStr = subtractDamageFromChar();
+		if (!damageStr.empty())
+			writeString(0, yp, damageStr);
+	}
+}
+
+void Combat::writeInfiltration() {
+	Common::String line = Common::String::format("%s %s",
+		_monsterP->getDisplayName().c_str(),
+		STRING["dialogs.combat.infiltration"].c_str());
+
+	resetBottom();
+	writeString(0, 20, line);
+	Sound::sound(SOUND_2);
+	Sound::sound(SOUND_2);
+}
+
+void Combat::writeWaitsForOpening() {
+	Common::String line = Common::String::format("%s %s",
+		_monsterP->getDisplayName().c_str(),
+		STRING["dialogs.combat.infiltration"].c_str()
+	);
+
+	resetBottom();
+	writeString(0, 20, line);
+}
+
+void Combat::writeSpellResult() {
+	for (uint i = 0; i < _spellResult._lines.size(); ++i) {
+		const Line &l = _spellResult._lines[i];
+		writeString(l.x, l.y + 20, l._text);
+	}
+}
+
+void Combat::checkMonsterSpellDone() {
+	for (uint i = 0; i < _monsterSpellLines.size(); ++i) {
+		if (i > 0 && _monsterSpellLines[i].y ==
+				_monsterSpellLines[i - 1].y) {
+			// Remove the message line just displayed, and redraw
+			// so the next one can be shown
+			_monsterSpellLines.remove_at(i - 1);
+			redraw();
+			return;
+		}
+	}
+
+	checkParty();
+}
+
+void Combat::delay() {
+	setOption(OPTION_DELAY);
+}
+
+void Combat::exchange() {
+	if (g_globals->_combatParty.size() > 1)
+		setOption(OPTION_EXCHANGE);
+}
+
+void Combat::fight() {
+	if (_allowFight) {
+		if (_remainingMonsters.size() < 2) {
+			attackMonsterPhysical();
+		} else {
+			setOption(OPTION_FIGHT);
+		}
+	}
+}
+
+void Combat::shoot() {
+	if (_allowShoot) {
+		if (_remainingMonsters.size() < 2) {
+			attackMonsterPhysical();
+		} else {
+			setOption(OPTION_SHOOT);
+		}
+	}
+}
+
+void Combat::writeMessage() {
+	resetBottom();
+	for (const auto &line : _message)
+		writeString(line.x, line.y, line._text);
+}
+
+void Combat::writeCharAttackDamage() {
+	resetBottom();
+
+	writeString(0, 20, Common::String::format("%s %s %s",
+		g_globals->_currCharacter->_name,
+		STRING[_isShooting ? "dialogs.combat.shoots" :
+		"dialogs.combat.attacks"].c_str(),
+		_monsterP->_name.c_str()
+	));
+	_isShooting = false;
+
+	writeString(0, 21, getAttackString());
+
+	if (_monsterP->_status == MONFLAG_DEAD) {
+		writeString(0, 22, Common::String::format("%s %s",
+			_monsterP->_name.c_str(),
+			STRING["dialogs.combat.goes_down"].c_str()));
+	}
+}
+
+void Combat::writeCharAttackNoEffect() {
+	resetBottom();
+
+	writeString(0, 20, Common::String::format("%s %s %s",
+		g_globals->_currCharacter->_name,
+		STRING[_isShooting ? "dialogs.combat.shoots" :
+		"dialogs.combat.attacks"].c_str(),
+		_monsterP->_name.c_str()
+	));
+	_isShooting = false;
+
+	writeString(0, 21, STRING["dialogs.combat.weapon_no_effect"]);
+}
+
+Common::String Combat::getAttackString() {
+	Common::String line1;
+	if (_numberOfTimes == 1) {
+		line1 = STRING["dialogs.combat.once"];
+	} else {
+		line1 = Common::String::format("%d %s", _numberOfTimes,
+			STRING["dialogs.combat.times"].c_str());
+	}
+
+	line1 += Common::String::format(" %s ", STRING["dialogs.combat.and"].c_str());
+
+	if (_displayedDamage == 0) {
+		line1 += STRING["dialogs.combat.misses"];
+	} else {
+		line1 += STRING["dialogs.combat.hit"];
+
+		if (_numberOfTimes > 1) {
+			line1 += ' ';
+
+			if (_timesHit == 1) {
+				line1 += STRING["dialogs.combat.once"];
+			} else {
+				line1 += Common::String::format("%d %s", _timesHit,
+					STRING["dialogs.combat.times"].c_str());
+			}
+		}
+
+		line1 += Common::String::format(" %s %d %s",
+			STRING["dialogs.combat.for"].c_str(), _displayedDamage,
+			STRING[_damage == 1 ? "dialogs.combat.point" : "dialogs.combat.points"].c_str());
+
+		if (line1.size() < 30) {
+			line1 += ' ';
+			line1 += STRING["dialogs.combat.of_damage"];
+		} else {
+			line1 += '!';
+		}
+	}
+
+	return line1;
+}
+
+void Combat::setOption(SelectedOption option) {
+	MetaEngine::setKeybindingMode((option == OPTION_EXCHANGE) ?
+		KeybindingMode::KBMODE_PARTY_MENUS :
+		KeybindingMode::KBMODE_MENUS);
+	_option = option;
+	redraw();
+}
+
+void Combat::displaySpellResult(const InfoMessage &msg) {
+	assert(msg._delaySeconds);
+	_spellResult = msg;
+
+	setMode(SPELL_RESULT);
+}
+
+void Combat::combatDone() {
+	Game::Combat::combatDone();
+
+	close();
+	g_events->send("Game", GameMessage("UPDATE"));
+}
+
+} // namespace ViewsEnh
+} // namespace MM1
+} // namespace MM
diff --git a/engines/mm/mm1/views_enh/combat.h b/engines/mm/mm1/views_enh/combat.h
new file mode 100644
index 00000000000..445c42f64c5
--- /dev/null
+++ b/engines/mm/mm1/views_enh/combat.h
@@ -0,0 +1,282 @@
+/* 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/>.
+ *
+ */
+
+#ifndef MM1_VIEWS_ENH_COMBAT_H
+#define MM1_VIEWS_ENH_COMBAT_H
+
+#include "mm/mm1/game/combat.h"
+#include "mm/mm1/views_enh/scroll_view.h"
+
+namespace MM {
+namespace MM1 {
+namespace ViewsEnh {
+
+class Combat : public ScrollView, public Game::Combat {
+private:
+	// TODO: Stuff to refactor
+	void writeSpaces(int count) { error("TODO"); }
+	void clearLines(int y1, int y2) { error("TODO"); }
+	void escToGoBack(int x, int y) { error("TODO"); }
+
+private:
+	LineArray _monsterSpellLines;
+	uint _attackableCount = 0;
+	InfoMessage _spellResult;
+	// Combat options that have sub-option selection
+	enum SelectedOption {
+		OPTION_NONE, OPTION_DELAY, OPTION_EXCHANGE,
+		OPTION_FIGHT, OPTION_SHOOT
+	};
+	SelectedOption _option = OPTION_NONE;
+
+	/**
+	 * Selects a combat option that requires a selection
+	 */
+	void setOption(SelectedOption option);
+
+	void writeOptions();
+	void writeAllOptions();
+	void writeAttackOptions();
+	void writeCastOption();
+	void writeShootOption();
+	void resetBottom();
+
+	/**
+	 * Write the encounter handicap
+	 */
+	void writeHandicap();
+
+	/**
+	 * Write out all the static content
+	 */
+	void writeStaticContent();
+
+	/**
+	 * Write out the round number
+	 */
+	void writeRound();
+
+	/**
+	 * Writes out the party member numbers,
+	 * with a plus next to each if they can attack
+	 */
+	void writePartyNumbers();
+
+	/**
+	 * Write the monsters list
+	 */
+	void writeMonsters();
+
+	/**
+	 * Write out a monster's status
+	 */
+	void writeMonsterStatus(int monsterNum);
+
+	/**
+	 * Write out a series of dots
+	 */
+	void writeDots();
+
+	/**
+	 * Writes out the party members
+	 */
+	void writeParty();
+
+	/**
+	 * Clears the party area
+	 */
+	void clearPartyArea();
+
+	/**
+	 * Writes the result of defeating all the monsters
+	 */
+	void writeDefeat();
+
+	/**
+	 * Highlight the round number indicator
+	 */
+	void highlightNextRound();
+
+	/**
+	 * Write monster changes
+	 */
+	void writeMonsterEffects();
+
+	/**
+	 * Handles a monster action
+	 */
+	void writeMonsterAction(bool flees);
+
+	/**
+	 * Write out message from a monster casting a spell
+	 */
+	void writeMonsterSpell();
+
+	/**
+	 * Write out monster's attack
+	 */
+	void writeMonsterAttack();
+
+	/**
+	 * Write message for monster infiltrating the party
+	 */
+	void writeInfiltration();
+
+	/**
+	 * Write message for monster waits for an opening
+	 */
+	void writeWaitsForOpening();
+
+	/**
+	 * Writes the result of a spell
+	 */
+	void writeSpellResult();
+
+	/**
+	 * Whether there's messages remaining
+	 */
+	void checkMonsterSpellDone();
+
+	/**
+	 * Delay option
+	 */
+	void delay();
+
+	/**
+	 * Exchange option
+	 */
+	void exchange();
+
+	/**
+	 * Fight option
+	 */
+	void fight();
+
+	/**
+	 * Shoot option
+	 */
+	void shoot();
+
+	/**
+	 * Write message for characters attacking monsters
+	 */
+	void writeCharAttackDamage();
+
+	/**
+	 * Write message for character attack having no effect
+	 */
+	void writeCharAttackNoEffect();
+
+	/**
+	 * Get attack damage string
+	 */
+	Common::String getAttackString();
+
+	/**
+	 * Writes out a message
+	 */
+	void writeMessage();
+
+	/**
+	 * Writes text for delay number selection
+	 */
+	void writeDelaySelect();
+
+	/**
+	 * Write text for exchange party member
+	 */
+	void writeExchangeSelect();
+
+	/**
+	 * Having selected to fight, selects monster to attack
+	 */
+	void writeFightSelect();
+
+	/**
+	 * Having selected to shoot, selects monster to attack
+	 */
+	void writeShootSelect();
+
+protected:
+	/**
+	 * Sets a new display mode
+	 */
+	void setMode(Mode newMode) override;
+
+	/**
+	 * Does final cleanup when combat is done
+	 */
+	void combatDone() override;
+
+public:
+	Combat();
+	virtual ~Combat() {}
+
+	void displaySpellResult(const InfoMessage &msg) override;
+
+	/**
+	 * Disable the flags for allowing attacks for
+	 * the current character
+	 */
+	void disableAttacks();
+
+	/**
+	 * Called when the view is focused
+	 */
+	bool msgFocus(const FocusMessage &msg) override;
+
+	/**
+	 * Called when the view is unfocused
+	 */
+	bool msgUnfocus(const UnfocusMessage &msg) override;
+
+	/**
+	 * Called for game messages
+	 */
+	bool msgGame(const GameMessage &msg) override;
+
+	/**
+	 * Draw the Combat details overlayed on
+	 * the existing game screen
+	 */
+	void draw() override;
+
+	/**
+	 * Handles delay timeouts
+	 */
+	void timeout() override;
+
+	/**
+	 * Handles keypresses
+	 */
+	bool msgKeypress(const KeypressMessage &msg) override;
+
+	/**
+	 * Key binder actions
+	 */
+	bool msgAction(const ActionMessage &msg) override;
+};
+
+} // namespace ViewsEnh
+} // namespace MM1
+} // namespace MM
+
+#endif
diff --git a/engines/mm/mm1/views_enh/dialogs.h b/engines/mm/mm1/views_enh/dialogs.h
index 3ab802a3dee..60e6b8f1fb0 100644
--- a/engines/mm/mm1/views_enh/dialogs.h
+++ b/engines/mm/mm1/views_enh/dialogs.h
@@ -29,6 +29,7 @@
 #include "mm/mm1/views_enh/character_inventory.h"
 #include "mm/mm1/views_enh/character_select.h"
 #include "mm/mm1/views_enh/characters.h"
+#include "mm/mm1/views_enh/combat.h"
 #include "mm/mm1/views_enh/confirm.h"
 #include "mm/mm1/views_enh/create_characters.h"
 #include "mm/mm1/views_enh/encounter.h"
@@ -79,6 +80,7 @@ private:
 	ViewsEnh::CharacterInventory _characterInventory;
 	ViewsEnh::CharacterSelect _characterSelect;
 	ViewsEnh::Characters _characters;
+	ViewsEnh::Combat _combat;
 	ViewsEnh::Confirm _confirm;
 	ViewsEnh::CreateCharacters _createCharacters;
 	ViewsEnh::Encounter _encounter;
diff --git a/engines/mm/module.mk b/engines/mm/module.mk
index 650d34bcfce..98d9d534bdf 100644
--- a/engines/mm/module.mk
+++ b/engines/mm/module.mk
@@ -133,6 +133,7 @@ MODULE_OBJS += \
 	mm1/views_enh/character_select.o \
 	mm1/views_enh/character_view.o \
 	mm1/views_enh/characters.o \
+	mm1/views_enh/combat.o \
 	mm1/views_enh/confirm.o \
 	mm1/views_enh/create_characters.o \
 	mm1/views_enh/dialogs.o \


Commit: bb220307f04e9d497c5eab60df942706372e26ba
    https://github.com/scummvm/scummvm/commit/bb220307f04e9d497c5eab60df942706372e26ba
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2023-03-25T22:21:38-07:00

Commit Message:
MM: MM1: Support inverse characters

Changed paths:
    engines/mm/mm1/views_enh/text_view.cpp
    engines/mm/mm1/views_enh/text_view.h
    engines/mm/shared/utils/xeen_font.cpp


diff --git a/engines/mm/mm1/views_enh/text_view.cpp b/engines/mm/mm1/views_enh/text_view.cpp
index 026a85770b9..3bfc4fbd6a0 100644
--- a/engines/mm/mm1/views_enh/text_view.cpp
+++ b/engines/mm/mm1/views_enh/text_view.cpp
@@ -50,10 +50,9 @@ XeenFont *TextView::getFont() const {
 		&g_globals->_fontNormal;
 }
 
-void TextView::writeChar(char c) {
-	assert((unsigned char)c < 0x80);
+void TextView::writeChar(unsigned char c) {
 	XeenFont::setColors(_colorsNum);
-	Graphics::Font &font = *getFont();
+	XeenFont &font = *getFont();
 
 	if (c == '\r' || c == '\n') {
 		_textPos.x = 0;
@@ -74,7 +73,7 @@ void TextView::writeChar(char c) {
 	}
 }
 
-void TextView::writeChar(int x, int y, char c) {
+void TextView::writeChar(int x, int y, unsigned char c) {
 	_textPos.x = x;
 	_textPos.y = y;
 	writeChar(c);
diff --git a/engines/mm/mm1/views_enh/text_view.h b/engines/mm/mm1/views_enh/text_view.h
index 53565172651..e8e770f7ce2 100644
--- a/engines/mm/mm1/views_enh/text_view.h
+++ b/engines/mm/mm1/views_enh/text_view.h
@@ -52,8 +52,8 @@ protected:
 	/**
 	 * Write a character
 	 */
-	void writeChar(char c);
-	void writeChar(int x, int y, char c);
+	void writeChar(unsigned char c);
+	void writeChar(int x, int y, unsigned char c);
 
 	/**
 	 * Write some text
diff --git a/engines/mm/shared/utils/xeen_font.cpp b/engines/mm/shared/utils/xeen_font.cpp
index fd8e449ff53..5b84d437702 100644
--- a/engines/mm/shared/utils/xeen_font.cpp
+++ b/engines/mm/shared/utils/xeen_font.cpp
@@ -56,15 +56,18 @@ void XeenFont::setColors(uint index) {
 }
 
 int XeenFont::getCharWidth(uint32 chr) const {
-	assert(chr < 128);
+	assert(chr < 256);
 	return _widths[chr & 0x7f];
 }
 
 void XeenFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
-	assert(chr < 128);
+	assert(chr < 256);
 	if (chr == 'g' || chr == 'p' || chr == 'q' || chr == 'y')
 		++y;
 
+	bool isInverse = (chr >= 128);
+	chr &= 0x7f;
+
 	const uint16 *src = &_data[chr * FONT_HEIGHT];
 	for (int yCtr = 0; yCtr < FONT_HEIGHT; ++yCtr, ++src) {
 		if ((y + yCtr) < 0 || (y + yCtr) > dst->h)
@@ -75,8 +78,12 @@ void XeenFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32
 
 		for (int xCtr = 0; xCtr < _widths[chr];
 				++xCtr, ++dest, srcVal >>= 2) {
-			if ((srcVal & 3) && (x + xCtr) >= 0 && (x + xCtr) < dst->w)
-				*dest = _colors[srcVal & 3];
+			if ((x + xCtr) >= 0 && (x + xCtr) < dst->w) {
+				if (isInverse)
+					*dest = (srcVal & 3) ? 2 : 0;
+				else if (srcVal & 3)
+					*dest = _colors[srcVal & 3];
+			}
 		}
 	}
 }


Commit: a4e5e014143302f6c27b05341a87246f5cc273af
    https://github.com/scummvm/scummvm/commit/a4e5e014143302f6c27b05341a87246f5cc273af
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2023-03-25T22:21:38-07:00

Commit Message:
MM: MM1: Adding initial combat info display

Changed paths:
    devtools/create_mm/files/mm1/strings_en.yml
    engines/mm/mm1/views_enh/combat.cpp
    engines/mm/mm1/views_enh/combat.h
    engines/mm/mm1/views_enh/scroll_view.cpp
    engines/mm/mm1/views_enh/scroll_view.h


diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml
index fbc07fd9edb..9b525c735b1 100644
--- a/devtools/create_mm/files/mm1/strings_en.yml
+++ b/devtools/create_mm/files/mm1/strings_en.yml
@@ -354,23 +354,23 @@ dialogs:
 		alignment_slips: "*** Alignment slips ***"
 		combat: "Combat!"
 	combat:
-		combat: "combat"
+		combat: "Combat"
 		round: "Round #"
-		delay: "d delay"
-		protect: "p protect"
-		quickref: "q quickref"
-		view_char: "# view ch"
-		handicap: "handicap"
-		options_for: "options for: "
-		attack: "'a' attack(a)"
-		cast: "'c' cast"
-		fight: "'f' fight(+)"
-		shoot: "'s' shoot"
-		exchange_use: "'e' exchange  'u' use"
-		retreat_block: "'r' retreat   'b' block"
-		even: "even"
-		party_plus: "party +"
-		monster_plus: "monster +"
+		delay: "D Delay"
+		protect: "P Protect"
+		quickref: "Q QuickRef"
+		view_char: "# View Ch"
+		handicap: "Handicap"
+		options_for: "Options for: "
+		attack: "'A' Attack(a)"
+		cast: "'C' Cast"
+		fight: "'F' Fight(+)"
+		shoot: "'S' Shoot"
+		exchange_use: "'E' Exchange  'U' Use"
+		retreat_block: "'R' Retreat   'B' Block"
+		even: "Even"
+		party_plus: "Party +"
+		monster_plus: "Monster +"
 		and_goes_down: "and goes down!!!"
 		goes_down: "goes down!!!"
 		dies: "dies!"
diff --git a/engines/mm/mm1/views_enh/combat.cpp b/engines/mm/mm1/views_enh/combat.cpp
index 2519702da29..bfab55cfb32 100644
--- a/engines/mm/mm1/views_enh/combat.cpp
+++ b/engines/mm/mm1/views_enh/combat.cpp
@@ -30,6 +30,10 @@ namespace MM {
 namespace MM1 {
 namespace ViewsEnh {
 
+#define MONSTERS_X 120
+#define BOTTOM_Y 120
+#define LINE_H 8
+
 Combat::Combat() : ScrollView("Combat") {
 }
 
@@ -156,6 +160,7 @@ void Combat::draw() {
 	writePartyNumbers();
 	writeMonsters();
 	writeParty();
+	return; //***DEBUG***
 
 	switch (_mode) {
 	case SELECT_OPTION:
@@ -450,29 +455,54 @@ void Combat::writeShootOption() {
 	writeString(30, 20, STRING["dialogs.combat.shoot"]);
 }
 
+void Combat::clearSurface() {
+	frame();
+	fill();
+
+	clearBottom();
+
+	drawButtons();
+}
+
+void Combat::clearBottom() {
+	_bounds = Common::Rect(0, BOTTOM_Y, 320, 200);
+	frame();
+	fill();
+
+	_bounds = Common::Rect(0, 0, 320, 200);
+}
+
+void Combat::clearArea(const Common::Rect &r) {
+	Graphics::ManagedSurface s = getSurface();
+	Common::Rect area = r;
+	area.translate(_innerBounds.left, _innerBounds.top);
+	area.right = MIN(area.right, _innerBounds.right);
+
+	s.fillRect(area, 0x99);
+}
+
+
 void Combat::resetBottom() {
-	clearLines(20, 24);
+	clearBottom();
 	_allowFight = _allowShoot = false;
 	_allowCast = _allowAttack = false;
 }
 
 void Combat::writeStaticContent() {
+	setReduced(false);
 	writeString(0, 0, STRING["dialogs.combat.combat"]);
-	writeString(0, 1, STRING["dialogs.combat.round"]);
-	writeString(0, 7, STRING["dialogs.combat.delay"]);
-	writeString(0, 8, STRING["dialogs.combat.protect"]);
-	writeString(0, 9, STRING["dialogs.combat.quickref"]);
-	writeString(0, 10, STRING["dialogs.combat.view_char"]);
-	writeString(0, 12, STRING["dialogs.combat.handicap"]);
-
-	_textPos = Common::Point(0, 15);
-	for (int i = 0; i < 40; ++i)
-		writeChar('-');
+	writeString(0, 7 * LINE_H, STRING["dialogs.combat.delay"]);
+	writeString(0, 8 * LINE_H, STRING["dialogs.combat.protect"]);
+	writeString(0, 9 * LINE_H, STRING["dialogs.combat.quickref"]);
+	writeString(0, 10 * LINE_H, STRING["dialogs.combat.view_char"]);
 }
 
 void Combat::writeHandicap() {
-	writeString(0, 13, "          ");
-	_textPos.x = 0;
+	writeString(0, 12 * LINE_H, STRING["dialogs.combat.handicap"]);
+
+	clearArea(Common::Rect(0, 13 * LINE_H, 100, 14 * LINE_H));
+
+	_textPos = Common::Point(0, 13 * LINE_H);
 
 	switch (_handicap) {
 	case HANDICAP_EVEN:
@@ -490,40 +520,34 @@ void Combat::writeHandicap() {
 }
 
 void Combat::writeRound() {
-	writeNumber(7, 1, _roundNum);
+	writeString(0, LINE_H, Common::String::format("%s%d",
+		STRING["dialogs.combat.round"].c_str(), _roundNum));
 }
 
 void Combat::writePartyNumbers() {
 	for (uint i = 0; i < g_globals->_combatParty.size(); ++i) {
-		writeChar(2 + 4 * (i % 2), 3 + (i / 2),
+		writeChar((2 + 4 * (i % 2)) * 8, (3 + (i / 2)) * LINE_H,
 			g_globals->_combatParty[i]->_canAttack ? '+' : ' ');
 		writeChar('1' + i);
 	}
 }
 
 void Combat::writeMonsters() {
-	if (_remainingMonsters.empty()) {
-		_textPos = Common::Point(10, 0);
-		writeSpaces(30);
-	} else {
-		for (int i = 0; i < (int)_remainingMonsters.size(); ++i) {
-			_textPos = Common::Point(11, i);
-			writeChar(i < _attackersCount ? '+' : ' ');
-			unsigned char c = 'A' + i;
-			if ((i == _activeMonsterNum) && (_mode == MONSTER_ADVANCES ||
-				_mode == MONSTER_ATTACK || _mode == MONSTER_SPELL))
-				c |= 0x80;
-
-			writeChar(c);
-			writeString(") ");
-			writeString(_remainingMonsters[i]->_name);
-			writeMonsterStatus(i);
-		}
-	}
+	Common::String mStr = "A)";
+	setReduced(true);
 
-	for (; _textPos.y < 15; _textPos.y++) {
-		_textPos.x = 10;
-		writeSpaces(30);
+	for (int i = 0; i < (int)_remainingMonsters.size(); ++i) {
+		writeString(MONSTERS_X, i * LINE_H, (i < _attackersCount) ? "+" : " ");
+
+		unsigned char c = 'A' + i;
+		if ((i == _activeMonsterNum) && (_mode == MONSTER_ADVANCES ||
+			_mode == MONSTER_ATTACK || _mode == MONSTER_SPELL))
+			c |= 0x80;
+		mStr.setChar(c, 0);
+		writeString(MONSTERS_X + 16, i * LINE_H, mStr, ALIGN_RIGHT);
+
+		writeString(MONSTERS_X + 22, i * LINE_H, _remainingMonsters[i]->_name);
+		writeMonsterStatus(i);
 	}
 }
 
@@ -549,13 +573,14 @@ void Combat::writeMonsterStatus(int monsterNum) {
 	} else if (_monsterP->_hp != _monsterP->_defaultHP) {
 		writeDots();
 		writeString(STRING["dialogs.combat.status.wounded"]);
-	} else {
-		writeSpaces(40 - _textPos.x);
 	}
 }
 
 void Combat::writeDots() {
-	while (_textPos.x < 30)
+	const int dotWidth = getStringWidth(".");
+	_textPos.x = ((_textPos.x + dotWidth - 1) / dotWidth) * dotWidth;
+
+	while (_textPos.x < 240)
 		writeChar('.');
 }
 
@@ -564,7 +589,7 @@ void Combat::writeParty() {
 
 	for (uint i = 0; i < g_globals->_combatParty.size(); ++i) {
 		const Character &c = *g_globals->_combatParty[i];
-		writeString(21 * (i % 2), 16 + (i / 2),
+		writeString(160 * (i % 2), (15 + (i / 2)) * LINE_H,
 			Common::String::format("%c%c) %s",
 				(c._condition == 0) ? ' ' : '*',
 				'1' + i,
@@ -575,7 +600,7 @@ void Combat::writeParty() {
 }
 
 void Combat::clearPartyArea() {
-	clearLines(16, 18);
+	clearArea(Common::Rect(0, 15 * LINE_H, 320, 18 * LINE_H));
 }
 
 void Combat::writeDefeat() {
diff --git a/engines/mm/mm1/views_enh/combat.h b/engines/mm/mm1/views_enh/combat.h
index 445c42f64c5..727e0f60526 100644
--- a/engines/mm/mm1/views_enh/combat.h
+++ b/engines/mm/mm1/views_enh/combat.h
@@ -57,6 +57,10 @@ private:
 	void writeAttackOptions();
 	void writeCastOption();
 	void writeShootOption();
+
+	void clearSurface();
+	void clearBottom();
+	void clearArea(const Common::Rect &r);
 	void resetBottom();
 
 	/**
diff --git a/engines/mm/mm1/views_enh/scroll_view.cpp b/engines/mm/mm1/views_enh/scroll_view.cpp
index 60ebd15f771..bec4e037e36 100644
--- a/engines/mm/mm1/views_enh/scroll_view.cpp
+++ b/engines/mm/mm1/views_enh/scroll_view.cpp
@@ -82,6 +82,11 @@ void ScrollView::resetSelectedButton() {
 void ScrollView::draw() {
 	frame();
 	fill();
+
+	drawButtons();
+}
+
+void ScrollView::drawButtons() {
 	setTextColor(0);
 
 	Graphics::ManagedSurface s = getSurface();
diff --git a/engines/mm/mm1/views_enh/scroll_view.h b/engines/mm/mm1/views_enh/scroll_view.h
index eefc8cbd365..6bfc0054a1d 100644
--- a/engines/mm/mm1/views_enh/scroll_view.h
+++ b/engines/mm/mm1/views_enh/scroll_view.h
@@ -99,6 +99,12 @@ protected:
 	size_t getButtonCount() const {
 		return _buttons.size();
 	}
+
+	/**
+	 * Draws the buttons
+	 */
+	void drawButtons();
+
 public:
 	ScrollView(const Common::String &name);
 	ScrollView(const Common::String &name, UIElement *owner);


Commit: 8b91aa90e1e8bc58bfacca26b7e0882ef9c436c0
    https://github.com/scummvm/scummvm/commit/8b91aa90e1e8bc58bfacca26b7e0882ef9c436c0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2023-03-25T22:21:39-07:00

Commit Message:
MM: MM1: Adding combat options display

Changed paths:
    devtools/create_mm/files/mm1/strings_en.yml
    engines/mm/mm1/globals.cpp
    engines/mm/mm1/globals.h
    engines/mm/mm1/views_enh/combat.cpp
    engines/mm/mm1/views_enh/combat.h
    engines/mm/mm1/views_enh/select_number.cpp
    engines/mm/mm1/views_enh/select_number.h


diff --git a/devtools/create_mm/files/mm1/strings_en.yml b/devtools/create_mm/files/mm1/strings_en.yml
index 9b525c735b1..05711deb37b 100644
--- a/devtools/create_mm/files/mm1/strings_en.yml
+++ b/devtools/create_mm/files/mm1/strings_en.yml
@@ -513,6 +513,15 @@ enhdialogs:
 		title: "Select target"
 	characters:
 		left_click: "Left click portraits to view"
+	combat:
+		attack: "\x01""37Attack(A)"
+		cast: "\x01""37Cast"
+		fight: "\x01""37Fight(+)"
+		shoot: "\x01""37Shoot"
+		exchange: "\x01""37Exchange"
+		use: "\x01""37Use"
+		retreat: "\x01""37Retreat"
+		block: "\x01""37Block"
 	create_characters:
 		intellect: "Intellect ="
 		might: "Might ="
diff --git a/engines/mm/mm1/globals.cpp b/engines/mm/mm1/globals.cpp
index 4cdbbf9e4a3..198fb6d3ef6 100644
--- a/engines/mm/mm1/globals.cpp
+++ b/engines/mm/mm1/globals.cpp
@@ -41,6 +41,17 @@ Globals::~Globals() {
 	g_globals = nullptr;
 }
 
+void Globals::createBlankButton() {
+	// Get the Escape glyph we'll use as a base
+	Shared::Xeen::SpriteResource escSprite;
+	escSprite.load("esc.icn");
+	_blankButton.create(20, 20);
+	_blankButton.clear(255);
+	_blankButton.setTransparentColor(255);
+	escSprite.draw(&_blankButton, 0, Common::Point(0, 0));
+	_blankButton.fillRect(Common::Rect(2, 2, 18, 18), 0x9f);
+}
+
 bool Globals::load(bool isEnhanced) {
 	// Initialise engine data for the game
 	Common::U32String errMsg;
@@ -68,6 +79,8 @@ bool Globals::load(bool isEnhanced) {
 		_tileSprites.load("town.til");
 		_escSprites.load("esc.icn");
 
+		createBlankButton();
+
 		{
 			Common::File f;
 			if (!f.open("symbols.bin"))
diff --git a/engines/mm/mm1/globals.h b/engines/mm/mm1/globals.h
index 788e1da025e..a32db31598d 100644
--- a/engines/mm/mm1/globals.h
+++ b/engines/mm/mm1/globals.h
@@ -64,6 +64,11 @@ public:
 	bool _encountersOn = true;
 	bool _allSpells = false;
 
+	/**
+	 * Creates a blank button with no inner glyph
+	 */
+	void createBlankButton();
+
 public:
 	// Enhanced mode globals
 	Shared::Xeen::SpriteResource _mainIcons;
@@ -71,6 +76,7 @@ public:
 	Shared::Xeen::SpriteResource _globalSprites;
 	Shared::Xeen::SpriteResource _tileSprites;
 	Shared::Xeen::SpriteResource _escSprites;
+	Graphics::ManagedSurface _blankButton;
 	byte SYMBOLS[20][64];
 	XeenFont _fontNormal;
 	XeenFont _fontReduced;
diff --git a/engines/mm/mm1/views_enh/combat.cpp b/engines/mm/mm1/views_enh/combat.cpp
index bfab55cfb32..153ecbb1ead 100644
--- a/engines/mm/mm1/views_enh/combat.cpp
+++ b/engines/mm/mm1/views_enh/combat.cpp
@@ -160,7 +160,6 @@ void Combat::draw() {
 	writePartyNumbers();
 	writeMonsters();
 	writeParty();
-	return; //***DEBUG***
 
 	switch (_mode) {
 	case SELECT_OPTION:
@@ -377,11 +376,11 @@ void Combat::writeAllOptions() {
 	assert(g_globals->_currCharacter &&
 		g_globals->_currCharacter == g_globals->_combatParty[_currentChar]);
 	const Character &c = *g_globals->_currCharacter;
-	writeString(0, 20, STRING["dialogs.combat.options_for"]);
-	writeString(0, 22, c._name);
+	writeBottomText(0, 0, STRING["dialogs.combat.options_for"]);
+	writeBottomText(0, 2, c._name);
 
 	// Highlight the currently active character
-	writeChar(3 + 4 * (_currentChar % 2), 3 + (_currentChar / 2),
+	writeChar((2 + 4 * (_currentChar % 2)) * 8 + 8, (3 + (_currentChar / 2)) * LINE_H,
 		(unsigned char)'1' + _currentChar + 0x80);
 
 	bool testShoot;
@@ -405,8 +404,10 @@ void Combat::writeAllOptions() {
 		_allowCast = true;
 	}
 
-	writeString(16, 22, STRING["dialogs.combat.exchange_use"]);
-	writeString(16, 23, STRING["dialogs.combat.retreat_block"]);
+	writeOption(0, 2, STRING["enhdialogs.combat.exchange"]);
+	writeOption(1, 2, STRING["enhdialogs.combat.use"]);
+	writeOption(0, 3, STRING["enhdialogs.combat.retreat"]);
+	writeOption(1, 3, STRING["enhdialogs.combat.block"]);
 }
 
 void Combat::writeDelaySelect() {
@@ -443,16 +444,16 @@ void Combat::writeShootSelect() {
 }
 
 void Combat::writeAttackOptions() {
-	writeString(16, 20, STRING["dialogs.combat.attack"]);
-	writeString(16, 21, STRING["dialogs.combat.fight"]);
+	writeOption(0, 0, STRING["dialogs.combat.attack"]);
+	writeOption(0, 1, STRING["dialogs.combat.fight"]);
 }
 
 void Combat::writeCastOption() {
-	writeString(30, 21, STRING["dialogs.combat.cast"]);
+	writeOption(1, 1, STRING["dialogs.combat.cast"]);
 }
 
 void Combat::writeShootOption() {
-	writeString(30, 20, STRING["dialogs.combat.shoot"]);
+	writeString(1, 0, STRING["dialogs.combat.shoot"]);
 }
 
 void Combat::clearSurface() {
@@ -477,17 +478,39 @@ void Combat::clearArea(const Common::Rect &r) {
 	Common::Rect area = r;
 	area.translate(_innerBounds.left, _innerBounds.top);
 	area.right = MIN(area.right, _innerBounds.right);
+	area.bottom = MIN(area.bottom, _innerBounds.bottom);
 
 	s.fillRect(area, 0x99);
 }
 
 
 void Combat::resetBottom() {
-	clearBottom();
+	clearArea(Common::Rect(0, BOTTOM_Y, 320, 200));
 	_allowFight = _allowShoot = false;
 	_allowCast = _allowAttack = false;
 }
 
+void Combat::writeBottomText(int x, int line, const Common::String &msg) {
+	writeString(x, (line + 19) * LINE_H, msg);
+}
+
+void Combat::writeOption(uint col, uint row, const Common::String &msg) {
+	assert(col < 2 && row < 4);
+	int x = col ? 240 : 100;
+	int y = (row + 19) * LINE_H;
+
+	// Create an 8x8 blank button
+	Graphics::ManagedSurface btnSmall(8, 8);
+	btnSmall.blitFrom(g_globals->_blankButton, Common::Rect(0, 0, 20, 20),
+		Common::Rect(0, 0, 8, 8));
+
+	Graphics::ManagedSurface s = getSurface();
+	s.blitFrom(btnSmall, Common::Point(x + _innerBounds.left,
+		y + _innerBounds.top));
+
+	writeBottomText(x + 12, row, msg);
+}
+
 void Combat::writeStaticContent() {
 	setReduced(false);
 	writeString(0, 0, STRING["dialogs.combat.combat"]);
diff --git a/engines/mm/mm1/views_enh/combat.h b/engines/mm/mm1/views_enh/combat.h
index 727e0f60526..d5bf35e5ddb 100644
--- a/engines/mm/mm1/views_enh/combat.h
+++ b/engines/mm/mm1/views_enh/combat.h
@@ -62,6 +62,8 @@ private:
 	void clearBottom();
 	void clearArea(const Common::Rect &r);
 	void resetBottom();
+	void writeBottomText(int x, int line, const Common::String &msg);
+	void writeOption(uint col, uint row, const Common::String &msg);
 
 	/**
 	 * Write the encounter handicap
diff --git a/engines/mm/mm1/views_enh/select_number.cpp b/engines/mm/mm1/views_enh/select_number.cpp
index 40a2f180da6..8070ab518df 100644
--- a/engines/mm/mm1/views_enh/select_number.cpp
+++ b/engines/mm/mm1/views_enh/select_number.cpp
@@ -47,15 +47,6 @@ bool SelectNumber::msgMouseDown(const MouseDownMessage &msg) {
 
 SelectNumberSubview::SelectNumberSubview() : ScrollView("SelectNumberSubview") {
 	_bounds = Common::Rect(234, 144, 320, 200);
-
-	// Get the Escape glyph we'll use as a base
-	Shared::Xeen::SpriteResource escSprite;
-	escSprite.load("esc.icn");
-	_button.create(20, 20);
-	_button.clear(255);
-	_button.setTransparentColor(255);
-	escSprite.draw(&_button, 0, Common::Point(0, 0));
-	_button.fillRect(Common::Rect(2, 2, 18, 18), 0x9f);
 }
 
 void SelectNumberSubview::open(int maxNum, SelectNumberProc callback) {
@@ -80,7 +71,7 @@ void SelectNumberSubview::draw() {
 
 	for (int i = 0; i < _maxNumber; ++i) {
 		
-		s.blitFrom(_button, Common::Point((i % 3) * 22 + 8,
+		s.blitFrom(g_globals->_blankButton, Common::Point((i % 3) * 22 + 8,
 			(i / 3) * 22 + 4));
 		writeString((i % 3) * 22 + 10, (i / 3) * 22 + 2,
 			Common::String::format("%d", i + 1), ALIGN_MIDDLE);
diff --git a/engines/mm/mm1/views_enh/select_number.h b/engines/mm/mm1/views_enh/select_number.h
index 80299c87a09..fd27b290e79 100644
--- a/engines/mm/mm1/views_enh/select_number.h
+++ b/engines/mm/mm1/views_enh/select_number.h
@@ -34,7 +34,6 @@ typedef void (*SelectNumberProc)(int choiceNum);
 class SelectNumberSubview : public ScrollView {
 private:
 	SelectNumberProc _callback = nullptr;
-	Graphics::ManagedSurface _button;
 	int _maxNumber = 0;
 
 public:


Commit: e8492022ef74b83dee756048d20f95c007e6c041
    https://github.com/scummvm/scummvm/commit/e8492022ef74b83dee756048d20f95c007e6c041
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2023-03-25T22:21:39-07:00

Commit Message:
MM: MM1: Camel case the monster list

Changed paths:
    devtools/create_mm/files/mm1/monsters.txt


diff --git a/devtools/create_mm/files/mm1/monsters.txt b/devtools/create_mm/files/mm1/monsters.txt
index f4765d782fd..3758ee13347 100644
--- a/devtools/create_mm/files/mm1/monsters.txt
+++ b/devtools/create_mm/files/mm1/monsters.txt
@@ -1,195 +1,195 @@
-"FLESH EATER    ", 6, 0, 2, 2, 6, 1, 7, 50, 0, 0, 0, 130, 0, 0, 16, 4
-"BATTLE RAT     ", 10, 1, 1, 3, 3, 1, 12, 50, 2, 0, 0, 130, 0, 0, 0, 6
-"SLITHER BEAST  ", 6, 0, 2, 4, 8, 1, 10, 125, 0, 0, 0, 0, 0, 0, 0, 35
-"GNOME          ", 6, 50, 3, 5, 6, 1, 12, 125, 2, 20, 1, 0, 132, 0, 6, 8
-"GOBLIN         ", 12, 0, 1, 4, 6, 1, 10, 50, 2, 0, 0, 0, 131, 0, 4, 15
-"GREMLIN        ", 6, 1, 1, 3, 3, 2, 4, 125, 10, 0, 4, 129, 0, 0, 0, 10
-"GUARDSMAN      ", 6, 10, 0, 2, 6, 1, 14, 75, 2, 0, 0, 0, 134, 0, 150, 55
-"KOBOLD         ", 10, 1, 1, 4, 4, 1, 6, 50, 2, 0, 0, 0, 131, 0, 4, 5
-"MUTANT LARVA   ", 6, 0, 0, 0, 3, 1, 2, 50, 0, 0, 7, 130, 0, 0, 0, 20
-"ORC            ", 12, 5, 2, 4, 6, 1, 11, 75, 10, 0, 0, 0, 134, 0, 22, 14
-"POLTERGEIST    ", 6, 0, 1, 0, 2, 2, 16, 150, 0, 128, 7, 131, 0, 0, 160, 60
-"RABID JACKAL   ", 6, 0, 0, 3, 2, 1, 15, 50, 0, 0, 0, 130, 0, 0, 16, 29
-"SKELETON       ", 12, 0, 1, 3, 6, 1, 9, 50, 2, 128, 7, 0, 0, 0, 160, 63
-"SNAKE          ", 6, 0, 0, 2, 3, 1, 17, 125, 0, 0, 0, 132, 0, 0, 16, 35
-"SPRITE         ", 8, 60, 0, 10, 2, 1, 20, 250, 11, 30, 1, 133, 1, 50, 8, 9
-"VAMPIRE BAT    ", 8, 0, 0, 2, 3, 1, 14, 125, 0, 0, 0, 134, 0, 0, 16, 24
-"MINOR DEMON    ", 10, 0, 10, 5, 8, 2, 16, 200, 5, 20, 15, 135, 2, 25, 218, 11
-"DEMON DOG      ", 10, 3, 8, 3, 10, 2, 14, 100, 0, 0, 0, 0, 0, 0, 16, 32
-"DUNG BEETLE    ", 6, 1, 8, 6, 8, 1, 8, 100, 8, 0, 1, 130, 0, 0, 16, 1
-"FIRE ANT       ", 15, 0, 5, 5, 6, 1, 7, 100, 26, 0, 67, 0, 3, 10, 20, 0
-"GHOUL          ", 6, 0, 8, 4, 5, 3, 13, 200, 5, 128, 7, 136, 0, 0, 16, 58
-"GNOLL          ", 10, 0, 8, 5, 8, 1, 10, 100, 10, 0, 0, 0, 134, 0, 6, 15
-"HAG            ", 2, 0, 3, 1, 4, 2, 8, 100, 1, 0, 0, 138, 4, 20, 20, 12
-"LOCUST PLAGUE  ", 4, 0, 8, 5, 1, 10, 17, 200, 0, 0, 7, 130, 32, 10, 47, 2
-"ORC LEADER     ", 1, 0, 10, 5, 8, 1, 14, 100, 28, 0, 0, 0, 138, 0, 38, 14
-"RABID LEPER    ", 4, 0, 5, 0, 3, 1, 11, 100, 0, 0, 0, 137, 0, 0, 16, 65
-"ROTTING CORPSE ", 6, 0, 8, 2, 4, 2, 3, 100, 0, 128, 7, 137, 0, 0, 16, 65
-"SAVAGE SHREW   ", 4, 5, 4, 3, 5, 3, 13, 150, 0, 0, 0, 0, 0, 0, 0, 32
-"STRANGLING VINE", 10, 0, 1, 3, 3, 4, 6, 100, 40, 0, 3, 134, 0, 0, 51, 47
-"THIEF          ", 8, 0, 6, 3, 8, 1, 16, 100, 20, 0, 0, 139, 134, 0, 4, 49
-"TROGLODYTE     ", 6, 1, 8, 5, 4, 3, 11, 100, 10, 0, 3, 132, 5, 20, 22, 37
-"ZOMBIE         ", 8, 0, 8, 2, 8, 1, 2, 100, 0, 128, 7, 130, 0, 0, 32, 7
-"ACIDIC BLOB    ", 6, 0, 8, 1, 8, 2, 8, 300, 0, 0, 127, 140, 6, 20, 118, 20
-"CENTAUR        ", 12, 60, 20, 4, 4, 4, 12, 200, 27, 0, 3, 0, 7, 20, 20, 18
-"CLERIC         ", 4, 10, 15, 5, 8, 1, 12, 300, 11, 0, 0, 0, 8, 50, 20, 53
-"MINOR DEVIL    ", 10, 0, 15, 4, 4, 2, 15, 250, 61, 20, 15, 136, 2, 30, 234, 11
-"FIRE BEETLE    ", 5, 0, 16, 7, 15, 1, 6, 200, 2, 0, 65, 0, 3, 30, 22, 1
-"GARGOYLE       ", 6, 0, 24, 5, 4, 4, 12, 300, 3, 20, 15, 136, 0, 0, 16, 11
-"GARGANTUAN ANT ", 6, 0, 18, 8, 12, 1, 9, 200, 24, 0, 3, 0, 0, 0, 160, 0
-"DINOLIZARD     ", 6, 0, 16, 5, 10, 1, 11, 200, 0, 0, 3, 0, 0, 0, 16, 36
-"GIANT SPIDER   ", 6, 1, 20, 5, 8, 1, 18, 200, 1, 0, 1, 140, 0, 0, 16, 0
-"HARPY          ", 6, 0, 15, 3, 5, 3, 15, 200, 28, 0, 3, 0, 8, 10, 20, 25
-"HIPPOGRIFF     ", 6, 5, 18, 5, 8, 3, 14, 200, 12, 0, 0, 138, 0, 0, 16, 39
-"KILLER BEES    ", 4, 0, 10, 10, 2, 10, 16, 300, 0, 0, 7, 132, 32, 20, 42, 2
-"PEGASUS        ", 6, 90, 25, 4, 8, 3, 20, 250, 27, 10, 15, 135, 9, 10, 4, 38
-"SHADOW BEAST   ", 6, 0, 20, 3, 5, 1, 18, 200, 0, 0, 15, 141, 0, 0, 32, 60
-"WILD BOAR      ", 6, 5, 15, 3, 12, 1, 14, 200, 0, 0, 0, 0, 0, 0, 16, 32
-"WOLVERINE      ", 3, 0, 10, 5, 5, 3, 12, 250, 10, 0, 1, 0, 0, 0, 16, 29
-"BARBARIAN      ", 10, 5, 50, 8, 12, 2, 15, 400, 12, 20, 1, 0, 140, 0, 170, 23
-"CARYATID GUARD ", 6, 2, 20, 5, 10, 1, 15, 400, 1, 25, 255, 142, 9, 10, 54, 64
-"COCKATRICE     ", 6, 3, 28, 4, 8, 1, 8, 500, 0, 0, 3, 143, 0, 0, 16, 28
-"CYCLOPS        ", 8, 1, 32, 6, 15, 2, 10, 400, 28, 0, 1, 0, 148, 0, 168, 22
-"DRUID          ", 4, 2, 24, 4, 8, 2, 14, 400, 3, 0, 1, 138, 7, 50, 22, 53
-"RHINO BEETLE   ", 4, 0, 25, 7, 20, 1, 7, 500, 24, 0, 3, 0, 6, 30, 35, 3
-"GIANT CENTIPEDE", 4, 0, 15, 5, 4, 8, 9, 500, 2, 0, 3, 136, 0, 0, 32, 1
-"MAGICIAN       ", 3, 1, 25, 5, 8, 1, 15, 600, 29, 0, 1, 0, 10, 90, 24, 52
-"MILITIAMAN     ", 6, 10, 30, 9, 10, 2, 9, 300, 2, 0, 1, 0, 138, 0, 150, 50
-"ORC CHIEFTAIN  ", 1, 0, 60, 10, 12, 2, 15, 500, 28, 0, 1, 136, 140, 0, 170, 14
-"OGRE           ", 6, 0, 45, 7, 10, 2, 12, 350, 12, 0, 1, 0, 140, 0, 170, 19
-"SATYR          ", 5, 50, 28, 5, 8, 2, 10, 300, 26, 0, 15, 135, 8, 40, 24, 18
-"SWARMING WASPS ", 4, 0, 20, 4, 2, 10, 17, 400, 0, 0, 7, 132, 32, 25, 47, 2
-"UNICORN        ", 4, 90, 35, 8, 10, 3, 22, 500, 7, 20, 127, 141, 9, 20, 69, 38
-"WEREWOLF       ", 4, 10, 30, 7, 8, 2, 14, 400, 0, 0, 7, 137, 0, 0, 144, 30
-"WIGHT          ", 6, 0, 20, 6, 10, 1, 12, 500, 0, 128, 7, 142, 0, 0, 160, 60
-"BARBARIAN CHIEF", 1, 0, 80, 10, 12, 3, 18, 800, 28, 0, 3, 0, 143, 0, 184, 23
-"BASILISK       ", 4, 2, 30, 5, 15, 1, 14, 1000, 0, 0, 3, 143, 11, 30, 163, 45
-"CELESTIAL STAG ", 2, 1, 50, 14, 10, 3, 19, 700, 34, 0, 3, 0, 0, 0, 32, 39
-"DUST DEMON     ", 3, 0, 30, 9, 12, 3, 15, 600, 1, 0, 15, 7, 7, 20, 154, 34
-"GIANT SCORPION ", 4, 0, 30, 7, 8, 3, 13, 600, 0, 0, 3, 12, 0, 0, 32, 0
-"5 HEADED HYDRA ", 1, 0, 80, 7, 8, 5, 12, 1500, 60, 0, 3, 0, 14, 40, 160, 44
-"WARRIOR CAT    ", 4, 5, 40, 6, 6, 4, 17, 600, 0, 0, 3, 0, 0, 0, 16, 33
-"MINOTAUR       ", 2, 0, 55, 7, 35, 1, 15, 1500, 60, 20, 143, 144, 0, 0, 240, 40
-"OGRE CHIEF     ", 1, 0, 64, 9, 15, 2, 15, 750, 28, 0, 131, 0, 148, 0, 160, 19
-"PANTHRO MIST   ", 6, 5, 40, 7, 8, 4, 18, 600, 0, 0, 3, 0, 0, 0, 16, 33
-"PHANTOM        ", 6, 0, 35, 7, 8, 2, 10, 600, 0, 0, 3, 145, 0, 0, 16, 63
-"SWORDSMAN      ", 6, 5, 40, 6, 10, 2, 18, 600, 20, 0, 3, 0, 143, 0, 166, 55
-"TROLL          ", 6, 0, 40, 6, 9, 3, 12, 600, 12, 0, 131, 0, 0, 0, 224, 17
-"WOOD GOLEM     ", 3, 0, 30, 5, 15, 2, 5, 800, 1, 0, 191, 0, 0, 0, 176, 16
-"WRAITH         ", 6, 0, 35, 6, 6, 2, 9, 800, 0, 0, 135, 14, 0, 0, 176, 60
-"YETI           ", 6, 5, 50, 4, 10, 2, 13, 600, 10, 0, 3, 0, 148, 0, 24, 31
-"DEADLY SPORES  ", 15, 0, 10, 2, 1, 1, 10, 600, 0, 0, 3, 4, 12, 90, 54, 48
-"ENCHANTRESS    ", 2, 1, 30, 6, 6, 2, 15, 1000, 37, 0, 3, 136, 13, 80, 26, 54
-"FIRE LIZARD    ", 4, 1, 40, 7, 10, 3, 12, 800, 0, 0, 67, 0, 3, 20, 166, 36
-"GIANT SLOTH    ", 3, 70, 40, 5, 8, 4, 14, 750, 8, 0, 19, 0, 0, 0, 0, 31
-"GRIFFIN        ", 8, 10, 45, 7, 8, 3, 14, 700, 28, 0, 3, 143, 0, 0, 16, 28
-"PYRO HYDRA     ", 1, 0, 60, 7, 8, 5, 12, 2000, 96, 0, 195, 0, 14, 50, 164, 44
-"MAN EATING MARE", 4, 0, 42, 6, 8, 3, 14, 600, 52, 0, 3, 0, 0, 0, 32, 39
-"MANTICORE      ", 4, 1, 40, 6, 6, 4, 12, 600, 28, 0, 3, 0, 3, 20, 42, 26
-"MEDUSA         ", 2, 1, 32, 5, 4, 1, 9, 1000, 0, 0, 135, 143, 15, 20, 36, 12
-"RAKSHASHA      ", 4, 5, 40, 14, 5, 3, 14, 3000, 255, 50, 255, 142, 13, 80, 31, 11
-"STONE GOLEM    ", 3, 0, 50, 7, 40, 1, 6, 1500, 1, 20, 255, 0, 0, 0, 48, 16
-"CAVE TROLL     ", 6, 1, 50, 7, 11, 3, 10, 900, 28, 0, 163, 0, 0, 0, 96, 17
-"HILL TROLL     ", 5, 2, 50, 8, 12, 3, 11, 1100, 10, 0, 179, 0, 0, 0, 96, 17
-"WARLOCK        ", 4, 60, 40, 8, 8, 1, 16, 800, 21, 0, 3, 0, 16, 95, 26, 52
-"WEREBEAR       ", 4, 10, 45, 8, 8, 4, 14, 800, 0, 0, 135, 137, 0, 0, 160, 31
-"WICKED WITCH   ", 4, 50, 30, 4, 6, 2, 14, 1000, 3, 0, 3, 151, 10, 40, 26, 12
-"ASSASSIN       ", 4, 0, 45, 6, 8, 1, 19, 2000, 48, 0, 3, 146, 153, 0, 166, 57
-"BANSHEE        ", 2, 1, 40, 10, 10, 1, 12, 3000, 0, 128, 135, 145, 8, 40, 52, 62
-"CAVE GIANT     ", 6, 5, 50, 10, 16, 3, 12, 2000, 60, 0, 3, 0, 158, 0, 42, 17
-"CHIMERA        ", 4, 1, 60, 8, 5, 6, 14, 5000, 28, 0, 127, 0, 14, 40, 35, 26
-"AIR ELEMENTAL  ", 1, 5, 70, 7, 15, 1, 20, 4000, 0, 20, 175, 147, 17, 30, 180, 27
-"EXECUTIONER    ", 1, 0, 60, 8, 12, 2, 14, 4000, 28, 0, 3, 146, 0, 0, 160, 57
-"GORGON         ", 4, 5, 55, 8, 12, 1, 12, 6000, 0, 0, 3, 143, 11, 40, 35, 45
-"LESSER DEMON   ", 4, 0, 40, 10, 8, 4, 16, 2500, 125, 20, 255, 145, 9, 15, 244, 59
-"LESSER DEVIL   ", 4, 0, 40, 8, 6, 5, 16, 2500, 125, 20, 255, 145, 9, 25, 244, 59
-"MUMMY          ", 6, 0, 50, 7, 20, 2, 7, 2000, 96, 128, 191, 9, 0, 0, 48, 61
-"NECROMANCER    ", 4, 1, 35, 7, 8, 2, 17, 2000, 63, 40, 3, 0, 18, 95, 42, 54
-"SPECTER        ", 6, 0, 47, 8, 12, 1, 12, 3000, 0, 128, 143, 17, 0, 0, 48, 58
-"WHITE WOLF     ", 6, 0, 42, 10, 12, 3, 14, 2500, 4, 0, 19, 9, 27, 30, 50, 29
-"WYVERN         ", 6, 5, 45, 7, 18, 2, 12, 2000, 38, 0, 3, 149, 0, 0, 32, 46
-"GREEN DRAGON   ", 2, 0, 55, 8, 8, 3, 12, 6000, 63, 20, 255, 12, 25, 50, 163, 43
-"BLUE DRAGON    ", 3, 5, 50, 8, 10, 3, 13, 6000, 63, 20, 255, 12, 26, 50, 163, 43
-"EVIL EYE       ", 2, 0, 65, 10, 10, 2, 10, 5000, 103, 20, 255, 143, 21, 60, 38, 21
-"EARTH ELEMENTAL", 1, 5, 80, 8, 20, 1, 18, 4000, 0, 0, 215, 147, 17, 35, 180, 27
-"GHOST          ", 3, 0, 60, 10, 10, 1, 10, 4000, 0, 128, 135, 16, 0, 0, 48, 62
-"FROST GIANT    ", 6, 0, 70, 10, 24, 1, 12, 5000, 62, 0, 147, 0, 148, 0, 166, 23
-"STONE GIANT    ", 6, 2, 80, 10, 10, 4, 12, 4000, 62, 0, 131, 0, 148, 0, 166, 19
-"8 HEADED HYDRA ", 1, 0, 75, 10, 8, 8, 13, 7500, 116, 0, 131, 0, 14, 35, 162, 44
-"LAVA BEAST     ", 6, 0, 50, 5, 12, 2, 9, 4000, 0, 0, 231, 0, 14, 20, 35, 20
-"MANTIS WARRIOR ", 3, 0, 70, 8, 12, 4, 16, 4000, 68, 0, 131, 12, 0, 0, 160, 4
-"NAGA           ", 3, 0, 65, 8, 8, 1, 15, 4000, 60, 25, 131, 136, 8, 40, 22, 35
-"DINOBEETLE     ", 4, 0, 200, 10, 50, 1, 8, 6000, 28, 0, 131, 0, 0, 0, 160, 3
-"SPHINX         ", 2, 50, 60, 11, 10, 3, 18, 5000, 63, 40, 255, 7, 8, 40, 22, 34
-"VAMPIRE        ", 4, 0, 55, 9, 12, 2, 14, 5000, 61, 138, 135, 145, 13, 50, 246, 59
-"WARRIOR        ", 4, 1, 75, 12, 12, 2, 14, 4000, 38, 0, 131, 0, 148, 0, 168, 50
-"WIZARD         ", 2, 1, 60, 8, 6, 2, 18, 7000, 39, 0, 139, 0, 19, 95, 42, 52
-"WHITE DRAGON   ", 3, 0, 65, 8, 12, 3, 15, 10000, 127, 30, 255, 0, 27, 60, 163, 42
-"GRAY DRAGON    ", 3, 2, 70, 8, 15, 3, 16, 10000, 127, 30, 255, 0, 28, 60, 163, 42
-"ARCH DRUID     ", 1, 5, 65, 10, 8, 2, 18, 15000, 29, 0, 255, 151, 20, 90, 34, 53
-"CHAOTIC KNIGHT ", 2, 0, 90, 14, 15, 3, 18, 7000, 134, 20, 135, 148, 158, 0, 250, 61
-"GREATER DEMON  ", 2, 0, 60, 15, 8, 7, 19, 10000, 127, 30, 255, 21, 13, 25, 250, 13
-"GREATER DEVIL  ", 2, 0, 65, 12, 15, 4, 19, 10000, 127, 30, 255, 21, 13, 35, 250, 13
-"FIRE ELEMENTAL ", 1, 5, 90, 9, 30, 1, 20, 8000, 0, 0, 199, 147, 17, 40, 180, 27
-"GUARDIAN SPIRIT", 2, 0, 60, 8, 6, 6, 16, 6000, 0, 128, 135, 17, 0, 0, 48, 64
-"STORM GIANT    ", 4, 1, 100, 9, 30, 2, 14, 10000, 198, 0, 167, 0, 19, 40, 38, 23
-"12 HEADED HYDRA", 1, 0, 70, 10, 10, 12, 16, 12000, 127, 0, 131, 0, 14, 25, 162, 44
-"INVISIBLE THING", 4, 2, 50, 14, 10, 3, 25, 6000, 0, 0, 255, 22, 0, 0, 32, 58
-"MAGE           ", 2, 1, 60, 10, 6, 3, 20, 8000, 39, 20, 143, 0, 21, 95, 42, 52
-"MASTER THIEF   ", 2, 1, 65, 12, 8, 2, 20, 5000, 62, 0, 131, 23, 148, 0, 42, 49
-"STEEL GOLEM    ", 2, 0, 70, 15, 25, 2, 10, 7500, 129, 30, 255, 0, 0, 0, 176, 61
-"WEREPHASE MUMMY", 4, 1, 70, 20, 20, 2, 35, 8000, 1, 50, 255, 9, 0, 0, 240, 61
-"BLACK DRAGON   ", 2, 0, 75, 12, 18, 3, 16, 15000, 127, 30, 255, 135, 29, 70, 163, 41
-"RED DRAGON     ", 2, 2, 80, 12, 20, 3, 15, 15000, 127, 30, 255, 141, 30, 70, 163, 41
-"XX!XX!XX!XX!XX ", 2, 0, 10, 20, 1, 1, 18, 15000, 0, 50, 255, 151, 0, 0, 0, 9
-"BLACK KNIGHT   ", 1, 0, 150, 16, 50, 3, 20, 10000, 134, 30, 255, 14, 168, 0, 246, 56
-"DEMON LORD     ", 1, 0, 150, 20, 50, 2, 30, 60000, 255, 50, 255, 24, 23, 20, 246, 13
-"ARCH DEVIL     ", 1, 0, 200, 16, 100, 1, 30, 60000, 255, 50, 255, 24, 23, 30, 246, 13
-"GOLD DRAGON    ", 1, 10, 150, 10, 20, 5, 16, 50000, 255, 40, 255, 136, 31, 80, 180, 41
-"SILVER DRAGON  ", 2, 0, 90, 8, 16, 4, 16, 20000, 255, 40, 255, 136, 31, 80, 180, 41
-"DIAMOND GOLEM  ", 2, 0, 100, 15, 60, 3, 12, 15000, 1, 40, 255, 0, 0, 0, 48, 16
-"16 HEADED HYDRA", 1, 0, 100, 15, 12, 16, 12, 20000, 255, 20, 255, 0, 29, 25, 246, 44
-"HIGH CLERIC    ", 1, 5, 100, 14, 16, 3, 18, 10000, 127, 20, 131, 0, 22, 80, 36, 54
-"KIRIN          ", 1, 50, 90, 15, 40, 4, 22, 14000, 135, 30, 255, 25, 9, 25, 42, 26
-"LICH           ", 1, 0, 80, 10, 10, 2, 20, 20000, 135, 218, 255, 17, 23, 90, 54, 65
-"ARCH MAGE      ", 1, 0, 70, 12, 8, 2, 25, 25000, 63, 30, 255, 0, 24, 95, 42, 52
-"MASTER ARCHER  ", 1, 5, 120, 10, 16, 8, 18, 25000, 199, 20, 255, 150, 250, 0, 47, 51
-"PHOENIX        ", 1, 50, 150, 13, 8, 3, 24, 15000, 129, 10, 255, 144, 14, 60, 42, 27
-"ROC            ", 2, 20, 130, 10, 50, 3, 14, 15000, 0, 0, 255, 0, 0, 0, 32, 39
-"SAND WORM      ", 3, 1, 200, 7, 200, 1, 8, 15000, 129, 0, 143, 146, 0, 0, 176, 35
-"TITAN          ", 1, 50, 180, 13, 60, 2, 30, 20000, 255, 95, 255, 0, 250, 0, 122, 36
-"ALGAE BEAST    ", 15, 0, 1, 0, 6, 1, 1, 50, 0, 0, 7, 130, 0, 0, 16, 20
-"WATER RAT      ", 15, 0, 3, 1, 6, 1, 6, 100, 0, 0, 6, 130, 0, 0, 16, 6
-"LAMPREY        ", 10, 0, 10, 2, 8, 1, 15, 200, 0, 0, 7, 131, 0, 0, 32, 35
-"GIANT LEECH    ", 6, 0, 10, 2, 8, 1, 3, 250, 0, 0, 7, 132, 0, 0, 32, 75
-"CROCODILE      ", 8, 0, 30, 5, 10, 2, 12, 300, 0, 0, 6, 0, 0, 0, 160, 75
-"GIANT CRAB     ", 6, 0, 25, 9, 10, 2, 12, 300, 0, 0, 7, 0, 0, 0, 32, 0
-"BARRACUDA      ", 15, 0, 20, 5, 20, 1, 16, 350, 0, 0, 7, 0, 0, 0, 48, 75
-"GIANT SQUID    ", 4, 0, 30, 5, 6, 8, 14, 400, 0, 0, 7, 136, 6, 20, 38, 75
-"ELECTRIC EEL   ", 10, 0, 30, 5, 8, 1, 15, 500, 0, 0, 47, 136, 10, 20, 47, 75
-"SEA HAG        ", 6, 0, 40, 8, 6, 3, 12, 500, 0, 20, 15, 12, 15, 30, 102, 12
-"HIPPOCAMPUS    ", 8, 0, 50, 12, 10, 4, 18, 600, 0, 20, 15, 7, 0, 0, 224, 38
-"SHARK          ", 15, 0, 40, 6, 30, 2, 24, 700, 0, 0, 15, 0, 0, 0, 176, 75
-"SIREN          ", 8, 0, 30, 8, 8, 2, 13, 700, 0, 20, 255, 143, 7, 20, 102, 64
-"WATER ELEMENTAL", 6, 0, 80, 12, 50, 1, 30, 1200, 0, 20, 255, 0, 17, 50, 247, 9
-"SEA SERPENT    ", 3, 32, 100, 10, 100, 1, 20, 3000, 0, 40, 143, 146, 0, 0, 240, 42
-"SEA DRAGON     ", 3, 32, 150, 15, 50, 4, 32, 20000, 0, 50, 255, 8, 31, 50, 243, 42
-"SCORPION       ", 1, 0, 210, 12, 60, 2, 20, 12000, 0, 50, 207, 12, 0, 0, 240, 1
-"DARK RIDER     ", 1, 0, 210, 15, 50, 4, 30, 12000, 0, 90, 127, 17, 19, 20, 255, 56
-"WINGED BEAST   ", 1, 0, 210, 12, 120, 1, 30, 12000, 0, 50, 159, 8, 0, 0, 240, 46
-"GREAT SEA BEAST", 1, 0, 210, 12, 100, 1, 30, 12000, 0, 50, 143, 147, 0, 0, 240, 75
-"DEMON KING     ", 1, 0, 240, 30, 50, 5, 35, 50000, 255, 120, 255, 24, 23, 30, 255, 73
-"SUCCUBUS QUEEN ", 1, 0, 150, 20, 30, 3, 20, 10000, 127, 100, 239, 147, 21, 50, 255, 74
-"TYRANNOSAURUS  ", 3, 0, 240, 10, 200, 1, 12, 5000, 6, 0, 7, 147, 0, 0, 160, 45
-"ALIEN          ", 6, 16, 100, 15, 20, 2, 15, 1000, 1, 40, 7, 149, 24, 30, 35, 4
-"NATIVES        ", 15, 21, 40, 6, 10, 2, 10, 200, 3, 0, 3, 132, 32, 20, 163, 7
-"VOLCANO GOD    ", 1, 0, 220, 30, 40, 6, 32, 60000, 255, 120, 255, 24, 13, 50, 255, 20
-"PAUL PEAD      ", 1, 0, 100, 10, 30, 1, 19, 2000, 61, 50, 143, 14, 13, 40, 243, 50
-"PIRATE         ", 15, 0, 40, 8, 20, 1, 17, 500, 7, 10, 135, 138, 0, 0, 176, 58
-"PIRATE CAPTAIN ", 1, 0, 80, 10, 20, 3, 18, 1000, 15, 30, 135, 11, 7, 20, 51, 58
-"GRAY MINOTAUR  ", 1, 0, 150, 13, 30, 4, 20, 15000, 63, 40, 143, 7, 10, 30, 255, 40
-"LORD ARCHER    ", 1, 0, 32, 15, 80, 3, 21, 20000, 63, 100, 207, 6, 250, 0, 255, 51
-"BRONTASAURUS   ", 3, 16, 200, 8, 150, 1, 6, 5000, 6, 0, 7, 147, 0, 0, 160, 45
-"STEGOSAURUS    ", 3, 5, 200, 15, 200, 1, 6, 5000, 6, 0, 7, 147, 0, 0, 160, 45
-"KILLER CADAVER ", 3, 1, 50, 8, 12, 3, 15, 1500, 255, 0, 1, 9, 0, 0, 240, 65
-"OKRIM          ", 2, 1, 80, 11, 6, 4, 18, 20000, 39, 0, 139, 0, 19, 95, 42, 52
+"Flesh Eater    ", 6, 0, 2, 2, 6, 1, 7, 50, 0, 0, 0, 130, 0, 0, 16, 4
+"Battle Rat     ", 10, 1, 1, 3, 3, 1, 12, 50, 2, 0, 0, 130, 0, 0, 0, 6
+"Slither Beast  ", 6, 0, 2, 4, 8, 1, 10, 125, 0, 0, 0, 0, 0, 0, 0, 35
+"Gnome          ", 6, 50, 3, 5, 6, 1, 12, 125, 2, 20, 1, 0, 132, 0, 6, 8
+"Goblin         ", 12, 0, 1, 4, 6, 1, 10, 50, 2, 0, 0, 0, 131, 0, 4, 15
+"Gremlin        ", 6, 1, 1, 3, 3, 2, 4, 125, 10, 0, 4, 129, 0, 0, 0, 10
+"Guardsman      ", 6, 10, 0, 2, 6, 1, 14, 75, 2, 0, 0, 0, 134, 0, 150, 55
+"Kobold         ", 10, 1, 1, 4, 4, 1, 6, 50, 2, 0, 0, 0, 131, 0, 4, 5
+"Mutant Larva   ", 6, 0, 0, 0, 3, 1, 2, 50, 0, 0, 7, 130, 0, 0, 0, 20
+"Orc            ", 12, 5, 2, 4, 6, 1, 11, 75, 10, 0, 0, 0, 134, 0, 22, 14
+"Poltergeist    ", 6, 0, 1, 0, 2, 2, 16, 150, 0, 128, 7, 131, 0, 0, 160, 60
+"Rabid Jackal   ", 6, 0, 0, 3, 2, 1, 15, 50, 0, 0, 0, 130, 0, 0, 16, 29
+"Skeleton       ", 12, 0, 1, 3, 6, 1, 9, 50, 2, 128, 7, 0, 0, 0, 160, 63
+"Snake          ", 6, 0, 0, 2, 3, 1, 17, 125, 0, 0, 0, 132, 0, 0, 16, 35
+"Sprite         ", 8, 60, 0, 10, 2, 1, 20, 250, 11, 30, 1, 133, 1, 50, 8, 9
+"Vampire Bat    ", 8, 0, 0, 2, 3, 1, 14, 125, 0, 0, 0, 134, 0, 0, 16, 24
+"Minor Demon    ", 10, 0, 10, 5, 8, 2, 16, 200, 5, 20, 15, 135, 2, 25, 218, 11
+"Demon Dog      ", 10, 3, 8, 3, 10, 2, 14, 100, 0, 0, 0, 0, 0, 0, 16, 32
+"Dung Beetle    ", 6, 1, 8, 6, 8, 1, 8, 100, 8, 0, 1, 130, 0, 0, 16, 1
+"Fire Ant       ", 15, 0, 5, 5, 6, 1, 7, 100, 26, 0, 67, 0, 3, 10, 20, 0
+"Ghoul          ", 6, 0, 8, 4, 5, 3, 13, 200, 5, 128, 7, 136, 0, 0, 16, 58
+"Gnoll          ", 10, 0, 8, 5, 8, 1, 10, 100, 10, 0, 0, 0, 134, 0, 6, 15
+"Hag            ", 2, 0, 3, 1, 4, 2, 8, 100, 1, 0, 0, 138, 4, 20, 20, 12
+"Locust Plague  ", 4, 0, 8, 5, 1, 10, 17, 200, 0, 0, 7, 130, 32, 10, 47, 2
+"Orc Leader     ", 1, 0, 10, 5, 8, 1, 14, 100, 28, 0, 0, 0, 138, 0, 38, 14
+"Rabid Leper    ", 4, 0, 5, 0, 3, 1, 11, 100, 0, 0, 0, 137, 0, 0, 16, 65
+"Rotting Corpse ", 6, 0, 8, 2, 4, 2, 3, 100, 0, 128, 7, 137, 0, 0, 16, 65
+"Savage Shrew   ", 4, 5, 4, 3, 5, 3, 13, 150, 0, 0, 0, 0, 0, 0, 0, 32
+"Strangling Vine", 10, 0, 1, 3, 3, 4, 6, 100, 40, 0, 3, 134, 0, 0, 51, 47
+"Thief          ", 8, 0, 6, 3, 8, 1, 16, 100, 20, 0, 0, 139, 134, 0, 4, 49
+"Troglodyte     ", 6, 1, 8, 5, 4, 3, 11, 100, 10, 0, 3, 132, 5, 20, 22, 37
+"Zombie         ", 8, 0, 8, 2, 8, 1, 2, 100, 0, 128, 7, 130, 0, 0, 32, 7
+"Acidic Blob    ", 6, 0, 8, 1, 8, 2, 8, 300, 0, 0, 127, 140, 6, 20, 118, 20
+"Centaur        ", 12, 60, 20, 4, 4, 4, 12, 200, 27, 0, 3, 0, 7, 20, 20, 18
+"Cleric         ", 4, 10, 15, 5, 8, 1, 12, 300, 11, 0, 0, 0, 8, 50, 20, 53
+"Minor Devil    ", 10, 0, 15, 4, 4, 2, 15, 250, 61, 20, 15, 136, 2, 30, 234, 11
+"Fire Beetle    ", 5, 0, 16, 7, 15, 1, 6, 200, 2, 0, 65, 0, 3, 30, 22, 1
+"Gargoyle       ", 6, 0, 24, 5, 4, 4, 12, 300, 3, 20, 15, 136, 0, 0, 16, 11
+"Gargantuan Ant ", 6, 0, 18, 8, 12, 1, 9, 200, 24, 0, 3, 0, 0, 0, 160, 0
+"Dinolizard     ", 6, 0, 16, 5, 10, 1, 11, 200, 0, 0, 3, 0, 0, 0, 16, 36
+"Giant Spider   ", 6, 1, 20, 5, 8, 1, 18, 200, 1, 0, 1, 140, 0, 0, 16, 0
+"Harpy          ", 6, 0, 15, 3, 5, 3, 15, 200, 28, 0, 3, 0, 8, 10, 20, 25
+"Hippogriff     ", 6, 5, 18, 5, 8, 3, 14, 200, 12, 0, 0, 138, 0, 0, 16, 39
+"Killer Bees    ", 4, 0, 10, 10, 2, 10, 16, 300, 0, 0, 7, 132, 32, 20, 42, 2
+"Pegasus        ", 6, 90, 25, 4, 8, 3, 20, 250, 27, 10, 15, 135, 9, 10, 4, 38
+"Shadow Beast   ", 6, 0, 20, 3, 5, 1, 18, 200, 0, 0, 15, 141, 0, 0, 32, 60
+"Wild Boar      ", 6, 5, 15, 3, 12, 1, 14, 200, 0, 0, 0, 0, 0, 0, 16, 32
+"Wolverine      ", 3, 0, 10, 5, 5, 3, 12, 250, 10, 0, 1, 0, 0, 0, 16, 29
+"Barbarian      ", 10, 5, 50, 8, 12, 2, 15, 400, 12, 20, 1, 0, 140, 0, 170, 23
+"Caryatid Guard ", 6, 2, 20, 5, 10, 1, 15, 400, 1, 25, 255, 142, 9, 10, 54, 64
+"Cockatrice     ", 6, 3, 28, 4, 8, 1, 8, 500, 0, 0, 3, 143, 0, 0, 16, 28
+"Cyclops        ", 8, 1, 32, 6, 15, 2, 10, 400, 28, 0, 1, 0, 148, 0, 168, 22
+"Druid          ", 4, 2, 24, 4, 8, 2, 14, 400, 3, 0, 1, 138, 7, 50, 22, 53
+"Rhino Beetle   ", 4, 0, 25, 7, 20, 1, 7, 500, 24, 0, 3, 0, 6, 30, 35, 3
+"Giant Centipede", 4, 0, 15, 5, 4, 8, 9, 500, 2, 0, 3, 136, 0, 0, 32, 1
+"Magician       ", 3, 1, 25, 5, 8, 1, 15, 600, 29, 0, 1, 0, 10, 90, 24, 52
+"Militiaman     ", 6, 10, 30, 9, 10, 2, 9, 300, 2, 0, 1, 0, 138, 0, 150, 50
+"Orc Chieftain  ", 1, 0, 60, 10, 12, 2, 15, 500, 28, 0, 1, 136, 140, 0, 170, 14
+"Ogre           ", 6, 0, 45, 7, 10, 2, 12, 350, 12, 0, 1, 0, 140, 0, 170, 19
+"Satyr          ", 5, 50, 28, 5, 8, 2, 10, 300, 26, 0, 15, 135, 8, 40, 24, 18
+"Swarming Wasps ", 4, 0, 20, 4, 2, 10, 17, 400, 0, 0, 7, 132, 32, 25, 47, 2
+"Unicorn        ", 4, 90, 35, 8, 10, 3, 22, 500, 7, 20, 127, 141, 9, 20, 69, 38
+"Werewolf       ", 4, 10, 30, 7, 8, 2, 14, 400, 0, 0, 7, 137, 0, 0, 144, 30
+"Wight          ", 6, 0, 20, 6, 10, 1, 12, 500, 0, 128, 7, 142, 0, 0, 160, 60
+"Barbarian Chief", 1, 0, 80, 10, 12, 3, 18, 800, 28, 0, 3, 0, 143, 0, 184, 23
+"Basilisk       ", 4, 2, 30, 5, 15, 1, 14, 1000, 0, 0, 3, 143, 11, 30, 163, 45
+"Celestial Stag ", 2, 1, 50, 14, 10, 3, 19, 700, 34, 0, 3, 0, 0, 0, 32, 39
+"Dust Demon     ", 3, 0, 30, 9, 12, 3, 15, 600, 1, 0, 15, 7, 7, 20, 154, 34
+"Giant Scorpion ", 4, 0, 30, 7, 8, 3, 13, 600, 0, 0, 3, 12, 0, 0, 32, 0
+"5 Headed hydra ", 1, 0, 80, 7, 8, 5, 12, 1500, 60, 0, 3, 0, 14, 40, 160, 44
+"Warrior Cat    ", 4, 5, 40, 6, 6, 4, 17, 600, 0, 0, 3, 0, 0, 0, 16, 33
+"Minotaur       ", 2, 0, 55, 7, 35, 1, 15, 1500, 60, 20, 143, 144, 0, 0, 240, 40
+"Ogre Chief     ", 1, 0, 64, 9, 15, 2, 15, 750, 28, 0, 131, 0, 148, 0, 160, 19
+"Panthro Mist   ", 6, 5, 40, 7, 8, 4, 18, 600, 0, 0, 3, 0, 0, 0, 16, 33
+"Phantom        ", 6, 0, 35, 7, 8, 2, 10, 600, 0, 0, 3, 145, 0, 0, 16, 63
+"Swordsman      ", 6, 5, 40, 6, 10, 2, 18, 600, 20, 0, 3, 0, 143, 0, 166, 55
+"Troll          ", 6, 0, 40, 6, 9, 3, 12, 600, 12, 0, 131, 0, 0, 0, 224, 17
+"Wood Golem     ", 3, 0, 30, 5, 15, 2, 5, 800, 1, 0, 191, 0, 0, 0, 176, 16
+"Wraith         ", 6, 0, 35, 6, 6, 2, 9, 800, 0, 0, 135, 14, 0, 0, 176, 60
+"Yeti           ", 6, 5, 50, 4, 10, 2, 13, 600, 10, 0, 3, 0, 148, 0, 24, 31
+"Deadly Spores  ", 15, 0, 10, 2, 1, 1, 10, 600, 0, 0, 3, 4, 12, 90, 54, 48
+"Enchantress    ", 2, 1, 30, 6, 6, 2, 15, 1000, 37, 0, 3, 136, 13, 80, 26, 54
+"Fire Lizard    ", 4, 1, 40, 7, 10, 3, 12, 800, 0, 0, 67, 0, 3, 20, 166, 36
+"Giant Sloth    ", 3, 70, 40, 5, 8, 4, 14, 750, 8, 0, 19, 0, 0, 0, 0, 31
+"Griffin        ", 8, 10, 45, 7, 8, 3, 14, 700, 28, 0, 3, 143, 0, 0, 16, 28
+"Pyro Hydra     ", 1, 0, 60, 7, 8, 5, 12, 2000, 96, 0, 195, 0, 14, 50, 164, 44
+"Man Eating mare", 4, 0, 42, 6, 8, 3, 14, 600, 52, 0, 3, 0, 0, 0, 32, 39
+"Manticore      ", 4, 1, 40, 6, 6, 4, 12, 600, 28, 0, 3, 0, 3, 20, 42, 26
+"Medusa         ", 2, 1, 32, 5, 4, 1, 9, 1000, 0, 0, 135, 143, 15, 20, 36, 12
+"Rakshasha      ", 4, 5, 40, 14, 5, 3, 14, 3000, 255, 50, 255, 142, 13, 80, 31, 11
+"Stone Golem    ", 3, 0, 50, 7, 40, 1, 6, 1500, 1, 20, 255, 0, 0, 0, 48, 16
+"Cave Troll     ", 6, 1, 50, 7, 11, 3, 10, 900, 28, 0, 163, 0, 0, 0, 96, 17
+"Hill Troll     ", 5, 2, 50, 8, 12, 3, 11, 1100, 10, 0, 179, 0, 0, 0, 96, 17
+"Warlock        ", 4, 60, 40, 8, 8, 1, 16, 800, 21, 0, 3, 0, 16, 95, 26, 52
+"Werebear       ", 4, 10, 45, 8, 8, 4, 14, 800, 0, 0, 135, 137, 0, 0, 160, 31
+"Wicked Witch   ", 4, 50, 30, 4, 6, 2, 14, 1000, 3, 0, 3, 151, 10, 40, 26, 12
+"Assassin       ", 4, 0, 45, 6, 8, 1, 19, 2000, 48, 0, 3, 146, 153, 0, 166, 57
+"Banshee        ", 2, 1, 40, 10, 10, 1, 12, 3000, 0, 128, 135, 145, 8, 40, 52, 62
+"Cave Giant     ", 6, 5, 50, 10, 16, 3, 12, 2000, 60, 0, 3, 0, 158, 0, 42, 17
+"Chimera        ", 4, 1, 60, 8, 5, 6, 14, 5000, 28, 0, 127, 0, 14, 40, 35, 26
+"Air Elemental  ", 1, 5, 70, 7, 15, 1, 20, 4000, 0, 20, 175, 147, 17, 30, 180, 27
+"Executioner    ", 1, 0, 60, 8, 12, 2, 14, 4000, 28, 0, 3, 146, 0, 0, 160, 57
+"Gorgon         ", 4, 5, 55, 8, 12, 1, 12, 6000, 0, 0, 3, 143, 11, 40, 35, 45
+"Lesser Demon   ", 4, 0, 40, 10, 8, 4, 16, 2500, 125, 20, 255, 145, 9, 15, 244, 59
+"Lesser Devil   ", 4, 0, 40, 8, 6, 5, 16, 2500, 125, 20, 255, 145, 9, 25, 244, 59
+"Mummy          ", 6, 0, 50, 7, 20, 2, 7, 2000, 96, 128, 191, 9, 0, 0, 48, 61
+"Necromancer    ", 4, 1, 35, 7, 8, 2, 17, 2000, 63, 40, 3, 0, 18, 95, 42, 54
+"Specter        ", 6, 0, 47, 8, 12, 1, 12, 3000, 0, 128, 143, 17, 0, 0, 48, 58
+"White Wolf     ", 6, 0, 42, 10, 12, 3, 14, 2500, 4, 0, 19, 9, 27, 30, 50, 29
+"Wyvern         ", 6, 5, 45, 7, 18, 2, 12, 2000, 38, 0, 3, 149, 0, 0, 32, 46
+"Green Dragon   ", 2, 0, 55, 8, 8, 3, 12, 6000, 63, 20, 255, 12, 25, 50, 163, 43
+"Blue Dragon    ", 3, 5, 50, 8, 10, 3, 13, 6000, 63, 20, 255, 12, 26, 50, 163, 43
+"Evil Eye       ", 2, 0, 65, 10, 10, 2, 10, 5000, 103, 20, 255, 143, 21, 60, 38, 21
+"Earth Elemental", 1, 5, 80, 8, 20, 1, 18, 4000, 0, 0, 215, 147, 17, 35, 180, 27
+"Ghost          ", 3, 0, 60, 10, 10, 1, 10, 4000, 0, 128, 135, 16, 0, 0, 48, 62
+"Frost Giant    ", 6, 0, 70, 10, 24, 1, 12, 5000, 62, 0, 147, 0, 148, 0, 166, 23
+"Stone Giant    ", 6, 2, 80, 10, 10, 4, 12, 4000, 62, 0, 131, 0, 148, 0, 166, 19
+"8 Headed hydra ", 1, 0, 75, 10, 8, 8, 13, 7500, 116, 0, 131, 0, 14, 35, 162, 44
+"Lava Beast     ", 6, 0, 50, 5, 12, 2, 9, 4000, 0, 0, 231, 0, 14, 20, 35, 20
+"Mantis Warrior ", 3, 0, 70, 8, 12, 4, 16, 4000, 68, 0, 131, 12, 0, 0, 160, 4
+"Naga           ", 3, 0, 65, 8, 8, 1, 15, 4000, 60, 25, 131, 136, 8, 40, 22, 35
+"Dinobeetle     ", 4, 0, 200, 10, 50, 1, 8, 6000, 28, 0, 131, 0, 0, 0, 160, 3
+"Sphinx         ", 2, 50, 60, 11, 10, 3, 18, 5000, 63, 40, 255, 7, 8, 40, 22, 34
+"Vampire        ", 4, 0, 55, 9, 12, 2, 14, 5000, 61, 138, 135, 145, 13, 50, 246, 59
+"Warrior        ", 4, 1, 75, 12, 12, 2, 14, 4000, 38, 0, 131, 0, 148, 0, 168, 50
+"Wizard         ", 2, 1, 60, 8, 6, 2, 18, 7000, 39, 0, 139, 0, 19, 95, 42, 52
+"White Dragon   ", 3, 0, 65, 8, 12, 3, 15, 10000, 127, 30, 255, 0, 27, 60, 163, 42
+"Gray Dragon    ", 3, 2, 70, 8, 15, 3, 16, 10000, 127, 30, 255, 0, 28, 60, 163, 42
+"Arch Druid     ", 1, 5, 65, 10, 8, 2, 18, 15000, 29, 0, 255, 151, 20, 90, 34, 53
+"Chaotic Knight ", 2, 0, 90, 14, 15, 3, 18, 7000, 134, 20, 135, 148, 158, 0, 250, 61
+"Greater Demon  ", 2, 0, 60, 15, 8, 7, 19, 10000, 127, 30, 255, 21, 13, 25, 250, 13
+"Greater Devil  ", 2, 0, 65, 12, 15, 4, 19, 10000, 127, 30, 255, 21, 13, 35, 250, 13
+"Fire Elemental ", 1, 5, 90, 9, 30, 1, 20, 8000, 0, 0, 199, 147, 17, 40, 180, 27
+"Guardian Spirit", 2, 0, 60, 8, 6, 6, 16, 6000, 0, 128, 135, 17, 0, 0, 48, 64
+"Storm Giant    ", 4, 1, 100, 9, 30, 2, 14, 10000, 198, 0, 167, 0, 19, 40, 38, 23
+"12 Headed hydra", 1, 0, 70, 10, 10, 12, 16, 12000, 127, 0, 131, 0, 14, 25, 162, 44
+"Invisible Thing", 4, 2, 50, 14, 10, 3, 25, 6000, 0, 0, 255, 22, 0, 0, 32, 58
+"Mage           ", 2, 1, 60, 10, 6, 3, 20, 8000, 39, 20, 143, 0, 21, 95, 42, 52
+"Master Thief   ", 2, 1, 65, 12, 8, 2, 20, 5000, 62, 0, 131, 23, 148, 0, 42, 49
+"Steel Golem    ", 2, 0, 70, 15, 25, 2, 10, 7500, 129, 30, 255, 0, 0, 0, 176, 61
+"Werephase Mummy", 4, 1, 70, 20, 20, 2, 35, 8000, 1, 50, 255, 9, 0, 0, 240, 61
+"Black Dragon   ", 2, 0, 75, 12, 18, 3, 16, 15000, 127, 30, 255, 135, 29, 70, 163, 41
+"Red Dragon     ", 2, 2, 80, 12, 20, 3, 15, 15000, 127, 30, 255, 141, 30, 70, 163, 41
+"Xx!xx!xx!xx!xx ", 2, 0, 10, 20, 1, 1, 18, 15000, 0, 50, 255, 151, 0, 0, 0, 9
+"Black Knight   ", 1, 0, 150, 16, 50, 3, 20, 10000, 134, 30, 255, 14, 168, 0, 246, 56
+"Demon Lord     ", 1, 0, 150, 20, 50, 2, 30, 60000, 255, 50, 255, 24, 23, 20, 246, 13
+"Arch Devil     ", 1, 0, 200, 16, 100, 1, 30, 60000, 255, 50, 255, 24, 23, 30, 246, 13
+"Gold Dragon    ", 1, 10, 150, 10, 20, 5, 16, 50000, 255, 40, 255, 136, 31, 80, 180, 41
+"Silver Dragon  ", 2, 0, 90, 8, 16, 4, 16, 20000, 255, 40, 255, 136, 31, 80, 180, 41
+"Diamond Golem  ", 2, 0, 100, 15, 60, 3, 12, 15000, 1, 40, 255, 0, 0, 0, 48, 16
+"16 Headed hydra", 1, 0, 100, 15, 12, 16, 12, 20000, 255, 20, 255, 0, 29, 25, 246, 44
+"High Cleric    ", 1, 5, 100, 14, 16, 3, 18, 10000, 127, 20, 131, 0, 22, 80, 36, 54
+"Kirin          ", 1, 50, 90, 15, 40, 4, 22, 14000, 135, 30, 255, 25, 9, 25, 42, 26
+"Lich           ", 1, 0, 80, 10, 10, 2, 20, 20000, 135, 218, 255, 17, 23, 90, 54, 65
+"Arch Mage      ", 1, 0, 70, 12, 8, 2, 25, 25000, 63, 30, 255, 0, 24, 95, 42, 52
+"Master Archer  ", 1, 5, 120, 10, 16, 8, 18, 25000, 199, 20, 255, 150, 250, 0, 47, 51
+"Phoenix        ", 1, 50, 150, 13, 8, 3, 24, 15000, 129, 10, 255, 144, 14, 60, 42, 27
+"Roc            ", 2, 20, 130, 10, 50, 3, 14, 15000, 0, 0, 255, 0, 0, 0, 32, 39
+"Sand Worm      ", 3, 1, 200, 7, 200, 1, 8, 15000, 129, 0, 143, 146, 0, 0, 176, 35
+"Titan          ", 1, 50, 180, 13, 60, 2, 30, 20000, 255, 95, 255, 0, 250, 0, 122, 36
+"Algae Beast    ", 15, 0, 1, 0, 6, 1, 1, 50, 0, 0, 7, 130, 0, 0, 16, 20
+"Water Rat      ", 15, 0, 3, 1, 6, 1, 6, 100, 0, 0, 6, 130, 0, 0, 16, 6
+"Lamprey        ", 10, 0, 10, 2, 8, 1, 15, 200, 0, 0, 7, 131, 0, 0, 32, 35
+"Giant Leech    ", 6, 0, 10, 2, 8, 1, 3, 250, 0, 0, 7, 132, 0, 0, 32, 75
+"Crocodile      ", 8, 0, 30, 5, 10, 2, 12, 300, 0, 0, 6, 0, 0, 0, 160, 75
+"Giant Crab     ", 6, 0, 25, 9, 10, 2, 12, 300, 0, 0, 7, 0, 0, 0, 32, 0
+"Barracuda      ", 15, 0, 20, 5, 20, 1, 16, 350, 0, 0, 7, 0, 0, 0, 48, 75
+"Giant Squid    ", 4, 0, 30, 5, 6, 8, 14, 400, 0, 0, 7, 136, 6, 20, 38, 75
+"Electric Eel   ", 10, 0, 30, 5, 8, 1, 15, 500, 0, 0, 47, 136, 10, 20, 47, 75
+"Sea Hag        ", 6, 0, 40, 8, 6, 3, 12, 500, 0, 20, 15, 12, 15, 30, 102, 12
+"Hippocampus    ", 8, 0, 50, 12, 10, 4, 18, 600, 0, 20, 15, 7, 0, 0, 224, 38
+"Shark          ", 15, 0, 40, 6, 30, 2, 24, 700, 0, 0, 15, 0, 0, 0, 176, 75
+"Siren          ", 8, 0, 30, 8, 8, 2, 13, 700, 0, 20, 255, 143, 7, 20, 102, 64
+"Water Elemental", 6, 0, 80, 12, 50, 1, 30, 1200, 0, 20, 255, 0, 17, 50, 247, 9
+"Sea Serpent    ", 3, 32, 100, 10, 100, 1, 20, 3000, 0, 40, 143, 146, 0, 0, 240, 42
+"Sea Dragon     ", 3, 32, 150, 15, 50, 4, 32, 20000, 0, 50, 255, 8, 31, 50, 243, 42
+"Scorpion       ", 1, 0, 210, 12, 60, 2, 20, 12000, 0, 50, 207, 12, 0, 0, 240, 1
+"Dark Rider     ", 1, 0, 210, 15, 50, 4, 30, 12000, 0, 90, 127, 17, 19, 20, 255, 56
+"Winged Beast   ", 1, 0, 210, 12, 120, 1, 30, 12000, 0, 50, 159, 8, 0, 0, 240, 46
+"Great Sea beast", 1, 0, 210, 12, 100, 1, 30, 12000, 0, 50, 143, 147, 0, 0, 240, 75
+"Demon King     ", 1, 0, 240, 30, 50, 5, 35, 50000, 255, 120, 255, 24, 23, 30, 255, 73
+"Succubus Queen ", 1, 0, 150, 20, 30, 3, 20, 10000, 127, 100, 239, 147, 21, 50, 255, 74
+"Tyrannosaurus  ", 3, 0, 240, 10, 200, 1, 12, 5000, 6, 0, 7, 147, 0, 0, 160, 45
+"Alien          ", 6, 16, 100, 15, 20, 2, 15, 1000, 1, 40, 7, 149, 24, 30, 35, 4
+"Natives        ", 15, 21, 40, 6, 10, 2, 10, 200, 3, 0, 3, 132, 32, 20, 163, 7
+"Volcano God    ", 1, 0, 220, 30, 40, 6, 32, 60000, 255, 120, 255, 24, 13, 50, 255, 20
+"Paul Pead      ", 1, 0, 100, 10, 30, 1, 19, 2000, 61, 50, 143, 14, 13, 40, 243, 50
+"Pirate         ", 15, 0, 40, 8, 20, 1, 17, 500, 7, 10, 135, 138, 0, 0, 176, 58
+"Pirate Captain ", 1, 0, 80, 10, 20, 3, 18, 1000, 15, 30, 135, 11, 7, 20, 51, 58
+"Gray Minotaur  ", 1, 0, 150, 13, 30, 4, 20, 15000, 63, 40, 143, 7, 10, 30, 255, 40
+"Lord Archer    ", 1, 0, 32, 15, 80, 3, 21, 20000, 63, 100, 207, 6, 250, 0, 255, 51
+"Brontasaurus   ", 3, 16, 200, 8, 150, 1, 6, 5000, 6, 0, 7, 147, 0, 0, 160, 45
+"Stegosaurus    ", 3, 5, 200, 15, 200, 1, 6, 5000, 6, 0, 7, 147, 0, 0, 160, 45
+"Killer Cadaver ", 3, 1, 50, 8, 12, 3, 15, 1500, 255, 0, 1, 9, 0, 0, 240, 65
+"Okrim          ", 2, 1, 80, 11, 6, 4, 18, 20000, 39, 0, 139, 0, 19, 95, 42, 52


Commit: 3b7bb9cfa92af9fe81344d60bc4e336003dc5f28
    https://github.com/scummvm/scummvm/commit/3b7bb9cfa92af9fe81344d60bc4e336003dc5f28
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2023-03-25T22:24:38-07:00

Commit Message:
MM: MM1: Fix display of combat party names

Changed paths:
    engines/mm/mm1/views_enh/combat.cpp


diff --git a/engines/mm/mm1/views_enh/combat.cpp b/engines/mm/mm1/views_enh/combat.cpp
index 153ecbb1ead..dacc1b6eb0a 100644
--- a/engines/mm/mm1/views_enh/combat.cpp
+++ b/engines/mm/mm1/views_enh/combat.cpp
@@ -485,7 +485,7 @@ void Combat::clearArea(const Common::Rect &r) {
 
 
 void Combat::resetBottom() {
-	clearArea(Common::Rect(0, BOTTOM_Y, 320, 200));
+	clearArea(Common::Rect(0, 19 * LINE_H, 320, 200));
 	_allowFight = _allowShoot = false;
 	_allowCast = _allowAttack = false;
 }




More information about the Scummvm-git-logs mailing list