Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

1
engines/efh/POTFILES Normal file
View File

@@ -0,0 +1 @@
engines/efh/metaengine.cpp

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine efh "Escape From Hell" yes

471
engines/efh/constants.cpp Normal file
View File

@@ -0,0 +1,471 @@
/* 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 "efh/constants.h"
namespace Efh {
const uint8 kFontWidthArray[96] = {
3, 2, 3, 5, 5, 5, 5, 2, 3, 3, 5, 5, 3, 3, 2, 7, 4, 3, 4, 4, 5, 4, 4, 4, 4, 4, 3, 4, 4, 5, 4, 5, 1, 4, 4, 4,
4, 4, 4, 4, 4, 3, 4, 4, 4, 7, 5, 4, 4, 4, 4, 4, 5, 4, 5, 7, 5, 5, 5, 3, 7, 3, 5, 0, 2, 4, 4, 4, 4, 4, 4, 4,
4, 1, 2, 4, 1, 7, 4, 4, 4, 4, 4, 4, 3, 4, 5, 7, 4, 4, 5, 3, 0, 3, 0, 0};
const uint8 kFontExtraLinesArray[96] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 3,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, 0, 0};
const Font kFontData[96] = {
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00}},
{{0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x00, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x00, 0x00}},
{{0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}},
{{0xC8, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x98, 0x00}},
{{0x20, 0x50, 0x20, 0x40, 0xA8, 0x90, 0x68, 0x00}},
{{0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40}},
{{0x40, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40}},
{{0x00, 0xA8, 0x70, 0xF8, 0x70, 0xA8, 0x00, 0x00}},
{{0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x40}},
{{0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}},
{{0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}},
{{0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}},
{{0x40, 0xC0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}},
{{0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00}},
{{0x60, 0x90, 0x10, 0x20, 0x10, 0x90, 0x60, 0x00}},
{{0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}},
{{0xF0, 0x80, 0xE0, 0x10, 0x10, 0x90, 0x60, 0x00}},
{{0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00}},
{{0xF0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x40, 0x00}},
{{0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00}},
{{0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00}},
{{0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00}},
{{0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x40, 0x00}},
{{0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00}},
{{0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00}},
{{0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00}},
{{0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x60, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}},
{{0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00}},
{{0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00}},
{{0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00}},
{{0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00}},
{{0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00}},
{{0x60, 0x90, 0x80, 0xB0, 0x90, 0x90, 0x70, 0x00}},
{{0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00}},
{{0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00}},
{{0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}},
{{0x90, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}},
{{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00}},
{{0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00}},
{{0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}},
{{0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}},
{{0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00}},
{{0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x10}},
{{0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x90, 0x00}},
{{0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00}},
{{0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}},
{{0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00}},
{{0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}},
{{0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x82, 0x00}},
{{0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}},
{{0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}},
{{0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00}},
{{0xC0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0}},
{{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00}},
{{0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60}},
{{0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x00, 0x00, 0x80, 0x80, 0x40, 0x00, 0x00, 0x00}},
{{0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00}},
{{0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00}},
{{0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00}},
{{0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00}},
{{0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x60, 0x00}},
{{0x30, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}},
{{0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0, 0x00}},
{{0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}},
{{0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}},
{{0x40, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80}},
{{0x80, 0x80, 0x90, 0x90, 0xE0, 0x90, 0x90, 0x00}},
{{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}},
{{0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00}},
{{0x00, 0x00, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00}},
{{0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00}},
{{0x00, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x80, 0x80}},
{{0x00, 0x70, 0x90, 0x90, 0x90, 0x70, 0x10, 0x10}},
{{0x00, 0x00, 0xB0, 0xC0, 0x80, 0x80, 0x80, 0x00}},
{{0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00}},
{{0x40, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x00}},
{{0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x00}},
{{0x00, 0x00, 0x88, 0x50, 0x50, 0x20, 0x20, 0x00}},
{{0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x6E, 0x00}},
{{0x00, 0x00, 0x90, 0x90, 0x60, 0x90, 0x90, 0x00}},
{{0x00, 0x90, 0x90, 0x90, 0x90, 0x70, 0x10, 0xE0}},
{{0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}},
{{0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
};
const Encounter kEncounters[] {
{"Indian", 0, 5, 50, {64, 64, 68, 70, 92}, 25, 2},
{"Warrior", 0, 6, 85, {70, 64, 68, 70, 92}, 35, 2},
{"Tracker", 0, 8, 115, {92, 64, 68, 70, 92}, 38, 2},
{"Savage", 0, 15, 150, {92, 64, 68, 70, 92}, 50, 2},
{"Chief", 0, 50, 200, {94, 64, 70, 92, 95}, 95, 2},
{"Archer", 1, 5, 50, {70, 71, 64, 66, 69}, 35, 2},
{"Bowman", 1, 10, 50, {70, 71, 64, 66, 69}, 50, 2},
{"Ranger", 1, 20, 150, {70, 71, 64, 66, 69}, 45, 2},
{"Censor", 2, 5, 35, {205, 64, 64, 64, 64}, 25, 2},
{"Noisy Guy", 2, 7, 80, {205, 64, 64, 64, 64}, 27, 2},
{"Cruiser", 2, 12, 55, {205, 210, 64, 64, 64}, 32, 2},
{"Boomer", 2, 20, 110, {205, 210, 210, 64, 64}, 45, 2},
{"Neanderthal", 3, 5, 65, {127, 127, 127, 127, 64}, 25, 2},
{"Savage", 3, 7, 90, {127, 127, 127, 127, 64}, 35, 2},
{"Roughian", 3, 15, 110, {127, 127, 127, 87, 64}, 37, 2},
{"Troglodyte", 3, 20, 135, {127, 127, 127, 127, 64}, 45, 2},
{"Scuba Guy", 4, 5, 50, {211, 64, 144, 165, 64}, 25, 2},
{"Diver", 4, 12, 80, {211, 165, 144, 165, 64}, 28, 2},
{"Surfer", 4, 10, 75, {212, 212, 144, 205, 64}, 30, 2},
{"Warrior", 4, 15, 100, {66, 69, 68, 64, 66}, 35, 2},
{"Maniac", 4, 20, 150, {214, 201, 205, 81, 90}, 38, 2},
{"Loon", 4, 35, 250, {214, 201, 205, 81, 90}, 45, 2},
{"Crypt Thing", 5, 15, 200, {215, 215, 215, 217, 217}, 35, 2},
{"Crypt Corpse", 5, 20, 250, {215, 215, 215, 217, 217}, 40, 2},
{"Zombie", 5, 25, 225, {215, 215, 215, 217, 217}, 45, 2},
{"Dead Being", 5, 40, 350, {215, 215, 216, 217, 217}, 55, 2},
{"Despair", 6, 10, 125, {127, 127, 128, 128, 129}, 25, 2},
{"Apparition", 6, 15, 245, {127, 127, 128, 128, 129}, 29, 2},
{"Burial Spirit", 6, 25, 300, {127, 128, 128, 129, 129}, 55, 2},
{"Ghoul", 6, 32, 410, {127, 127, 128, 128, 129}, 70, 2},
{"Skeleton", 6, 6, 75, {127, 127, 128, 128, 129}, 60, 2},
{"Soul", 6, 40, 400, {127, 127, 128, 128, 129}, 62, 2},
{"Projection", 6, 27, 350, {127, 127, 128, 128, 129}, 65, 2},
{"Cowboy", 7, 5, 150, {90, 90, 90, 90, 91}, 25, 2},
{"Sheriff", 7, 8, 250, {90, 90, 90, 91, 91}, 35, 2},
{"Bad Bart", 7, 35, 500, {90, 90, 91, 91, 91}, 95, 2},
{"Gun Slinger", 7, 20, 380, {90, 90, 91, 91, 91}, 55, 2},
{"Fast Draw", 7, 17, 290, {90, 91, 91, 91, 91}, 45, 2},
{"Quick Draw", 7, 30, 420, {90, 91, 92, 93, 92}, 65, 2},
{"Dinosaur", 8, 35, 200, {128, 128, 128, 126, 126}, 25, 2},
{"Biped", 8, 50, 225, {128, 128, 128, 126, 126}, 30, 2},
{"Dino Beast", 8, 65, 250, {128, 128, 128, 126, 126}, 35, 2},
{"Intellosaur", 8, 80, 380, {128, 128, 128, 126, 126}, 45, 2},
{"Awful Animal", 8, 105, 495, {128, 128, 128, 126, 126}, 55, 2},
{"Death Serpent", 9, 60, 450, {94, 97, 98, 99, 135}, 75, 2},
{"Demon Snake", 9, 80, 580, {97, 98, 94, 99, 137}, 85, 2},
{"Fire Lizard", 9, 100, 400, {135, 98, 99, 137, 136}, 95, 2},
{"Winged Demon", 9, 110, 475, {97, 98, 138, 139, 140}, 100, 2},
{"Duke of Hell", 10, 500, 2000, {137, 138, 139, 140, 135}, 100, 2},
{"Beach Fiend", 10, 150, 580, {137, 138, 139, 136, 98}, 100, 2},
{"Arch Devil", 10, 2000, 10000, {98, 97, 98, 140, 139}, 100, 2},
{"Major Fiend", 10, 195, 666, {98, 99, 98, 99, 137}, 100, 2},
{"Enforcer", 11, 20, 110, {127, 126, 76, 75, 145}, 25, 2},
{"Grunt", 11, 30, 150, {163, 127, 161, 165, 152}, 35, 2},
{"Behemoth", 11, 35, 175, {144, 148, 160, 161, 163}, 45, 2},
{"Giant Demon", 11, 50, 245, {127, 107, 151, 155, 159}, 55, 2},
{"Slaver", 11, 42, 225, {127, 124, 114, 115, 121}, 65, 2},
{"Minor Demon", 12, 6, 100, {73, 73, 130, 130, 130}, 27, 2},
{"Common Demon", 12, 9, 150, {73, 73, 130, 130, 130}, 30, 2},
{"Small Demon", 12, 15, 175, {73, 73, 73, 73, 130}, 38, 2},
{"Simple Demon", 12, 20, 200, {73, 73, 73, 130, 130}, 45, 2},
{"Lesser Demon", 12, 12, 160, {73, 73, 73, 73, 73}, 32, 2},
{"Warrior", 13, 7, 50, {65, 65, 66, 66, 64}, 30, 2},
{"Gladiator", 13, 12, 95, {65, 65, 66, 66, 64}, 35, 2},
{"Moutaineer", 13, 10, 80, {66, 66, 80, 72, 64}, 45, 2},
{"Strong Guy", 13, 13, 98, {66, 66, 66, 66, 66}, 55, 2},
{"Hell Private", 14, 10, 150, {66, 66, 66, 65, 65}, 35, 2},
{"Hell Corporal", 14, 15, 150, {66, 66, 66, 65, 65}, 40, 2},
{"Hell Sgt.", 14, 17, 150, {66, 66, 66, 65, 65}, 45, 2},
{"Hell LT.", 14, 25, 245, {105, 66, 66, 65, 65}, 50, 2},
{"Hell Guard", 14, 6, 100, {66, 66, 66, 65, 65}, 20, 2},
{"Hell Soldier", 14, 35, 380, {106, 66, 66, 163, 65}, 65, 2},
{"Demon Fighter", 14, 40, 400, {106, 105, 163, 65, 65}, 75, 2},
{"Ice Beast", 15, 25, 650, {69, 69, 69, 68, 68}, 45, 2},
{"Snow Fiend", 15, 30, 666, {132, 69, 69, 68, 68}, 55, 2},
{"SalivaMonster", 15, 45, 750, {107, 110, 132, 157, 129}, 65, 2},
{"Spit Grunt", 15, 40, 666, {107, 110, 132, 157, 129}, 75, 2},
{"Cold Demon", 15, 42, 666, {107, 110, 68, 69, 69}, 85, 2},
{"Insectoid", 16, 15, 400, {153, 152, 154, 161, 147}, 35, 2},
{"Giant Insect", 16, 17, 400, {94, 96, 96, 202, 202}, 45, 2},
{"Insect Guard", 16, 25, 400, {94, 96, 99, 202, 202}, 55, 2},
{"Roaming Bug", 16, 35, 450, {94, 96, 99, 136, 134}, 45, 2},
{"Blade Bug", 16, 45, 590, {135, 158, 156, 202, 202}, 45, 2},
{"Logger", 17, 7, 125, {89, 78, 89, 89, 64}, 30, 2},
{"Massacrer", 17, 10, 175, {89, 89, 89, 89, 64}, 35, 2},
{"Murderer", 17, 12, 225, {89, 89, 89, 79, 64}, 38, 2},
{"Crazy Guy", 17, 13, 235, {89, 87, 88, 89, 64}, 40, 2},
{"Massive Dude", 17, 15, 250, {89, 89, 81, 89, 64}, 36, 2},
{"Chainsaw Guy", 17, 11, 180, {89, 89, 88, 89, 64}, 45, 2},
{"DevilDaughter", 18, 75, 850, {181, 182, 182, 181, 195}, 100, 2},
{"Evil Woman", 18, 5, 85, {181, 182, 182, 181, 195}, 35, 2},
{"Enchantress'", 18, 7, 150, {181, 182, 182, 181, 195}, 40, 2}, // The extra quote is in the original game
{"Temptress'", 18, 9, 200, {181, 182, 182, 181, 195}, 55, 2}, // The extra quote is in the original game
{"Lustivious'", 18, 100, 1750, {181, 182, 196, 197, 197}, 100, 1}, // The extra quote is in the original game
{"Major Demon", 19, 25, 666, {106, 105, 163, 65, 65}, 45, 2},
{"Giant Demon", 19, 50, 865, {106, 105, 163, 65, 65}, 55, 2},
{"Gnarly Demon", 19, 75, 999, {106, 105, 163, 65, 65}, 65, 2},
{"Pit Fiend", 19, 40, 777, {114, 113, 163, 163, 163}, 95, 2},
{"Hellish Fiend", 19, 80, 1500, {113, 114, 113, 163, 163}, 100, 2},
{"Monk", 20, 6, 75, {0, 0, 0, 0, 0}, 0, 2},
{"Unholy Monk", 20, 12, 100, {202, 197, 96, 108, 149}, 30, 2},
{"Evil Monk", 20, 15, 150, {202, 197, 96, 153, 149}, 33, 2},
{"Sacrificer", 20, 18, 185, {202, 197, 108, 108, 108}, 37, 2},
{"Nasty Guy", 20, 25, 200, {202, 197, 96, 153, 149}, 45, 2},
{"Mutant Demon", 21, 15, 100, {93, 91, 90, 94, 95}, 35, 2},
{"Hell Captain", 21, 25, 275, {93, 91, 90, 94, 95}, 37, 2},
{"Muscle Demon", 21, 32, 350, {93, 91, 90, 94, 95}, 40, 2},
{"Blaster Demon", 21, 60, 690, {93, 91, 90, 94, 95}, 45, 2},
{"Knight", 22, 15, 150, {133, 133, 150, 128, 128}, 35, 2},
{"Evil Knight", 22, 25, 200, {133, 150, 116, 122, 128}, 40, 2},
{"UnJust Knight", 22, 35, 375, {133, 150, 128, 122, 128}, 45, 2},
{"Astray Knight", 22, 50, 450, {133, 150, 120, 121, 128}, 65, 2},
{"Anit-Paladin", 22, 75, 750, {109, 115, 128, 128, 128}, 85, 2},
{"Moaning", 23, 3, 3, {72, 78, 81, 83, 83}, 50, 2},
{"Tormented", 23, 5, 5, {72, 78, 81, 83, 83}, 50, 2},
{"Suffering", 23, 4, 4, {72, 78, 81, 83, 83}, 50, 2},
{"Starving Guy", 23, 2, 2, {72, 78, 81, 83, 83}, 50, 2},
{"Withered Soul", 23, 1, 1, {72, 78, 81, 83, 83}, 50, 2},
{"Ogre", 24, 20, 275, {109, 106, 65, 163, 163}, 45, 2},
{"ElectroKnight", 24, 25, 290, {109, 106, 65, 163, 163}, 55, 2},
{"Energy Demon", 24, 30, 320, {109, 106, 65, 163, 163}, 55, 2},
{"Power Devil", 24, 35, 350, {107, 109, 114, 207, 207}, 65, 2},
{"Sorcerer", 24, 42, 400, {109, 106, 65, 163, 163}, 75, 2},
{"Enchanter", 24, 35, 350, {109, 106, 65, 163, 163}, 85, 2},
{"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2},
{"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2},
{"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2},
{"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2},
{"Canon Monk", 28, 35, 100, {0, 0, 0, 0, 0}, 0, 2},
{"Screamer", 26, 5, 35, {152, 152, 146, 145, 64}, 30, 2},
{"Moaner", 26, 7, 40, {152, 152, 146, 145, 64}, 35, 2},
{"Screacher", 26, 12, 85, {152, 152, 146, 145, 64}, 40, 2},
{"Singer", 26, 15, 100, {152, 152, 146, 145, 64}, 45, 2},
{"Pilot", 27, 12, 150, {90, 90, 90, 92, 92}, 35, 2},
{"Crashed Pilot", 27, 20, 200, {90, 90, 90, 92, 92}, 40, 2},
{"WW I Pilot", 27, 25, 225, {90, 90, 90, 92, 92}, 45, 2},
{"WW II Pilot", 27, 35, 280, {94, 134, 136, 136, 92}, 55, 2},
{"Boney Soldier", 27, 45, 350, {90, 134, 136, 137, 138}, 65, 2},
{"ModernSoldier", 27, 75, 845, {97, 97, 98, 99, 94}, 95, 2},
{"Surpriser", 28, 10, 100, {100, 101, 102, 103, 104}, 35, 2},
{"Shocker", 28, 15, 350, {100, 101, 102, 103, 104}, 45, 2},
{"Blast Monk", 28, 20, 400, {100, 101, 102, 103, 104}, 55, 2},
{"Canon Monk", 28, 28, 480, {100, 101, 102, 103, 104}, 65, 2},
{"Killer", 28, 35, 550, {100, 101, 102, 103, 104}, 75, 2},
{"Rubber Necker", 29, 45, 1000, {152, 153, 144, 111, 112}, 20, 2},
{"Skull Thing", 29, 60, 1250, {113, 114, 115, 105, 112}, 30, 2},
{"Laser Eye", 29, 80, 1750, {94, 134, 135, 90, 91}, 40, 2},
{"Beamer", 29, 100, 2200, {94, 134, 135, 90, 91}, 50, 2},
{"Hideous Beast", 29, 150, 3500, {94, 134, 135, 90, 91}, 60, 2},
{"Samurai", 30, 10, 35, {67, 67, 67, 68, 68}, 30, 2},
{"Ninja", 30, 15, 90, {67, 67, 67, 68, 68}, 32, 2},
{"SegaSamurai", 30, 20, 150, {67, 67, 67, 68, 68}, 45, 2},
{"NintendoNinja", 30, 35, 220, {67, 67, 67, 68, 68}, 45, 2},
{"OrientalSlayr", 30, 45, 250, {67, 67, 67, 68, 68}, 55, 2},
{"Soldier", 31, 10, 100, {100, 101, 102, 90, 92}, 30, 2},
{"Fighter", 31, 15, 125, {100, 93, 94, 96, 104}, 35, 2},
{"Grenader", 31, 20, 175, {100, 101, 102, 103, 104}, 45, 2},
{"Gunner", 31, 25, 190, {137, 136, 135, 134, 94}, 50, 2},
{"Scratche", 32, 6, 95, {0, 0, 0, 0, 0}, 0, 2},
{"Claw", 32, 15, 150, {0, 0, 0, 0, 0}, 0, 2},
{"Claw Demon", 32, 25, 264, {0, 0, 0, 0, 0}, 0, 2},
{"Talon Demon", 32, 35, 300, {0, 0, 0, 0, 0}, 0, 2},
{"Malicioun", 32, 50, 350, {0, 0, 0, 0, 0}, 0, 2},
{"Imp", 33, 3, 100, {64, 64, 131, 131, 131}, 35, 2},
{"Tiny Demon", 33, 6, 150, {64, 132, 131, 131, 131}, 40, 2},
{"Short Devil", 33, 12, 255, {132, 132, 131, 131, 132}, 45, 2},
{"Gremlin", 33, 25, 300, {64, 64, 131, 131, 131}, 50, 2},
{"Thug", 34, 8, 175, {93, 93, 94, 92, 95}, 30, 2},
{"Punk", 34, 15, 250, {93, 93, 94, 92, 95}, 35, 2},
{"Killer", 34, 18, 275, {93, 93, 94, 92, 95}, 40, 2},
{"Street Dude", 34, 25, 350, {93, 93, 94, 92, 95}, 45, 2},
{"Slasher", 35, 5, 190, {131, 131, 131, 131, 131}, 30, 2},
{"Blade Demon", 35, 15, 250, {132, 131, 131, 131, 131}, 35, 2},
{"Cleaver Devil", 35, 30, 290, {132, 132, 131, 131, 131}, 45, 2},
{"Stench Beast", 36, 6, 75, {0, 0, 0, 0, 0}, 0, 2},
{"Breather", 36, 10, 150, {0, 0, 0, 0, 0}, 0, 2},
{"Smelly Thing", 36, 15, 175, {0, 0, 0, 0, 0}, 0, 2},
{"Ugly Devil", 36, 25, 225, {0, 0, 0, 0, 0}, 0, 2},
{"Surf Nazi", 37, 5, 67, {64, 86, 218, 218, 219}, 30, 2},
{"Beacher", 37, 8, 95, {64, 86, 218, 218, 219}, 35, 2},
{"Scum", 37, 12, 125, {64, 86, 218, 218, 219}, 45, 2},
{"Waste", 37, 18, 150, {64, 86, 218, 218, 219}, 55, 2},
{"Duelist", 38, 6, 65, {65, 65, 65, 147, 66}, 40, 2},
{"Sword Guy", 38, 10, 87, {65, 155, 65, 153, 66}, 50, 2},
{"Muskateer", 38, 15, 97, {65, 65, 154, 66, 66}, 65, 2},
{"Valkyrie", 39, 7, 37, {65, 65, 65, 66, 66}, 35, 2},
{"WarriorMaiden", 39, 20, 137, {65, 65, 65, 66, 66}, 55, 2},
{"Worm King", 40, 150, 4500, {202, 194, 195, 181, 181}, 100, 2},
{"Worm Lord", 40, 100, 3300, {202, 194, 195, 181, 181}, 100, 2},
{"Eye of Hell", 40, 60, 1200, {202, 194, 195, 181, 181}, 70, 2},
{"Visionary", 40, 40, 800, {202, 194, 195, 181, 181}, 55, 2},
{"Thing", 40, 25, 650, {202, 194, 195, 181, 181}, 45, 2},
{"Zombie", 41, 10, 450, {97, 97, 98, 98, 127}, 35, 2},
{"Police Dude", 41, 25, 350, {97, 161, 148, 98, 127}, 45, 2},
{"Cop", 41, 15, 275, {97, 152, 98, 156, 127}, 30, 2},
{"Dark Cop", 41, 20, 300, {97, 162, 98, 98, 127}, 35, 2},
{"Bully Cop", 41, 25, 350, {97, 97, 98, 98, 127}, 45, 2},
{"Drowning", 42, 10, 50, {0, 0, 0, 0, 0}, 0, 2},
{"Watery Guy", 42, 35, 150, {0, 0, 0, 0, 0}, 0, 2},
{"Evangelist", 43, 8, 50, {0, 0, 0, 0, 0}, 0, 2},
{"Preacher", 43, 15, 150, {0, 0, 0, 0, 0}, 0, 2},
{"Smooth Talker", 43, 20, 175, {0, 0, 0, 0, 0}, 0, 2},
{"Hulk", 44, 20, 100, {220, 220, 220, 220, 202}, 32, 0},
{"MIGHTY Guy", 44, 30, 200, {220, 220, 220, 220, 202}, 43, 2},
{"Powerful Dude", 44, 45, 400, {220, 220, 220, 220, 202}, 55, 2},
{ "XXXXXXXXXXXXX", 0xFF, 0xFFFF, 0xFFFF, {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, 0, 0 }
};
const char kSkillArray[37][20] = {
// Active Scores
"Flying",
"Swimming",
"Electrical",
"Mechanical",
"Hacking",
"Bluffing",
"Boatman",
"Pilot",
"Bureaucracy",
"Find Trap",
"Parachuting",
"Pick Lock",
"Explosives",
"Chemistry",
"Steal",
// Passive Scores
"Dueling",
"Marksmanship",
"Fist Fighting",
"Martial Arts",
"Acrobatics",
"Melee Weapon",
"Pistol Combat",
"Rifle Combat",
"Automatic/SMG",
"Archery",
"Rocket Lncher",
// Info Scores
"Strength",
"Intelligence",
"Piety",
"Agility",
"Stamina",
"Stealth",
"Evasion",
"Comprehension",
"Perception",
"Psychic Force",
"Alignment"
};
const uint8 kByte2C7D0[60] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 0, 2, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
const char kPossessive[3][4] = { "his", "her", "its"};
const char kPersonal[3][4] = {"him", "her", "it"};
const char kAttackVerbs[51][20] = {
"hits",
"strikes",
"hits",
"slashes",
"hacks",
"slashes",
"stabs",
"sticks",
"pokes",
"pounds",
"bashes",
"hammers",
"blasts",
"blasts",
"roasts",
"blasts",
"chills",
"zaps",
"zaps",
"zaps",
"zaps",
"shoots",
"hits",
"strikes",
"zaps",
"zaps",
"zaps",
"blasts",
"blasts",
"blasts",
"blasts",
"blasts",
"blasts",
"blasts",
"blasts",
"blasts",
"blasts",
"shoots",
"shoots",
"blasts",
"shoots",
"shoots",
"blasts",
"shoots",
"shoots",
"gases",
"sprays",
"fumigates",
"shoots",
"shoots",
"shoots"
};
const int16 kSoundFrequency[72] = {
18356, 17292, 16344, 15297, 14551,
13714, 12829, 12175, 11472, 10847,
10198, 9700, 9108, 8584, 8116, // last 3 : C, C#, D
7648, 7231, 6818, 6449, 6087, // D#, E, F, F#, G
5736, 5423, 5120, 4830, 4554, // G#, A, A#, B, Middle C
4307, 4058, 3836, 3615, 3418, // C#, D, D#
3224, 3043, 2875, 2711, 2560,
2415, 2281, 2153, 2032, 1918,
1810, 1709, 1612, 1521, 1435,
1355, 1280, 1207, 1139, 1075,
1015, 958, 897, 854, 806,
760, 718, 677, 639, 603,
570, 538, 507, 479, 452,
427, 403, 380, 359, 338,
319, 301
};
} // End of namespace Efh

86
engines/efh/constants.h Normal file
View File

@@ -0,0 +1,86 @@
/* 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 EFH_CONSTANTS_H
#define EFH_CONSTANTS_H
#include "common/scummsys.h"
namespace Efh {
enum EfhMenuItems {
kEfhMenuEquip = 0,
kEfhMenuUse = 1,
kEfhMenuGive = 2,
kEfhMenuTrade = 3,
kEfhMenuDrop = 4,
kEfhMenuInfo = 5,
kEfhMenuPassive = 6,
kEfhMenuActive = 7,
kEfhMenuLeave = 8,
kEfhMenuInvalid = 9
};
enum EfhReactionType {
kEfhReactionReels = 0,
kEfhReactionCriesOut = 1,
kEfhReactionFalters = 2,
kEfhReactionWinces = 3,
kEfhReactionScreams = 4,
kEfhReactionChortles = 5,
kEfhReactionLaughs = 6
};
enum EfhStatusType {
kEfhStatusNormal = 0,
kEfhStatusSleeping = 1,
kEfhStatusFrozen = 2
};
struct Font {
uint8 _lines[8];
};
struct Encounter {
char _name[14];
uint8 _animId;
uint16 _pictureRef;
uint16 _xpGiven;
uint16 _dropItemId[5];
uint8 _dropOccurrencePct;
uint8 _nameArticle;
};
#define kDefaultNoteDuration 616
extern const uint8 kFontWidthArray[96];
extern const uint8 kFontExtraLinesArray[96];
extern const Font kFontData[96];
extern const Encounter kEncounters[];
extern const char kSkillArray[37][20];
extern const uint8 kByte2C7D0[60];
extern const char kPossessive[3][4];
extern const char kPersonal[3][4];
extern const char kAttackVerbs[51][20];
extern const int16 kSoundFrequency[72];
} // End of namespace Efh
#endif // EFH_CONSTANTS_H

3
engines/efh/credits.pl Normal file
View File

@@ -0,0 +1,3 @@
begin_section("Efh");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
end_section();

87
engines/efh/detection.cpp Normal file
View File

@@ -0,0 +1,87 @@
/* 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 "base/plugins.h"
#include "engines/advancedDetector.h"
#include "efh/detection.h"
#include "efh/efh.h"
namespace Efh {
static const PlainGameDescriptor efhGames[] = {
// Games
{"efh", "Escape From Hell"},
{nullptr, nullptr}
};
static const ADGameDescription gameDescriptions[] = {
// Escape From Hell English - Unpacked version
{
"efh", nullptr, AD_ENTRY1s("escape.exe", "2702f8f713e113a853a925d29aecc709", 147312),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GAMEOPTION_TTS)
},
// Escape From Hell English
{
"efh", nullptr, AD_ENTRY1s("escape.exe", "1ca4ae3f2ea66c30d1ef3e257a86cd05", 141487),
Common::EN_ANY,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GAMEOPTION_TTS)
},
AD_TABLE_END_MARKER
};
static const DebugChannelDef debugFlagList[] = {
{Efh::kDebugEngine, "engine", "Engine debug level"},
{Efh::kDebugUtils, "utils", "Utils debug level"},
{Efh::kDebugGraphics, "graphics", "Graphics debug level"},
DEBUG_CHANNEL_END};
class EfhMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
public:
EfhMetaEngineDetection() : AdvancedMetaEngineDetection(gameDescriptions, efhGames) {
}
const char *getEngineName() const override {
return "Efh";
}
const char *getName() const override {
return "efh";
}
const char *getOriginalCopyright() const override {
return "Escape From Hell (C) Electronic Arts, 1990";
}
const DebugChannelDef *getDebugChannels() const override {
return debugFlagList;
}
};
} // End of namespace efh
REGISTER_PLUGIN_STATIC(EFH_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, Efh::EfhMetaEngineDetection);

27
engines/efh/detection.h Normal file
View File

@@ -0,0 +1,27 @@
/* 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 EFH_DETECTION_H
#define EFH_DETECTION_H
#define GAMEOPTION_TTS GUIO_GAMEOPTIONS1
#endif // EFH_DETECTION_H

2712
engines/efh/efh.cpp Normal file

File diff suppressed because it is too large Load Diff

793
engines/efh/efh.h Normal file
View File

@@ -0,0 +1,793 @@
/* 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 EFH_H
#define EFH_H
#include "audio/softsynth/pcspk.h"
#include "audio/mixer.h"
#include "common/file.h"
#include "common/rect.h"
#include "common/events.h"
#include "common/serializer.h"
#include "common/text-to-speech.h"
#include "engines/advancedDetector.h"
#include "engines/engine.h"
#include "graphics/surface.h"
#include "efh/constants.h"
namespace Common {
class RandomSource;
}
/**
* This is the namespace of the Efh engine.
*
* Status of this engine:
* - No music in intro
* - No random PC speaker farts (aka sounds)
* - The rest is more or less working :)
*
* Games using this engine:
* - Escape From Hell
*
* Note: Wasteland and Fountain of dreams *seem* to use the same engine, but it's not the case.
* Escape From Hell was written from scratch based on the visual look of the other
*/
namespace Efh {
static const uint8 kSavegameVersion = 1;
#define EFH_SAVE_HEADER MKTAG('E', 'F', 'H', 'S')
enum EfhDebugChannels {
kDebugEngine = 1,
kDebugUtils,
kDebugGraphics,
kDebugScript,
kDebugFight,
};
class EfhGraphicsStruct {
public:
EfhGraphicsStruct();
EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 width, int16 height);
int8 **_vgaLineBuffer;
uint16 _shiftValue;
uint16 _width;
uint16 _height;
Common::Rect _area;
void copy(EfhGraphicsStruct *src);
};
struct InvObject {
int16 _ref;
uint8 _stat1; // abbb bbbb - a: equipped b: uses left
uint8 _curHitPoints;
void init();
bool isEquipped();
int8 getUsesLeft();
};
struct MapSpecialTileStruct {
uint8 _placeId;
uint8 _posX;
uint8 _posY;
uint8 _triggerType; // 0xFD = Check inventory 0xFE = Check Character in team 0xFF Display description <= 0x77 = check score (all values in this case in data are <= 0xF)
uint8 _triggerValue;
uint16 _field5_textId;
uint16 _field7_textId;
void init();
};
struct FrameList {
int8 _subFileId[4];
void init();
};
struct AnimInfo {
uint16 _posX[10];
uint8 _posY[10];
FrameList _frameList[15];
void init();
};
struct ItemStruct {
char _name[15];
uint8 _damage;
uint8 _defense;
uint8 _attacks;
uint8 _uses;
int8 _agilityModifier; // data contains values from -8 to +8
uint8 _range;
uint8 _attackType;
uint8 _specialEffect;
uint8 _defenseType;
uint8 _exclusiveType;
uint8 _field19_mapPosX_or_maxDeltaPoints;
uint8 _mapPosY;
void init();
};
struct NPCStruct {
char _name[11];
uint8 fieldB_textId;
uint8 field_C;
uint8 field_D;
uint8 fieldE_textId;
uint8 field_F;
uint8 field_10;
uint8 field11_NpcId;
uint16 field12_textId;
uint16 field14_textId;
uint32 _xp;
uint8 _activeScore[15];
uint8 _passiveScore[11];
uint8 _infoScore[11];
uint8 field_3F;
uint8 field_40;
InvObject _inventory[10];
uint8 _possessivePronounSHL6;
uint8 _speed;
uint8 field_6B;
uint8 field_6C;
uint8 field_6D;
uint8 _defaultDefenseItemId;
uint8 field_6F;
uint8 field_70;
uint8 field_71;
uint8 field_72;
uint8 field_73;
int16 _hitPoints;
int16 _maxHP;
uint8 field_78;
uint16 field_79;
uint16 field_7B;
uint8 field_7D;
uint8 field_7E;
uint8 field_7F;
uint8 field_80;
uint8 field_81;
uint8 field_82;
uint8 field_83;
uint8 field_84;
uint8 field_85;
void init();
uint8 getPronoun();
void synchronize(Common::Serializer &s);
};
struct FontDescr {
const uint8 *_widthArray;
const uint8 *_extraLines;
const Font *_fontData;
uint8 _charHeight;
uint8 _extraVerticalSpace;
uint8 _extraHorizontalSpace;
};
struct BufferBM {
uint8 *_dataPtr;
uint16 _width;
uint16 _startX;
uint16 _startY;
uint16 _height;
uint16 _lineDataSize;
uint8 _paletteTransformation;
uint16 _fieldD;
};
struct CharStatus {
int16 _type;
int16 _duration;
};
struct MapMonster {
uint8 _possessivePronounSHL6; // aabb bbbb aa:Possessive Pronoun, bb bbbb: unknown
uint8 _npcId;
uint8 _fullPlaceId; // unsigned? Magic values are 0xFF and 0xFE
uint8 _posX;
uint8 _posY;
uint8 _weaponItemId;
uint8 _maxDamageAbsorption;
uint8 _monsterRef;
uint8 _additionalInfo; // abbb cddd a: special move flag, bbb: Pct modifier for random move, c aggressiveness, ddd move type
uint8 _talkTextId;
uint8 _groupSize;
int16 _hitPoints[9];
uint8 getPronoun();
};
struct InitiativeStruct {
int16 _id;
int16 _initiative;
void init();
};
struct TileFactStruct {
uint8 _status;
uint8 _tileId;
void init();
};
struct TeamChar {
int16 _id;
CharStatus _status;
int16 _pctVisible;
int16 _pctDodgeMiss;
int16 _nextAttack;
int16 _lastInventoryUsed;
int16 _lastAction;
void init();
};
struct TeamMonster {
int16 _id;
CharStatus _mobsterStatus[9];
void init();
};
enum TTSMenuRestriction {
kNoRestriction,
kLowStatusMenu,
kMenu
};
/* typed enum to match unsignedness of Common::CustomEventType */
enum EFHAction : Common::CustomEventType {
kActionNone,
kActionQuit,
kActionSkipVideo,
kActionSkipSong,
kActionSkipSongAndIntro,
kActionSave,
kActionLoad,
kActionMoveUp,
kActionMoveDown,
kActionMoveLeft,
kActionMoveRight,
kActionMoveUpLeft,
kActionMoveUpRight,
kActionMoveDownLeft,
kActionMoveDownRight,
kActionCharacter1Status,
kActionCharacter2Status,
kActionCharacter3Status,
kActionYes,
kActionNo,
kActionCharacter1,
kActionCharacter2,
kActionCharacter3,
kActionCancelCharacterSelection,
kActionStartFight,
kActionLeave,
kActionStatus,
kActionTalk,
kActionAttack,
kActionDefend,
kActionHide,
kActionRun,
kActionTeamStatus,
kActionTerrain,
kActionEnemy1,
kActionEnemy2,
kActionEnemy3,
kActionEnemy4,
kActionEnemy5,
kActionCancelEnemySelection,
kActionreset,
kActionExitStatusMenu,
kActionActive,
kActionDrop,
kActionEquip,
kActionGive,
kActionInfo,
kActionPassive,
kActionTrade,
kActionUse,
kActionSelect,
kActionScrollDown,
kActionScrollUp,
kActionExitSubMenu,
kActionOption1,
kActionOption2,
kActionOption3,
kActionOption4,
kActionOption5,
kActionOption6,
kActionOption7,
kActionOption8,
kActionOption9,
kActionOption10,
kActionOption11,
kActionOption12,
kActionOption13,
kActionOption14,
kActionSound13,
kActionSound14,
kActionSound15,
kActionSound5,
kActionSound10,
kActionSound9,
kActionSound16,
};
struct EfhSelectionAction {
EFHAction _action;
int8 _id;
};
static const EfhSelectionAction _efhEnemySelectionCodes[] = {
{ kActionEnemy1, 0 },
{ kActionEnemy2, 1 },
{ kActionEnemy3, 2 },
{ kActionEnemy4, 3 },
{ kActionEnemy5, 4 },
};
static const EfhSelectionAction _efhTeamSelectionCodes[] = {
{ kActionCharacter1, 0 },
{ kActionCharacter2, 1 },
{ kActionCharacter3, 2 },
};
static const EfhSelectionAction _efhStatusMenuSubMenuCodes[] = {
{ kActionOption1, 0 },
{ kActionOption2, 1 },
{ kActionOption3, 2 },
{ kActionOption4, 3 },
{ kActionOption5, 4 },
{ kActionOption6, 5 },
{ kActionOption7, 6 },
{ kActionOption8, 7 },
{ kActionOption9, 8 },
{ kActionOption10, 9 },
{ kActionOption11, 10 },
{ kActionOption12, 11 },
{ kActionOption13, 12 },
{ kActionOption14, 13 },
};
enum EfhKeymapCode {
kKeymapDefault,
kKeymapMenu,
kKeymapSkipVideo,
kKeymapSkipSong,
kKeymapStatusMenu,
kKeymapStatusMenuNavigation,
kKeymapStatusMenuSubMenu,
kKeymapInteraction,
kKeymapFight,
kKeymapCharacterSelection,
kKeymapEnemySelection,
kKeymapDeathMenu,
};
struct EfhKeymap {
EfhKeymapCode _keymap;
const char *_id;
};
static const EfhKeymap _efhKeymaps[] = {
{ kKeymapDefault, "efh-default" },
{ kKeymapMenu, "menu" },
{ kKeymapSkipVideo, "skip-video" },
{ kKeymapSkipSong, "skip-song" },
{ kKeymapStatusMenu, "status-menu" },
{ kKeymapStatusMenuNavigation, "status-menu-navigation" },
{ kKeymapStatusMenuSubMenu, "status-menu-submenu" },
{ kKeymapInteraction, "interaction" },
{ kKeymapFight, "fight" },
{ kKeymapCharacterSelection, "character-selection" },
{ kKeymapEnemySelection, "enemy-selection" },
{ kKeymapDeathMenu, "death-menu" },
};
class EfhEngine : public Engine {
public:
EfhEngine(OSystem *syst, const ADGameDescription *gd);
~EfhEngine() override;
Graphics::Surface *_mainSurface;
Common::RandomSource *_rnd;
const ADGameDescription *_gameDescription;
// metaengine.cpp
void initGame(const ADGameDescription *gd);
uint32 getFeatures() const;
const char *getGameId() const;
Common::Platform getPlatform() const;
bool hasFeature(EngineFeature f) const override;
const char *getCopyrightString() const;
// savegames.cpp
Common::String getSavegameFilename(int slot);
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error loadGameState(int slot) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
protected:
int _lastTime;
// Engine APIs
Common::Error run() override;
private:
Common::Platform _platform;
int _loadSaveSlot;
bool _saveAuthorized;
void initialize();
void playIntro();
void initEngine();
void initMapMonsters();
void saveAnimImageSetId();
int16 getEquipmentDefense(int16 charId);
uint16 getEquippedExclusiveType(int16 charId, int16 exclusiveType, bool flag);
void displayLowStatusScreen(bool flag);
void loadImageSetToTileBank(int16 bankId, int16 setId);
void restoreAnimImageSetId();
void checkProtection();
void loadEfhGame();
void copyCurrentPlaceToBuffer(int16 id);
uint8 getMapTileInfo(int16 mapPosX, int16 mapPosY);
uint16 getStringWidth(const Common::String &str) const;
void setTextPos(int16 textPosX, int16 textPosY);
void drawGameScreenAndTempText(bool flag);
void drawMap(bool largeMapFl, int16 mapPosX, int16 mapPosY, int16 mapSize, bool drawHeroFl, bool drawMonstersFl);
void displaySmallMap(int16 posX, int16 posY);
void displayLargeMap(int16 posX, int16 posY);
void drawScreen();
void removeObject(int16 charId, int16 objectId);
void totalPartyKill();
void removeCharacterFromTeam(int16 teamMemberId);
void refreshTeamSize();
bool isNpcATeamMember(int16 id);
void handleWinSequence();
bool giveItemTo(int16 charId, int16 objectId, int16 fromCharId);
int16 chooseCharacterToReplace();
int16 handleCharacterJoining();
void drawText(uint8 *srcPtr, int16 posX, int16 posY, int16 maxX, int16 maxY, bool flag);
void displayMiddleLeftTempText(uint8 *impArray, bool flag);
void transitionMap(int16 centerX, int16 centerY);
void setSpecialTechZone(int16 unkId, int16 centerX, int16 centerY);
int16 findMapSpecialTileIndex(int16 posX, int16 posY);
bool isPosOutOfMap(int16 mapPosX, int16 mapPosY);
void goSouth();
void goNorth();
void goEast();
void goWest();
void goNorthEast();
void goSouthEast();
void goNorthWest();
void goSouthWest();
void showCharacterStatus(uint8 character);
void handleNewRoundEffects();
void resetGame();
void computeMapAnimation();
void handleAnimations();
void handleEvents();
int8 checkMonsterMoveCollisionAndTileTexture(int16 monsterId);
bool moveMonsterAwayFromTeam(int16 monsterId);
bool moveMonsterTowardsTeam(int16 monsterId);
bool moveMonsterGroupOther(int16 monsterId, int16 direction);
bool moveMonsterGroupRandom(int16 monsterId);
int16 computeMonsterGroupDistance(int16 monsterId);
bool checkWeaponRange(int16 monsterId, int16 weaponId);
bool checkMonsterMovementType(int16 id, bool teamFlag);
bool checkTeamWeaponRange(int16 monsterId);
bool checkIfMonsterOnSameLargeMapPlace(int16 monsterId);
bool checkMonsterWeaponRange(int16 monsterId);
void handleMapMonsterMoves();
bool checkMapMonsterAvailability(int16 monsterId);
void displayMonsterAnim(int16 monsterId);
int16 countAliveMonsters(int16 id);
bool checkMonsterGroupDistance1OrLess(int16 monsterId);
bool handleTalk(int16 monsterId, int16 arg2, int16 itemId);
void startTalkMenu(int16 monsterId);
void displayImp1Text(int16 textId);
bool handleInteractionText(int16 mapPosX, int16 mapPosY, int16 charId, int16 itemId, int16 arg8, int16 imageSetId);
int8 checkTileStatus(int16 mapPosX, int16 mapPosY, bool teamFl);
void computeInitiatives();
void redrawScreenForced();
int16 countMonsterGroupMembers(int16 monsterGroup);
uint16 getXPLevel(uint32 xp);
bool isItemCursed(int16 itemId);
bool hasObjectEquipped(int16 charId, int16 objectId);
void setMapMonsterAggressivenessAndMovementType(int16 id, uint8 mask);
bool isMonsterActive(int16 groupId, int16 id);
int16 getTileFactId(int16 mapPosX, int16 mapPosY);
void setCharacterObjectToBroken(int16 charId, int16 objectId);
int16 selectOtherCharFromTeam();
bool checkMonsterCollision();
// Fight
bool handleFight(int16 monsterId);
void handleFight_checkEndEffect(int16 charId);
void handleFight_lastAction_A(int16 teamCharId);
void handleFight_lastAction_D(int16 teamCharId);
void handleFight_lastAction_H(int16 teamCharId);
bool handleFight_lastAction_U(int16 teamCharId);
void handleFight_MobstersAttack(int groupId);
bool isTPK();
bool isMonsterAlreadyFighting(int16 monsterId, int16 teamMonsterId);
void createOpponentList(int16 monsterTeamId);
void resetTeamMonsterEffects();
void initFight(int16 monsterId);
void resetTeamMonsterIdArray();
bool isTeamMemberStatusNormal(int16 id);
void getDeathTypeDescription(int16 victimId, int16 attackerId);
int16 determineTeamTarget(int16 charId, int16 unkFied18Val, bool checkDistanceFl);
bool getTeamAttackRoundPlans();
void drawCombatScreen(int16 charId, bool whiteFl, bool drawFl);
void getXPAndSearchCorpse(int16 charId, Common::String namePt1, Common::String namePt2, int16 monsterId);
bool characterSearchesMonsterCorpse(int16 charId, int16 monsterId);
void addReactionText(int16 id);
void displayEncounterInfo(bool WhiteFl);
int16 getWeakestMobster(int16 groupNumber);
int16 getCharacterScore(int16 charId, int16 itemId);
bool checkSpecialItemsOnCurrentPlace(int16 itemId);
bool hasAdequateDefense(int16 monsterId, uint8 attackType);
bool hasAdequateDefenseNPC(int16 charId, uint8 attackType);
void addNewOpponents(int16 monsterId);
int16 getTeamMonsterAnimId();
int16 selectMonsterGroup();
void redrawCombatScreenWithTempText(int16 charId);
void handleDamageOnArmor(int16 charId, int16 damage);
// Files
int32 readFileToBuffer(const Common::Path &filename, uint8 *destBuffer);
void readAnimInfo();
void findMapFile(int16 mapId);
void rImageFile(const Common::Path &filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer);
void readItems();
void readImpFile(int16 id, bool techMapFl);
void loadNewPortrait();
void loadAnimImageSet();
void loadHistory();
void loadTechMapImp(int16 fileId);
void loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl);
void readTileFact();
void loadNPCS();
void preLoadMaps();
// Graphics
void initPalette();
void drawLeftCenterBox();
void displayNextAnimFrame();
void displayAnimFrame();
void displayAnimFrames(int16 animId, bool displayMenuBoxFl);
void displayFctFullScreen();
void copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY);
void copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y);
void displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY);
void drawRect(int16 minX, int16 minY, int16 maxX, int16 maxY);
void drawColoredRect(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color);
void clearScreen(int16 color);
void displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY);
void drawString(const Common::String &str, int16 startX, int16 startY, uint16 textColor);
void displayCenteredString(const Common::String &str, int16 minX, int16 maxX, int16 posY);
void displayMenuAnswerString(const Common::String &str, int16 minX, int16 maxX, int16 posY);
void drawMapWindow();
void displayGameScreen();
void drawUpperLeftBorders();
void drawUpperRightBorders();
void drawBottomBorders();
void drawChar(uint8 curChar, int16 posX, int16 posY);
void setTextColorWhite();
void setTextColorRed();
void setTextColorGrey();
void displayStringAtTextPos(const Common::String &message);
void clearBottomTextZone(int16 color);
void clearBottomTextZone_2(int16 color);
void setNextCharacterPos();
void displayCharAtTextPos(char character);
void displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest);
void displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color);
// Menu
int16 displayBoxWithText(const Common::String &str, int16 menuType, int16 displayOption, bool displayTeamWindowFl, bool voiceText = true);
bool handleDeathMenu();
void displayCombatMenu(int16 charId);
void displayMenuItemString(int16 menuBoxId, int16 thisBoxId, int16 minX, int16 maxX, int16 minY, const char *str);
void displayStatusMenu(int16 windowId);
void prepareStatusRightWindowIndexes(int16 menuId, int16 charId);
void displayCharacterSummary(int16 curMenuLine, int16 npcId);
void displayCharacterInformationOrSkills(int16 curMenuLine, int16 npcId);
void displayStatusMenuActions(int16 menuId, int16 curMenuLine, int16 npcId);
void prepareStatusMenu(int16 windowId, int16 menuId, int16 curMenuLine, int16 charId, bool refreshFl);
void displayWindowAndStatusMenu(int16 charId, int16 windowId, int16 menuId, int16 curMenuLine);
int16 displayStringInSmallWindowWithBorder(const Common::String &str, bool delayFl, int16 charId, int16 windowId, int16 menuId, int16 curMenuLine);
int16 handleStatusMenu(int16 gameMode, int16 charId);
void unequipItem(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine);
void tryToggleEquipped(int16 charId, int16 objectId, int16 windowId, int16 menuId, int16 curMenuLine);
int16 useObject(int16 charId, int16 objectId, int16 teamMonsterId, int16 menuId, int16 curMenuLine, int16 gameMode);
// Savegames
void synchronize(Common::Serializer &s);
// Script
const uint8 *script_readNumberArray(const uint8 *buffer, int16 destArraySize, int16 *destArray);
const uint8 *script_getNumber(const uint8 *srcBuffer, int16 *retBuf);
int16 script_parse(Common::String str, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag);
// Sound
void songDelay(int delay);
void playNote(int frequencyIndex, int totalDelay);
Common::CustomEventType playSong(uint8 *buffer);
void generateSound1(int lowFreq, int highFreq, int duration);
void generateSound2(int startFreq, int endFreq, int speed);
void generateSound3();
void generateSound4(int repeat);
void generateSound5(int repeat);
void generateSound(int16 soundType);
void genericGenerateSound(int16 soundType, int16 repeatCount);
void sayText(const Common::String &text, TTSMenuRestriction menuRestriction, Common::TextToSpeechManager::Action action = Common::TextToSpeechManager::QUEUE) const;
void stopTextToSpeech() const;
// Utils
void decryptImpFile(bool techMapFl);
void loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer);
uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf);
int16 getRandom(int16 maxVal);
Common::CustomEventType getLastCharAfterAnimCount(int16 delay, bool waitForTTS = true);
Common::CustomEventType getInput(int16 delay);
Common::CustomEventType waitForKey();
Common::CustomEventType handleAndMapInput(bool animFl);
bool getValidationFromUser();
uint32 ROR(uint32 val, uint8 shiftVal);
Common::String getArticle(int pronoun);
void setKeymap(EfhKeymapCode keymapCode);
// Actions
void handleActionSave();
void handleActionLoad();
uint8 _videoMode;
uint8 _bufferCharBM[128];
int8 *_vgaLineBuffer[200];
EfhGraphicsStruct *_vgaGraphicsStruct1;
EfhGraphicsStruct *_vgaGraphicsStruct2;
EfhGraphicsStruct *_graphicsStruct;
uint8 _tileBank[3][12000];
uint8 _circleImageBuf[40100];
uint8 _portraitBuf[25000];
uint8 _decompBuf[40100];
uint8 _menuBuf[12500];
uint8 _windowWithBorderBuf[1500];
uint8 _mapArr[19][7000];
uint8 _places[12000];
uint8 _curPlace[24][24];
NPCStruct _npcBuf[100];
uint8 _imp1[13000];
uint8 _imp2[10000];
uint8 _titleSong[1024];
ItemStruct _items[300];
TileFactStruct _tileFact[432];
AnimInfo _animInfo[100];
uint8 _history[256];
uint8 _techDataArr[19][4100];
Common::String _enemyNamePt1;
Common::String _enemyNamePt2;
Common::String _characterNamePt1;
Common::String _characterNamePt2;
Common::String _nameBuffer;
Common::String _attackBuffer;
Common::String _messageToBePrinted;
struct BitmapRef {
int8 _setId1;
int8 _setId2;
};
BitmapRef _mapBitmapRefArr[19];
MapSpecialTileStruct _mapSpecialTiles[19][100];
MapMonster _mapMonsters[19][64];
uint8 _mapGameMaps[19][64][64];
uint8 _defaultBoxColor;
FontDescr _fontDescr;
bool _introDoneFl;
uint16 _textColor;
int16 _oldAnimImageSetId;
int16 _animImageSetId;
uint8 _paletteTransformationConstant;
uint8 *_circleImageSubFileArray[12];
uint8 *_tileBankSubFilesArray[216];
BufferBM _imageDataPtr;
int16 _currentTileBankImageSetId[3];
int16 _unkRelatedToAnimImageSetId;
int16 _techId;
int16 _currentAnimImageSetId;
uint8 *_portraitSubFilesArray[20];
int16 _unkAnimRelatedIndex;
uint8 *_imp1PtrArray[100];
uint8 *_imp2PtrArray[432];
uint16 _fullPlaceId;
int16 _guessAnimationAmount;
uint16 _largeMapFlag; // CHECKME: bool?
int16 _textPosX;
int16 _textPosY;
Common::Rect _initRect;
bool _engineInitPending;
bool _protectionPassed;
int16 _alertDelay;
int16 _teamSize;
int16 _word2C872;
bool _checkTileDisabledByScriptFl;
bool _redrawNeededFl;
bool _drawHeroOnMapFl;
bool _drawMonstersOnMapFl;
bool _textBoxDisabledByScriptFl;
int16 _imageSetSubFilesIdx;
int16 _oldImageSetSubFilesIdx;
int16 _mapPosX, _mapPosY;
int16 _oldMapPosX, _oldMapPosY;
int16 _techDataId_MapPosX, _techDataId_MapPosY;
uint16 _lastMainPlaceId;
uint16 _tempTextDelay;
uint8 *_tempTextPtr;
bool _ongoingFightFl;
bool _statusMenuActive;
int16 _menuStatItemArr[15];
int16 _menuDepth;
int16 _menuItemCounter;
int16 _selectedMenuBox;
bool _sayMenu;
bool _sayLowStatusScreen;
bool _initiatedTalkByMenu;
TeamChar _teamChar[3];
TeamMonster _teamMonster[5];
InitiativeStruct _initiatives[8];
int16 _regenCounter;
Audio::PCSpeaker *_speaker;
};
} // End of namespace Efh
#endif

1799
engines/efh/fight.cpp Normal file

File diff suppressed because it is too large Load Diff

388
engines/efh/files.cpp Normal file
View File

@@ -0,0 +1,388 @@
/* 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 "common/config-manager.h"
#include "efh/efh.h"
namespace Efh {
int32 EfhEngine::readFileToBuffer(const Common::Path &filename, uint8 *destBuffer) {
debugC(1, kDebugUtils, "readFileToBuffer %s", filename.toString().c_str());
Common::File f;
if (!f.open(filename))
error("Unable to find file %s", filename.toString().c_str());
int size = f.size();
return f.read(destBuffer, size);
}
void EfhEngine::readAnimInfo() {
debugC(6, kDebugEngine, "readAnimInfo");
Common::Path fileName("animinfo");
Common::File f;
if (!f.open(fileName))
error("Unable to find file %s", fileName.toString().c_str());
for (int i = 0; i < 100; ++i) {
for (int id = 0; id < 15; ++id) {
Common::String txtBuffer = "->";
for (int frameId = 0; frameId < 4; ++frameId) {
_animInfo[i]._frameList[id]._subFileId[frameId] = f.readByte();
txtBuffer += Common::String::format(" %d", _animInfo[i]._frameList[id]._subFileId[frameId]);
}
debugC(6, kDebugEngine, "%s", txtBuffer.c_str());
}
Common::String debugStr = "";
for (int id = 0; id < 10; ++id) {
_animInfo[i]._posY[id] = f.readByte();
debugStr += Common::String::format("%d ", _animInfo[i]._posY[id]);
}
debugC(6, kDebugEngine, "%s", debugStr.c_str());
debugStr = "";
for (int id = 0; id < 10; ++id) {
_animInfo[i]._posX[id] = f.readUint16LE();
debugStr += Common::String::format("%d ", _animInfo[i]._posX[id]);
}
debugC(6, kDebugEngine, "%s", debugStr.c_str());
debugC(6, kDebugEngine, "---------");
}
}
void EfhEngine::findMapFile(int16 mapId) {
debugC(7, kDebugEngine, "findMapFile %d", mapId);
if (!_introDoneFl)
return;
Common::Path fileName(Common::String::format("map.%d", mapId));
Common::File f;
// The original was checking for the file and eventually asking to change floppies
if (!f.open(fileName))
error("File not found: %s", fileName.toString().c_str());
f.close();
}
void EfhEngine::rImageFile(const Common::Path &filename, uint8 *targetBuffer, uint8 **subFilesArray, uint8 *packedBuffer) {
debugC(1, kDebugUtils, "rImageFile %s", filename.toString().c_str());
readFileToBuffer(filename, packedBuffer);
uint32 size = uncompressBuffer(packedBuffer, targetBuffer);
if (ConfMan.getBool("dump_scripts")) {
// dump a decompressed image file
Common::DumpFile dump;
dump.open(filename.append(".dump"));
dump.write(targetBuffer, size);
dump.flush();
dump.close();
// End of dump
}
// TODO: Refactoring: once uncompressed, the container contains for each image its width, its height, and raw data (4 Bpp)
// => Write a class to handle that more properly
uint8 *ptr = targetBuffer;
uint16 counter = 0;
while (READ_LE_INT16(ptr) != 0 && !shouldQuit()) {
subFilesArray[counter] = ptr;
++counter;
int16 imageWidth = READ_LE_INT16(ptr);
ptr += 2;
int16 imageHeight = READ_LE_INT16(ptr);
ptr += 2;
ptr += (imageWidth * imageHeight);
}
}
void EfhEngine::readImpFile(int16 id, bool techMapFl) {
debugC(6, kDebugEngine, "readImpFile %d %s", id, techMapFl ? "True" : "False");
Common::Path fileName(Common::String::format("imp.%d", id));
if (techMapFl)
readFileToBuffer(fileName, _imp1);
else
readFileToBuffer(fileName, _imp2);
decryptImpFile(techMapFl);
}
void EfhEngine::readItems() {
debugC(7, kDebugEngine, "readItems");
Common::Path fileName("items");
Common::File f;
if (!f.open(fileName))
error("Unable to find file %s", fileName.toString().c_str());
for (int i = 0; i < 300; ++i) {
for (uint idx = 0; idx < 15; ++idx)
_items[i]._name[idx] = f.readByte();
_items[i]._damage = f.readByte();
_items[i]._defense = f.readByte();
_items[i]._attacks = f.readByte();
_items[i]._uses = f.readByte();
_items[i]._agilityModifier = f.readByte();
_items[i]._range = f.readByte();
_items[i]._attackType = f.readByte();
_items[i]._specialEffect = f.readByte();
_items[i]._defenseType = f.readByte();
_items[i]._exclusiveType = f.readByte();
_items[i]._field19_mapPosX_or_maxDeltaPoints = f.readByte();
_items[i]._mapPosY = f.readByte();
debugC(7, kDebugEngine, "%s\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x", _items[i]._name, _items[i]._damage, _items[i]._defense, _items[i]._attacks, _items[i]._uses, _items[i]._agilityModifier, _items[i]._range, _items[i]._attackType, _items[i]._specialEffect, _items[i]._defenseType, _items[i]._exclusiveType, _items[i]._field19_mapPosX_or_maxDeltaPoints, _items[i]._mapPosY);
}
}
void EfhEngine::loadNewPortrait() {
debugC(7, kDebugEngine, "loadNewPortrait");
static int16 const unkConstRelatedToAnimImageSetId[19] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2};
_unkRelatedToAnimImageSetId = unkConstRelatedToAnimImageSetId[_techId];
if (_currentAnimImageSetId == 200 + _unkRelatedToAnimImageSetId)
return;
findMapFile(_techId);
_currentAnimImageSetId = 200 + _unkRelatedToAnimImageSetId;
int imageSetId = _unkRelatedToAnimImageSetId + 13;
loadImageSet(imageSetId, _portraitBuf, _portraitSubFilesArray, _decompBuf);
}
void EfhEngine::loadAnimImageSet() {
debugC(3, kDebugEngine, "loadAnimImageSet");
if (_currentAnimImageSetId == _animImageSetId || _animImageSetId == 0xFF)
return;
findMapFile(_techId);
_unkAnimRelatedIndex = 0;
_currentAnimImageSetId = _animImageSetId;
int16 animSetId = _animImageSetId + 17;
loadImageSet(animSetId, _portraitBuf, _portraitSubFilesArray, _decompBuf);
}
void EfhEngine::loadHistory() {
debugC(2, kDebugEngine, "loadHistory");
Common::Path fileName("history");
readFileToBuffer(fileName, _history);
}
void EfhEngine::loadTechMapImp(int16 fileId) {
debugC(3, kDebugEngine, "loadTechMapImp %d", fileId);
if (fileId == 0xFF)
return;
_techId = fileId;
findMapFile(_techId);
// The original was loading the specific tech.%d and map.%d files.
// This is gone in our implementation as we pre-load all the files to save them inside the savegames
loadImageSetToTileBank(0, _mapBitmapRefArr[_techId]._setId1);
loadImageSetToTileBank(1, _mapBitmapRefArr[_techId]._setId2);
initMapMonsters();
readImpFile(_techId, true);
displayAnimFrames(0xFE, false);
}
void EfhEngine::loadPlacesFile(uint16 fullPlaceId, bool forceReloadFl) {
debugC(2, kDebugEngine, "loadPlacesFile %d %s", fullPlaceId, forceReloadFl ? "True" : "False");
if (fullPlaceId == 0xFF)
return;
findMapFile(_techId);
_fullPlaceId = fullPlaceId;
uint16 minPlace = _lastMainPlaceId * 20;
uint16 maxPlace = minPlace + 19;
if (_fullPlaceId < minPlace || _fullPlaceId > maxPlace || forceReloadFl) {
_lastMainPlaceId = _fullPlaceId / 20;
Common::Path fileName(Common::String::format("places.%d", _lastMainPlaceId));
readFileToBuffer(fileName, _decompBuf);
uncompressBuffer(_decompBuf, _places);
}
copyCurrentPlaceToBuffer(_fullPlaceId % 20);
}
void EfhEngine::readTileFact() {
debugC(7, kDebugEngine, "readTileFact");
Common::Path fileName("tilefact");
Common::File f;
if (!f.open(fileName))
error("Unable to find file %s", fileName.toString().c_str());
for (int i = 0; i < 432; ++i) {
_tileFact[i]._status = f.readByte();
_tileFact[i]._tileId = f.readByte();
}
}
void EfhEngine::loadNPCS() {
debugC(7, kDebugEngine, "loadNPCS");
Common::Path fileName("npcs");
Common::File f;
if (!f.open(fileName))
error("Unable to find file %s", fileName.toString().c_str());
for (int i = 0; i < 99; ++i) {
for (int idx = 0; idx < 11; ++idx)
_npcBuf[i]._name[idx] = f.readByte();
_npcBuf[i].fieldB_textId = f.readByte();
_npcBuf[i].field_C = f.readByte();
_npcBuf[i].field_D = f.readByte();
_npcBuf[i].fieldE_textId = f.readByte();
_npcBuf[i].field_F = f.readByte();
_npcBuf[i].field_10 = f.readByte();
_npcBuf[i].field11_NpcId = f.readByte();
_npcBuf[i].field12_textId = f.readUint16LE();
_npcBuf[i].field14_textId = f.readUint16LE();
_npcBuf[i]._xp = f.readUint32LE();
for (int idx = 0; idx < 15; ++idx) {
_npcBuf[i]._activeScore[idx] = f.readByte();
}
for (int idx = 0; idx < 11; ++idx) {
_npcBuf[i]._passiveScore[idx] = f.readByte();
}
for (int idx = 0; idx < 11; ++idx) {
_npcBuf[i]._infoScore[idx] = f.readByte();
}
_npcBuf[i].field_3F = f.readByte();
_npcBuf[i].field_40 = f.readByte();
for (int idx = 0; idx < 10; ++idx) {
_npcBuf[i]._inventory[idx]._ref = f.readSint16LE();
_npcBuf[i]._inventory[idx]._stat1 = f.readByte();
_npcBuf[i]._inventory[idx]._curHitPoints = f.readByte();
}
_npcBuf[i]._possessivePronounSHL6 = f.readByte();
_npcBuf[i]._speed = f.readByte();
_npcBuf[i].field_6B = f.readByte();
_npcBuf[i].field_6C = f.readByte();
_npcBuf[i].field_6D = f.readByte();
_npcBuf[i]._defaultDefenseItemId = f.readByte();
_npcBuf[i].field_6F = f.readByte();
_npcBuf[i].field_70 = f.readByte();
_npcBuf[i].field_71 = f.readByte();
_npcBuf[i].field_72 = f.readByte();
_npcBuf[i].field_73 = f.readByte();
_npcBuf[i]._hitPoints = f.readSint16LE();
_npcBuf[i]._maxHP = f.readSint16LE();
_npcBuf[i].field_78 = f.readByte();
_npcBuf[i].field_79 = f.readUint16LE();
_npcBuf[i].field_7B = f.readUint16LE();
_npcBuf[i].field_7D = f.readByte();
_npcBuf[i].field_7E = f.readByte();
_npcBuf[i].field_7F = f.readByte();
_npcBuf[i].field_80 = f.readByte();
_npcBuf[i].field_81 = f.readByte();
_npcBuf[i].field_82 = f.readByte();
_npcBuf[i].field_83 = f.readByte();
_npcBuf[i].field_84 = f.readByte();
_npcBuf[i].field_85 = f.readByte();
}
}
/**
* Pre-Loads MAP and TECH files.
* This is required in order to implement a clean savegame feature
*/
void EfhEngine::preLoadMaps() {
Common::DumpFile dump;
if (ConfMan.getBool("dump_scripts"))
dump.open("efhMaps.dump");
for (int idx = 0; idx < 19; ++idx) {
Common::Path fileName(Common::String::format("tech.%d", idx));
readFileToBuffer(fileName, _decompBuf);
uncompressBuffer(_decompBuf, _techDataArr[idx]);
fileName = Common::Path(Common::String::format("map.%d", idx));
readFileToBuffer(fileName, _decompBuf);
uncompressBuffer(_decompBuf, _mapArr[idx]);
_mapBitmapRefArr[idx]._setId1 = _mapArr[idx][0];
_mapBitmapRefArr[idx]._setId2 = _mapArr[idx][1];
uint8 *mapSpecialTilePtr = &_mapArr[idx][2];
for (int i = 0; i < 100; ++i) {
_mapSpecialTiles[idx][i]._placeId = mapSpecialTilePtr[9 * i];
_mapSpecialTiles[idx][i]._posX = mapSpecialTilePtr[9 * i + 1];
_mapSpecialTiles[idx][i]._posY = mapSpecialTilePtr[9 * i + 2];
_mapSpecialTiles[idx][i]._triggerType = mapSpecialTilePtr[9 * i + 3];
_mapSpecialTiles[idx][i]._triggerValue = mapSpecialTilePtr[9 * i + 4];
_mapSpecialTiles[idx][i]._field5_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 5]);
_mapSpecialTiles[idx][i]._field7_textId = READ_LE_UINT16(&mapSpecialTilePtr[9 * i + 7]);
if (ConfMan.getBool("dump_scripts") && _mapSpecialTiles[idx][i]._placeId != 0xFF) {
// dump a decoded version of the maps
Common::String buffer = Common::String::format("[%d][%d] _ placeId: 0x%02X _pos: %d, %d _triggerType: 0x%02X (%d), triggerId: %d, _field5/7: %d %d\n"
, idx, i, _mapSpecialTiles[idx][i]._placeId, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._posX, _mapSpecialTiles[idx][i]._triggerType
, _mapSpecialTiles[idx][i]._triggerType, _mapSpecialTiles[idx][i]._triggerValue, _mapSpecialTiles[idx][i]._field5_textId, _mapSpecialTiles[idx][i]._field7_textId);
dump.write(buffer.c_str(), buffer.size());
}
}
uint8 *mapMonstersPtr = &_mapArr[idx][902];
for (int i = 0; i < 64; ++i) {
_mapMonsters[idx][i]._possessivePronounSHL6 = mapMonstersPtr[29 * i];
_mapMonsters[idx][i]._npcId = mapMonstersPtr[29 * i + 1];
_mapMonsters[idx][i]._fullPlaceId = mapMonstersPtr[29 * i + 2];
_mapMonsters[idx][i]._posX = mapMonstersPtr[29 * i + 3];
_mapMonsters[idx][i]._posY = mapMonstersPtr[29 * i + 4];
_mapMonsters[idx][i]._weaponItemId = mapMonstersPtr[29 * i + 5];
_mapMonsters[idx][i]._maxDamageAbsorption = mapMonstersPtr[29 * i + 6];
_mapMonsters[idx][i]._monsterRef = mapMonstersPtr[29 * i + 7];
_mapMonsters[idx][i]._additionalInfo = mapMonstersPtr[29 * i + 8];
_mapMonsters[idx][i]._talkTextId = mapMonstersPtr[29 * i + 9];
_mapMonsters[idx][i]._groupSize = mapMonstersPtr[29 * i + 10];
for (int j = 0; j < 9; ++j)
_mapMonsters[idx][i]._hitPoints[j] = READ_LE_INT16(&mapMonstersPtr[29 * i + 11 + j * 2]);
}
uint8 *mapPtr = &_mapArr[idx][2758];
for (int i = 0; i < 64; ++i) {
for (int j = 0; j < 64; ++j)
_mapGameMaps[idx][i][j] = *mapPtr++;
}
}
if (ConfMan.getBool("dump_scripts")) {
dump.flush();
dump.close();
}
}
} // End of namespace Efh

416
engines/efh/graphics.cpp Normal file
View File

@@ -0,0 +1,416 @@
/* 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 "graphics/paletteman.h"
#include "common/system.h"
#include "efh/efh.h"
namespace Efh {
void EfhEngine::initPalette() {
// Strangerke - values from a tool I wrote in 2008. I can't remember if it's guess work or not.
static const uint8 pal[3 * 16] = {
0x00, 0x00, 0x00,
0x00, 0x00, 0xAA,
0x00, 0xAA, 0x00,
0x00, 0xAA, 0xAA,
0xAA, 0x00, 0x00,
0xAA, 0x00, 0xAA,
0xAA, 0x55, 0x00,
0xAA, 0xAA, 0xAA,
0x55, 0x55, 0x55,
0x55, 0x55, 0xFF,
0x01, 0x01, 0x01, // Color 0xA is for transparency
0x55, 0xFF, 0xFF,
0xFF, 0x55, 0x55,
0xFF, 0x55, 0xFF,
0xFF, 0xFF, 0x55,
0xFF, 0xFF, 0xFF
};
debugC(1, kDebugGraphics, "initPalette");
_system->getPaletteManager()->setPalette(pal, 0, 16);
_system->updateScreen();
}
void EfhEngine::drawLeftCenterBox() {
debugC(1, kDebugGraphics, "drawLeftCenterBox");
drawColoredRect(16, 8, 111, 135, 0);
}
void EfhEngine::displayNextAnimFrame() {
debugC(6, kDebugGraphics, "displayNextAnimFrame");
if (++_unkAnimRelatedIndex >= 15)
_unkAnimRelatedIndex = 0;
displayAnimFrame();
}
void EfhEngine::displayAnimFrame() {
debugC(1, kDebugGraphics, "displayAnimFrame");
// The original had a parameter. As it was always equal to zero, it was removed in ScummVM
if (_animImageSetId == 0xFF)
return;
if (_animImageSetId == 0xFE) {
displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8);
return;
}
displayRawDataAtPos(_portraitSubFilesArray[0], 16, 8);
for (int i = 0; i < 4; ++i) {
int8 var2 = _animInfo[_animImageSetId]._frameList[_unkAnimRelatedIndex]._subFileId[i];
if (var2 == -1)
continue;
displayRawDataAtPos(_portraitSubFilesArray[var2 + 1], _animInfo[_animImageSetId]._posX[var2] + 16, _animInfo[_animImageSetId]._posY[var2] + 8);
}
}
void EfhEngine::displayAnimFrames(int16 animId, bool displayMenuBoxFl) {
debugC(1, kDebugGraphics, "displayAnimFrames %d %s", animId, displayMenuBoxFl ? "True" : "False");
if (animId == 0xFF)
return;
_animImageSetId = animId;
if (_animImageSetId == 0xFE)
loadNewPortrait();
else
loadAnimImageSet();
if (!displayMenuBoxFl)
return;
for (int i = 0; i < 2; ++i) {
drawLeftCenterBox();
displayAnimFrame();
if (i == 0)
displayFctFullScreen();
}
}
void EfhEngine::displayFctFullScreen() {
debugC(1, kDebugGraphics, "displayFctFullScreen");
// CHECKME: 319 is in the original but looks suspicious.
// copyDirtyRect(0, 0, 319, 200);
_system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
_system->updateScreen();
}
void EfhEngine::copyDirtyRect(int16 minX, int16 minY, int16 maxX, int16 maxY) {
_graphicsStruct->copy(_vgaGraphicsStruct2);
_initRect = Common::Rect(minX, minY, maxX, maxY);
copyGraphicBufferFromTo(_vgaGraphicsStruct2, _vgaGraphicsStruct1, _initRect, minX, minY);
}
void EfhEngine::copyGraphicBufferFromTo(EfhGraphicsStruct *efh_graphics_struct, EfhGraphicsStruct *efh_graphics_struct1, const Common::Rect &rect, int16 min_x, int16 min_y) {
warning("STUB - copyGraphicBufferFromTo");
}
void EfhEngine::displayBufferBmAtPos(BufferBM *bufferBM, int16 posX, int16 posY) {
debugC(1, kDebugGraphics, "displayBufferBmAtPos %d %d", posX, posY);
// CHECKME: Quick code to display stuff, may require to really reverse the actual function
uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY);
int counter = 0;
for (int line = 0; line < bufferBM->_height; ++line) {
for (int col = 0; col < bufferBM->_lineDataSize; ++col) { // _lineDataSize = _width / 2
if (bufferBM->_dataPtr[counter] >> 4 != 0xA)
destPtr[320 * line + 2 * col] = bufferBM->_dataPtr[counter] >> 4;
if ((bufferBM->_dataPtr[counter] & 0xF) != 0xA)
destPtr[320 * line + 2 * col + 1] = bufferBM->_dataPtr[counter] & 0xF;
++counter;
}
}
// _system->copyRectToScreen((uint8 *)_mainSurface->getPixels(), 320, 0, 0, 320, 200);
// _system->updateScreen();
}
void EfhEngine::drawRect(int16 minX, int16 minY, int16 maxX, int16 maxY) {
debugC(1, kDebugGraphics, "drawRect %d-%d %d-%d", minX, minY, maxX, maxY);
if (minY > maxY)
SWAP(minY, maxY);
if (minX > maxX)
SWAP(minX, maxX);
minX = CLIP<int16>(minX, 0, 319);
maxX = CLIP<int16>(maxX, 0, 319);
minY = CLIP<int16>(minY, 0, 199);
maxY = CLIP<int16>(maxY, 0, 199);
int deltaY = 1 + maxY - minY;
int deltaX = 1 + maxX - minX;
uint8 color = _defaultBoxColor & 0xF;
bool xorColor = (_defaultBoxColor & 0x40) != 0;
uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(minX, minY);
for (int line = 0; line < deltaY; ++line) {
for (int col = 0; col < deltaX; ++col) {
if (xorColor)
destPtr[320 * line + col] ^= color;
else
destPtr[320 * line + col] = color;
}
}
}
void EfhEngine::drawColoredRect(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color) {
debugC(1, kDebugGraphics, "drawColoredRect %d-%d %d-%d %d", minX, minY, maxX, maxY, color);
uint8 oldValue = _defaultBoxColor;
_defaultBoxColor = color;
drawRect(minX, minY, maxX, maxY);
_defaultBoxColor = oldValue;
}
void EfhEngine::clearScreen(int16 color) {
debugC(1, kDebugGraphics, "clearScreen %d", color);
drawColoredRect(0, 0, 320, 200, color);
}
void EfhEngine::displayRawDataAtPos(uint8 *imagePtr, int16 posX, int16 posY) {
debugC(1, kDebugGraphics, "displayRawDataAtPos %d %d", posX, posY);
uint16 height = READ_LE_INT16(imagePtr);
uint16 width = READ_LE_INT16(imagePtr + 2);
uint8 *imageData = imagePtr + 4;
_imageDataPtr._lineDataSize = width;
_imageDataPtr._dataPtr = imageData;
_imageDataPtr._height = height;
_imageDataPtr._width = width * 2; // 2 pixels per byte
_imageDataPtr._startX = _imageDataPtr._startY = 0;
displayBufferBmAtPos(&_imageDataPtr, posX, posY);
}
void EfhEngine::drawString(const Common::String &str, int16 startX, int16 startY, uint16 textColor) {
debugC(1, kDebugGraphics, "drawString %s %d %d %d", str.c_str(), startX, startY, textColor);
const uint8 *curPtr = (const uint8 *)str.c_str();
uint16 lineHeight = _fontDescr._charHeight + _fontDescr._extraVerticalSpace;
int16 minX = startX;
if (textColor & 0x8000) {
warning("STUB - drawString - 0x8000");
// int16 minY = startY; // Used in case 0x8000
// int16 var6 = _fontDescr._extraLines[0] + startY - 1; // Used in case 0x8000
}
for (uint curChar = *curPtr++; curChar != 0; curChar = *curPtr++) {
if (curChar == 0x0A) {
startX = minX;
startY += lineHeight;
continue;
}
if (curChar < 0x20)
continue;
uint16 characterId = (curChar + 0xE0) & 0xFF;
uint8 charWidth = _fontDescr._widthArray[characterId];
if (startX + charWidth >= 319) {
startX = minX;
startY += lineHeight;
}
uint8 varC = _fontDescr._extraLines[characterId];
drawChar(curChar, startX, startY + varC);
startX += charWidth + _fontDescr._extraHorizontalSpace;
}
}
void EfhEngine::displayCenteredString(const Common::String &str, int16 minX, int16 maxX, int16 posY) {
debugC(1, kDebugGraphics, "displayCenteredString %s %d-%d %d", str.c_str(), minX, maxX, posY);
uint16 length = getStringWidth(str);
int16 startCenteredDisplayX = minX + (maxX - minX - length) / 2;
drawString(str, startCenteredDisplayX, posY, _textColor);
}
void EfhEngine::displayMenuAnswerString(const Common::String &str, int16 minX, int16 maxX, int16 posY) {
debugC(1, kDebugGraphics, "displayMenuAnswerString %s %d-%d %d", str.c_str(), minX, maxX, posY);
displayCenteredString(str, minX, maxX, posY);
displayFctFullScreen();
displayCenteredString(str, minX, maxX, posY);
}
void EfhEngine::drawMapWindow() {
debugC(1, kDebugGraphics, "drawMapWindow");
drawColoredRect(128, 8, 303, 135, 0);
}
void EfhEngine::displayGameScreen() {
debugC(1, kDebugGraphics, "displayGameScreen");
clearScreen(0);
drawUpperLeftBorders();
drawUpperRightBorders();
drawBottomBorders();
displayAnimFrame();
displayLowStatusScreen(false);
}
void EfhEngine::drawUpperLeftBorders() {
debugC(1, kDebugGraphics, "drawUpperLeftBorders");
displayRawDataAtPos(_circleImageSubFileArray[0], 0, 0);
displayRawDataAtPos(_circleImageSubFileArray[1], 112, 0);
displayRawDataAtPos(_circleImageSubFileArray[3], 16, 0);
}
void EfhEngine::drawUpperRightBorders() {
debugC(1, kDebugGraphics, "drawUpperRightBorders");
displayRawDataAtPos(_circleImageSubFileArray[2], 304, 0);
displayRawDataAtPos(_circleImageSubFileArray[4], 128, 0);
}
void EfhEngine::drawBottomBorders() {
debugC(1, kDebugGraphics, "drawBottomBorders");
displayRawDataAtPos(_circleImageSubFileArray[7], 16, 136);
displayRawDataAtPos(_circleImageSubFileArray[8], 16, 192);
displayRawDataAtPos(_circleImageSubFileArray[5], 0, 136);
displayRawDataAtPos(_circleImageSubFileArray[6], 304, 136);
}
void EfhEngine::drawChar(uint8 curChar, int16 posX, int16 posY) {
debugC(1, kDebugGraphics, "drawChar %c %d %d", curChar, posX, posY);
// CHECKME: Quick hacked display, may require rework
// Note: The original is making of a variable which is set to _textColor & 0x3FFF
// It seems _textColor is always set to a small value and thus this variable
// has been removed.
uint8 *destPtr = (uint8 *)_mainSurface->getBasePtr(posX, posY);
int16 charId = curChar - 0x20;
uint8 width = _fontDescr._widthArray[charId];
for (uint line = 0; line < 8; ++line) {
int16 x = 0;
for (int i = 7; i >= 7 - width; --i) {
if (_fontDescr._fontData[charId]._lines[line] & (1 << i))
destPtr[320 * line + x] = _textColor;
++x;
}
}
}
void EfhEngine::setTextColorWhite() {
debugC(1, kDebugGraphics, "setTextColorWhite");
if (_videoMode == 8) // CGA
_textColor = 0x3;
else
_textColor = 0xF;
}
void EfhEngine::setTextColorRed() {
debugC(1, kDebugGraphics, "setTextColorRed");
if (_videoMode == 8) // CGA
_textColor = 0x2;
else
_textColor = 0xC;
}
void EfhEngine::setTextColorGrey() {
debugC(1, kDebugGraphics, "setTextColorGrey");
if (_videoMode == 8) // CGA
_textColor = 0x1;
else
_textColor = 0x8;
}
void EfhEngine::displayStringAtTextPos(const Common::String &message) {
debugC(1, kDebugGraphics, "displayStringAtTextPos %s", message.c_str());
drawString(message, _textPosX, _textPosY, _textColor);
_textPosX += getStringWidth(message) + 1;
setNextCharacterPos();
}
void EfhEngine::clearBottomTextZone(int16 color) {
debugC(1, kDebugGraphics, "clearBottomTextZone %d", color);
drawColoredRect(16, 152, 302, 189, color);
}
void EfhEngine::clearBottomTextZone_2(int16 color) {
debugC(1, kDebugGraphics, "clearBottomTextZone_2 %d", color);
displayColoredMenuBox(16, 152, 302, 189, color);
}
void EfhEngine::setNextCharacterPos() {
debugC(1, kDebugGraphics, "setNextCharacterPos");
if (_textPosX <= 311)
return;
_textPosX = 0;
_textPosY += 8;
if (_textPosY > 191)
_textPosY = 0;
}
void EfhEngine::displayCharAtTextPos(char character) {
debugC(1, kDebugGraphics, "displayCharAtTextPos %c", character);
char buffer[2];
buffer[0] = character;
buffer[1] = 0;
drawString(buffer, _textPosX, _textPosY, _textColor);
_textPosX += getStringWidth(buffer) + 1;
setNextCharacterPos();
}
void EfhEngine::displayWindow(uint8 *buffer, int16 posX, int16 posY, uint8 *dest) {
debugC(1, kDebugGraphics, "displayWindow %d %d", posX, posY);
if (buffer == nullptr) {
warning("Target Buffer Not Defined...DCImage!"); // That's the original message... And yes, it's wrong: it's checking the source buffer :)
return;
}
// Only MCGA handled, the rest is skipped
uncompressBuffer(buffer, dest);
displayRawDataAtPos(dest, posX, posY);
displayFctFullScreen();
displayRawDataAtPos(dest, posX, posY);
}
void EfhEngine::displayColoredMenuBox(int16 minX, int16 minY, int16 maxX, int16 maxY, int16 color) {
debugC(1, kDebugGraphics, "displayColoredMenuBox %d %d -> %d %d %d", minX, minY, maxX, maxY, color);
drawColoredRect(minX, minY, maxX, maxY, color);
displayFctFullScreen();
drawColoredRect(minX, minY, maxX, maxY, color);
}
} // End of namespace Efh

410
engines/efh/init.cpp Normal file
View File

@@ -0,0 +1,410 @@
/* 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 "common/config-manager.h"
#include "efh/efh.h"
namespace Efh {
EfhGraphicsStruct::EfhGraphicsStruct() {
_vgaLineBuffer = nullptr;
_shiftValue = 0;
_width = 0;
_height = 0;
_area = Common::Rect(0, 0, 0, 0);
}
EfhGraphicsStruct::EfhGraphicsStruct(int8 **lineBuf, int16 x, int16 y, int16 width, int16 height) {
_vgaLineBuffer = lineBuf;
_shiftValue = 0;
_width = width;
_height = height;
_area = Common::Rect(x, y, x + width - 1, y + height - 1);
}
void InvObject::init() {
_ref = 0;
_stat1 = 0;
_curHitPoints = 0;
}
void MapSpecialTileStruct::init() {
_placeId = _posX = _posY = _triggerType = _triggerValue = 0;
_field5_textId = _field7_textId = 0;
}
void FrameList::init() {
for (int i = 0; i < 4; ++i)
_subFileId[i] = -1;
}
void AnimInfo::init() {
for (int i = 0; i < 10; ++i) {
_posX[i] = 0;
_posY[i] = 0;
}
for (int i = 0; i < 15; ++i)
_frameList[i].init();
}
void ItemStruct::init() {
for (uint idx = 0; idx < 15; ++idx)
_name[idx] = 0;
_damage = 0;
_defense = 0;
_attacks = 0;
_uses = 0;
_agilityModifier = 0;
_range = 0;
_attackType = 0;
_specialEffect = 0;
_defenseType = 0;
_exclusiveType = 0;
_field19_mapPosX_or_maxDeltaPoints = 0;
_mapPosY = 0;
}
void NPCStruct::init() {
for (int i = 0; i < 11; ++i)
_name[i] = 0;
fieldB_textId = 0;
field_C = 0;
field_D = 0;
fieldE_textId = 0;
field_F = 0;
field_10 = 0;
field11_NpcId = 0;
field12_textId = 0;
field14_textId = 0;
_xp = 0;
for (int i = 0; i < 15; ++i)
_activeScore[i] = 0;
for (int i = 0; i < 11; ++i) {
_passiveScore[i] = 0;
_infoScore[i] = 0;
}
field_3F = 0;
field_40 = 0;
for (int i = 0; i < 10; ++i)
_inventory[i].init();
_possessivePronounSHL6 = 0;
_speed = 0;
field_6B = 0;
field_6C = 0;
field_6D = 0;
_defaultDefenseItemId = 0;
field_6F = 0;
field_70 = 0;
field_71 = 0;
field_72 = 0;
field_73 = 0;
_hitPoints = 0;
_maxHP = 0;
field_78 = 0;
field_79 = 0;
field_7B = 0;
field_7D = 0;
field_7E = 0;
field_7F = 0;
field_80 = 0;
field_81 = 0;
field_82 = 0;
field_83 = 0;
field_84 = 0;
field_85 = 0;
}
uint8 NPCStruct::getPronoun() {
return _possessivePronounSHL6 >> 6;
}
void NPCStruct::synchronize(Common::Serializer &s) {
for (int idx = 0; idx < 11; ++idx)
s.syncAsByte(_name[idx]);
s.syncAsByte(fieldB_textId);
s.syncAsByte(field_C);
s.syncAsByte(field_D);
s.syncAsByte(fieldE_textId);
s.syncAsByte(field_F);
s.syncAsByte(field_10);
s.syncAsByte(field11_NpcId);
s.syncAsSint16LE(field12_textId);
s.syncAsSint16LE(field14_textId);
s.syncAsSint32LE(_xp);
for (int idx = 0; idx < 15; ++idx)
s.syncAsByte(_activeScore[idx]);
for (int idx = 0; idx < 11; ++idx)
s.syncAsByte(_passiveScore[idx]);
for (int idx = 0; idx < 11; ++idx)
s.syncAsByte(_infoScore[idx]);
s.syncAsByte(field_3F);
s.syncAsByte(field_40);
for (int idx = 0; idx < 10; ++idx) {
s.syncAsSint16LE(_inventory[idx]._ref);
s.syncAsByte(_inventory[idx]._stat1);
s.syncAsByte(_inventory[idx]._curHitPoints);
}
s.syncAsByte(_possessivePronounSHL6);
s.syncAsByte(_speed);
s.syncAsByte(field_6B);
s.syncAsByte(field_6C);
s.syncAsByte(field_6D);
s.syncAsByte(_defaultDefenseItemId);
s.syncAsByte(field_6F);
s.syncAsByte(field_70);
s.syncAsByte(field_71);
s.syncAsByte(field_72);
s.syncAsByte(field_73);
s.syncAsSint16LE(_hitPoints);
s.syncAsSint16LE(_maxHP);
s.syncAsByte(field_78);
s.syncAsSint16LE(field_79);
s.syncAsSint16LE(field_7B);
s.syncAsByte(field_7D);
s.syncAsByte(field_7E);
s.syncAsByte(field_7F);
s.syncAsByte(field_80);
s.syncAsByte(field_81);
s.syncAsByte(field_82);
s.syncAsByte(field_83);
s.syncAsByte(field_84);
s.syncAsByte(field_85);
}
uint8 MapMonster::getPronoun() {
return _possessivePronounSHL6 >> 6;
}
void TeamMonster::init() {
_id = -1;
for (int ctrMobsterId = 0; ctrMobsterId < 9; ++ctrMobsterId) {
_mobsterStatus[ctrMobsterId]._type = kEfhStatusNormal;
_mobsterStatus[ctrMobsterId]._duration = 0;
}
}
void InitiativeStruct::init() {
_id = _initiative = 0;
}
void TileFactStruct::init() {
_status = _tileId = 0;
}
void TeamChar::init() {
_id = -1;
_status._type = kEfhStatusNormal;
_status._duration = 0;
_pctVisible = 0;
_pctDodgeMiss = 0;
_nextAttack = -1;
_lastInventoryUsed = 0;
_lastAction = 0;
}
EfhEngine::EfhEngine(OSystem *syst, const ADGameDescription *gd) : Engine(syst), _gameDescription(gd) {
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "gendata");
SearchMan.addSubDirectoryMatching(gameDataDir, "images");
SearchMan.addSubDirectoryMatching(gameDataDir, "imp");
SearchMan.addSubDirectoryMatching(gameDataDir, "maps");
_system = syst;
_rnd = nullptr;
_lastTime = 0;
_platform = Common::kPlatformUnknown;
_mainSurface = nullptr;
for (int i = 0; i < 200; ++i)
_vgaLineBuffer[i] = nullptr;
_vgaGraphicsStruct1 = new EfhGraphicsStruct(_vgaLineBuffer, 0, 0, 320, 200);
_vgaGraphicsStruct2 = new EfhGraphicsStruct();
_videoMode = 0;
_graphicsStruct = nullptr;
for (int i = 0; i < 19; ++i) {
_mapBitmapRefArr[i]._setId1 = 0;
_mapBitmapRefArr[i]._setId2 = 0;
}
_defaultBoxColor = 0;
_fontDescr._widthArray = nullptr;
_fontDescr._extraLines = nullptr;
_fontDescr._fontData = nullptr;
_fontDescr._charHeight = 0;
_fontDescr._extraHorizontalSpace = _fontDescr._extraVerticalSpace = 0;
_introDoneFl = false;
_oldAnimImageSetId = -1;
_animImageSetId = 0xFE;
_paletteTransformationConstant = 10;
for (int i = 0; i < 12; ++i)
_circleImageSubFileArray[i] = nullptr;
_imageDataPtr._dataPtr = nullptr;
_imageDataPtr._width = 0;
_imageDataPtr._startX = _imageDataPtr._startY = 0;
_imageDataPtr._height = 0;
_imageDataPtr._lineDataSize = 0;
_imageDataPtr._paletteTransformation = 0;
_imageDataPtr._fieldD = 0;
for (int i = 0; i < 3; ++i)
_currentTileBankImageSetId[i] = -1;
_unkRelatedToAnimImageSetId = 0;
_techId = 0;
_currentAnimImageSetId = 0xFF;
for (int i = 0; i < 20; ++i) {
_portraitSubFilesArray[i] = nullptr;
}
_characterNamePt1 = "";
_characterNamePt2 = "";
_enemyNamePt1 = "";
_enemyNamePt2 = "";
_nameBuffer = "";
_attackBuffer = "";
for (int i = 0; i < 100; ++i) {
_imp1PtrArray[i] = nullptr;
for (int j = 0; j < 19; ++j)
_mapSpecialTiles[j][i].init();
}
for (int i = 0; i < 432; ++i)
_imp2PtrArray[i] = nullptr;
_unkAnimRelatedIndex = -1;
_initRect = Common::Rect(0, 0, 0, 0);
_engineInitPending = true;
_textColor = 0x0E; // Yellow
_protectionPassed = false;
_fullPlaceId = 0xFF;
_guessAnimationAmount = 9;
_largeMapFlag = 0xFFFF;
_alertDelay = 0;
for (int i = 0; i < 3; ++i)
_teamChar[i].init();
_teamChar[0]._id = 0;
for (int i = 0; i < 5; ++i)
_teamMonster[i].init();
_teamSize = 1;
_word2C872 = 0;
_imageSetSubFilesIdx = 144;
_oldImageSetSubFilesIdx = 143;
_mapPosX = _mapPosY = 31;
_oldMapPosX = _oldMapPosY = 31;
_techDataId_MapPosX = _techDataId_MapPosY = 31;
_textPosX = 0;
_textPosY = 0;
_lastMainPlaceId = 0;
_tempTextDelay = 0;
_tempTextPtr = nullptr;
_checkTileDisabledByScriptFl = false;
_redrawNeededFl = false;
_drawHeroOnMapFl = true;
_drawMonstersOnMapFl = true;
_textBoxDisabledByScriptFl = false;
_ongoingFightFl = false;
_statusMenuActive = false;
_menuDepth = 0;
_menuItemCounter = 0;
_selectedMenuBox = -1;
_sayMenu = true;
_sayLowStatusScreen = false;
_initiatedTalkByMenu = false;
for (int i = 0; i < 15; ++i)
_menuStatItemArr[i] = 0;
_messageToBePrinted = "";
for (int i = 0; i < 8; ++i)
_initiatives[i].init();
memset(_bufferCharBM, 0, ARRAYSIZE(_bufferCharBM));
for (int i = 0; i < 3; ++i)
memset(_tileBank[i], 0, ARRAYSIZE(_tileBank[i]));
memset(_circleImageBuf, 0, ARRAYSIZE(_circleImageBuf));
memset(_portraitBuf, 0, ARRAYSIZE(_portraitBuf));
memset(_decompBuf, 0, ARRAYSIZE(_decompBuf));
memset(_menuBuf, 0, ARRAYSIZE(_menuBuf));
memset(_windowWithBorderBuf, 0, ARRAYSIZE(_windowWithBorderBuf));
memset(_places, 0, ARRAYSIZE(_places));
for (int i = 0; i < 24; ++i)
memset(_curPlace[i], 0, ARRAYSIZE(_curPlace[i]));
memset(_npcBuf, 0, ARRAYSIZE(_npcBuf) * sizeof(NPCStruct));
memset(_imp1, 0, ARRAYSIZE(_imp1));
memset(_imp2, 0, ARRAYSIZE(_imp2));
memset(_titleSong, 0, ARRAYSIZE(_titleSong));
memset(_items, 0, ARRAYSIZE(_items) * sizeof(ItemStruct));
memset(_tileFact, 0, ARRAYSIZE(_tileFact) * sizeof(TileFactStruct));
memset(_animInfo, 0, ARRAYSIZE(_animInfo) * sizeof(AnimInfo));
memset(_history, 0, ARRAYSIZE(_history));
for (int i = 0; i < 19; ++i) {
memset(_techDataArr[i], 0, ARRAYSIZE(_techDataArr[i]));
memset(_mapArr[i], 0, ARRAYSIZE(_mapArr[i]));
memset(_mapMonsters[i], 0, ARRAYSIZE(_mapMonsters[i]) * sizeof(MapMonster));
for (int j = 0; j < 64; ++j) {
memset(_mapGameMaps[i][j], 0, ARRAYSIZE(_mapGameMaps[i][j]));
}
}
memset(_tileBankSubFilesArray, 0, ARRAYSIZE(_tileBankSubFilesArray) * sizeof(uint8 *));
_regenCounter = 0;
// If requested, load a savegame instead of showing the intro
_loadSaveSlot = -1;
_saveAuthorized = false;
if (ConfMan.hasKey("save_slot")) {
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot >= 0 && saveSlot <= 999)
_loadSaveSlot = saveSlot;
}
}
} // End of namespace Efh

1550
engines/efh/menu.cpp Normal file

File diff suppressed because it is too large Load Diff

705
engines/efh/metaengine.cpp Normal file
View File

@@ -0,0 +1,705 @@
/* 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 "engines/advancedDetector.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "common/system.h"
#include "common/savefile.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "graphics/surface.h"
#include "efh/detection.h"
#include "efh/efh.h"
namespace Efh {
#ifdef USE_TTS
static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_TTS,
{
_s("Enable Text to Speech"),
_s("Use TTS to read text in the game (if TTS is available)"),
"tts_enabled",
false,
0,
0
}
},
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
#endif
uint32 EfhEngine::getFeatures() const {
return _gameDescription->flags;
}
const char *EfhEngine::getGameId() const {
return _gameDescription->gameId;
}
void EfhEngine::initGame(const ADGameDescription *gd) {
_platform = gd->platform;
}
bool EfhEngine::hasFeature(EngineFeature f) const {
return (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
}
const char *EfhEngine::getCopyrightString() const {
return "Escape From Hell (C) Electronic Arts, 1990";
}
Common::Platform EfhEngine::getPlatform() const {
return _platform;
}
} // End of namespace Efh
namespace Efh {
class EfhMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
public:
const char *getName() const override {
return "efh";
}
#ifdef USE_TTS
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
return Efh::optionsList;
}
#endif
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const override;
bool hasFeature(MetaEngineFeature f) const override;
int getMaximumSaveSlot() const override;
SaveStateList listSaves(const char *target) const override;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
bool removeSaveState(const char *target, int slot) const override;
Common::KeymapArray initKeymaps(const char *target) const override;
};
Common::Error EfhMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
*engine = new EfhEngine(syst, gd);
((EfhEngine *)*engine)->initGame(gd);
return Common::kNoError;
}
bool EfhMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate);
}
int EfhMetaEngine::getMaximumSaveSlot() const {
return 99;
}
SaveStateList EfhMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::String pattern = target;
pattern += ".###";
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
char slot[3];
for (const auto &filename : filenames) {
slot[0] = filename.c_str()[filename.size() - 2];
slot[1] = filename.c_str()[filename.size() - 1];
slot[2] = '\0';
// Obtain the last 2 digits of the filename (without extension), since they correspond to the save slot
int slotNum = atoi(slot);
if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
Common::InSaveFile *file = saveFileMan->openForLoading(filename);
if (file) {
uint32 sign = file->readUint32LE();
uint8 saveVersion = file->readByte();
if (sign != EFH_SAVE_HEADER || saveVersion > kSavegameVersion) {
warning("Incompatible savegame");
delete file;
continue;
}
// read name
uint16 nameSize = file->readUint16LE();
if (nameSize >= 255) {
delete file;
continue;
}
char name[256];
file->read(name, nameSize);
name[nameSize] = 0;
saveList.push_back(SaveStateDescriptor(this, slotNum, name));
delete file;
}
}
}
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
SaveStateDescriptor EfhMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
if (file) {
uint32 sign = file->readUint32LE();
uint8 saveVersion = file->readByte();
if (sign != EFH_SAVE_HEADER || saveVersion > kSavegameVersion) {
warning("Incompatible savegame");
delete file;
return SaveStateDescriptor();
}
uint32 saveNameLength = file->readUint16LE();
Common::String saveName;
for (uint32 i = 0; i < saveNameLength; ++i) {
char curChr = file->readByte();
saveName += curChr;
}
SaveStateDescriptor desc(this, slot, saveName);
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*file, thumbnail)) {
delete file;
return SaveStateDescriptor();
}
desc.setThumbnail(thumbnail);
// Read in save date/time
int16 year = file->readSint16LE();
int16 month = file->readSint16LE();
int16 day = file->readSint16LE();
int16 hour = file->readSint16LE();
int16 minute = file->readSint16LE();
desc.setSaveDate(year, month, day);
desc.setSaveTime(hour, minute);
desc.setDeletableFlag(slot != 0);
desc.setWriteProtectedFlag(slot == 0);
delete file;
return desc;
}
return SaveStateDescriptor();
}
bool EfhMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
struct EfhSubMenuOption {
EFHAction _action;
const char *_id;
const char *_inputKey;
const char *_desc;
};
static const EfhSubMenuOption _efhSubMenuOptions[] = {
{ kActionOption1, "OPTION1", "a", _s("Select option 1") },
{ kActionOption2, "OPTION2", "b", _s("Select option 2") },
{ kActionOption3, "OPTION3", "c", _s("Select option 3") },
{ kActionOption4, "OPTION4", "d", _s("Select option 4") },
{ kActionOption5, "OPTION5", "e", _s("Select option 5") },
{ kActionOption6, "OPTION6", "f", _s("Select option 6") },
{ kActionOption7, "OPTION7", "g", _s("Select option 7") },
{ kActionOption8, "OPTION8", "h", _s("Select option 8") },
{ kActionOption9, "OPTION9", "i", _s("Select option 9") },
{ kActionOption10, "OPTION10", "j", _s("Select option 10") },
{ kActionOption11, "OPTION11", "k", _s("Select option 11") },
{ kActionOption12, "OPTION12", "l", _s("Select option 12") },
{ kActionOption13, "OPTION13", "m", _s("Select option 13") },
{ kActionOption14, "OPTION14", "n", _s("Select option 14") },
{ kActionNone, nullptr, nullptr, nullptr }
};
Common::KeymapArray EfhMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "efh-default", _("Default keymappings"));
Keymap *menuKeymap = new Keymap(Keymap::kKeymapTypeGame, "menu", _("Menu keymappings"));
Keymap *quitKeymap = new Keymap(Keymap::kKeymapTypeGame, "efh-quit", _("Quit keymappings"));
Keymap *skipVideoKeymap = new Keymap(Keymap::kKeymapTypeGame, "skip-video", _("Skip video keymappings"));
Keymap *skipSongKeymap = new Keymap(Keymap::kKeymapTypeGame, "skip-song", _("Skip song keymappings"));
Keymap *statusMenuNavigationKeymap = new Keymap(Keymap::kKeymapTypeGame, "status-menu-navigation", _("Status menu navigation keymappings"));
Keymap *statusMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "status-menu", _("Status menu keymappings"));
Keymap *statusMenuSubMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "status-menu-submenu", _("Status menu submenu keymappings"));
Keymap *interactionKeymap = new Keymap(Keymap::kKeymapTypeGame, "interaction", _("Interaction keymappings"));
Keymap *fightKeymap = new Keymap(Keymap::kKeymapTypeGame, "fight", _("Fight keymappings"));
Keymap *characterSelectionKeymap = new Keymap(Keymap::kKeymapTypeGame, "character-selection", _("Character selection keymappings"));
Keymap *enemySelectionKeymap = new Keymap(Keymap::kKeymapTypeGame, "enemy-selection", _("Enemy selection keymappings"));
Keymap *deathMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "death-menu", _("Death menu keymappings"));
Action *act;
act = new Action(kStandardActionSave, _("Save game"));
act->setCustomEngineActionEvent(kActionSave);
act->addDefaultInputMapping("F5");
act->addDefaultInputMapping("C+s");
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
engineKeymap->addAction(act);
act = new Action(kStandardActionLoad, _("Load game"));
act->setCustomEngineActionEvent(kActionLoad);
act->addDefaultInputMapping("F7");
act->addDefaultInputMapping("C+l");
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
engineKeymap->addAction(act);
act = new Action("MOVEUP", _("Move up"));
act->setCustomEngineActionEvent(kActionMoveUp);
act->addDefaultInputMapping("UP");
act->addDefaultInputMapping("KP8");
act->addDefaultInputMapping("JOY_UP");
engineKeymap->addAction(act);
act = new Action("MOVEDOWN", _("Move down"));
act->setCustomEngineActionEvent(kActionMoveDown);
act->addDefaultInputMapping("DOWN");
act->addDefaultInputMapping("KP2");
act->addDefaultInputMapping("JOY_DOWN");
engineKeymap->addAction(act);
act = new Action("MOVELEFT", _("Move left"));
act->setCustomEngineActionEvent(kActionMoveLeft);
act->addDefaultInputMapping("LEFT");
act->addDefaultInputMapping("KP4");
act->addDefaultInputMapping("JOY_LEFT");
engineKeymap->addAction(act);
act = new Action("MOVERIGHT", _("Move right"));
act->setCustomEngineActionEvent(kActionMoveRight);
act->addDefaultInputMapping("RIGHT");
act->addDefaultInputMapping("KP6");
act->addDefaultInputMapping("JOY_RIGHT");
engineKeymap->addAction(act);
act = new Action("MOVEUPLEFT", _("Move up-left"));
act->setCustomEngineActionEvent(kActionMoveUpLeft);
act->addDefaultInputMapping("HOME");
act->addDefaultInputMapping("KP7");
engineKeymap->addAction(act);
act = new Action("MOVEUPRIGHT", _("Move up-right"));
act->setCustomEngineActionEvent(kActionMoveUpRight);
act->addDefaultInputMapping("PAGEUP");
act->addDefaultInputMapping("KP9");
engineKeymap->addAction(act);
act = new Action("MOVEDOWNLEFT", _("Move down-left"));
act->setCustomEngineActionEvent(kActionMoveDownLeft);
act->addDefaultInputMapping("END");
act->addDefaultInputMapping("KP1");
engineKeymap->addAction(act);
act = new Action("MOVEDOWNRIGHT", _("Move down-right"));
act->setCustomEngineActionEvent(kActionMoveDownRight);
act->addDefaultInputMapping("PAGEDOWN");
act->addDefaultInputMapping("KP3");
engineKeymap->addAction(act);
// I18N: (Game name: Escape from hell) Character is a hero in-game
act = new Action("CHARACTER1STATUS", _("Character 1 status"));
act->setCustomEngineActionEvent(kActionCharacter1Status);
act->addDefaultInputMapping("1");
act->addDefaultInputMapping("F1");
act->addDefaultInputMapping("JOY_A");
engineKeymap->addAction(act);
// I18N: (Game name: Escape from hell) Character is a hero in-game
act = new Action("CHARACTER2STATUS", _("Character 2 status"));
act->setCustomEngineActionEvent(kActionCharacter2Status);
act->addDefaultInputMapping("2");
act->addDefaultInputMapping("F2");
act->addDefaultInputMapping("JOY_X");
engineKeymap->addAction(act);
// I18N: (Game name: Escape from hell) Character is a hero in-game
act = new Action("CHARACTER3STATUS", _("Character 3 status"));
act->setCustomEngineActionEvent(kActionCharacter3Status);
act->addDefaultInputMapping("3");
act->addDefaultInputMapping("F3");
act->addDefaultInputMapping("JOY_Y");
engineKeymap->addAction(act);
act = new Action("YES", _("Yes"));
act->setCustomEngineActionEvent(kActionYes);
act->addDefaultInputMapping("y");
act->addDefaultInputMapping("JOY_A");
menuKeymap->addAction(act);
act = new Action("NO", _("No"));
act->setCustomEngineActionEvent(kActionNo);
act->addDefaultInputMapping("JOY_B");
menuKeymap->addAction(act);
act = new Action("QUIT", _("Quit game"));
act->setCustomEngineActionEvent(kActionQuit);
act->addDefaultInputMapping("C+q");
act->addDefaultInputMapping("C+x");
quitKeymap->addAction(act);
act = new Action("SKIP", _("Skip"));
act->setCustomEngineActionEvent(kActionSkipVideo);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_A");
skipVideoKeymap->addAction(act);
act = new Action("SKIPSONG", _("Skip song"));
act->setCustomEngineActionEvent(kActionSkipSong);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("JOY_A");
skipSongKeymap->addAction(act);
act = new Action("SKIPSONGANDINTRO", _("Skip song and intro"));
act->setCustomEngineActionEvent(kActionSkipSongAndIntro);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_B");
skipSongKeymap->addAction(act);
act = new Action("SELECT", _("Select"));
act->setCustomEngineActionEvent(kActionSelect);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("JOY_A");
statusMenuNavigationKeymap->addAction(act);
act = new Action("SCROLLDOWN", _("Scroll down"));
act->setCustomEngineActionEvent(kActionScrollDown);
act->addDefaultInputMapping("DOWN");
act->addDefaultInputMapping("RIGHT");
act->addDefaultInputMapping("2");
act->addDefaultInputMapping("6");
act->addDefaultInputMapping("KP2");
act->addDefaultInputMapping("KP6");
act->addDefaultInputMapping("JOY_DOWN");
act->addDefaultInputMapping("JOY_RIGHT");
statusMenuNavigationKeymap->addAction(act);
act = new Action("SCROLLUP", _("Scroll up"));
act->setCustomEngineActionEvent(kActionScrollUp);
act->addDefaultInputMapping("UP");
act->addDefaultInputMapping("LEFT");
act->addDefaultInputMapping("8");
act->addDefaultInputMapping("4");
act->addDefaultInputMapping("KP8");
act->addDefaultInputMapping("KP4");
act->addDefaultInputMapping("JOY_UP");
act->addDefaultInputMapping("JOY_LEFT");
statusMenuNavigationKeymap->addAction(act);
act = new Action("ACTIVE", _("Active skills"));
act->setCustomEngineActionEvent(kActionActive);
act->addDefaultInputMapping("a");
statusMenuKeymap->addAction(act);
act = new Action("DROP", _("Drop"));
act->setCustomEngineActionEvent(kActionDrop);
act->addDefaultInputMapping("d");
statusMenuKeymap->addAction(act);
act = new Action("EQUIP", _("Equip"));
act->setCustomEngineActionEvent(kActionEquip);
act->addDefaultInputMapping("e");
statusMenuKeymap->addAction(act);
act = new Action("GIVE", _("Give"));
act->setCustomEngineActionEvent(kActionGive);
act->addDefaultInputMapping("g");
statusMenuKeymap->addAction(act);
act = new Action("INFO", _("Info"));
act->setCustomEngineActionEvent(kActionInfo);
act->addDefaultInputMapping("i");
statusMenuKeymap->addAction(act);
act = new Action("PASSIVE", _("Passive skills"));
act->setCustomEngineActionEvent(kActionPassive);
act->addDefaultInputMapping("p");
statusMenuKeymap->addAction(act);
act = new Action("TRADE", _("Trade"));
act->setCustomEngineActionEvent(kActionTrade);
act->addDefaultInputMapping("t");
statusMenuKeymap->addAction(act);
act = new Action("USE", _("Use"));
act->setCustomEngineActionEvent(kActionUse);
act->addDefaultInputMapping("u");
statusMenuKeymap->addAction(act);
act = new Action("EXIT", _("Exit status menu"));
act->setCustomEngineActionEvent(kActionExitStatusMenu);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_B");
statusMenuKeymap->addAction(act);
for (const EfhSubMenuOption *i = _efhSubMenuOptions; i->_id; ++i) {
act = new Action(i->_id, _(i->_desc));
act->setCustomEngineActionEvent(i->_action);
act->addDefaultInputMapping(i->_inputKey);
statusMenuSubMenuKeymap->addAction(act);
}
act = new Action("EXIT", _("Exit submenu"));
act->setCustomEngineActionEvent(kActionExitSubMenu);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_B");
statusMenuSubMenuKeymap->addAction(act);
act = new Action("STARTFIGHT", _("Attack"));
act->setCustomEngineActionEvent(kActionStartFight);
act->addDefaultInputMapping("a");
act->addDefaultInputMapping("JOY_UP");
interactionKeymap->addAction(act);
act = new Action("LEAVE", _("Leave"));
act->setCustomEngineActionEvent(kActionLeave);
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_DOWN");
interactionKeymap->addAction(act);
act = new Action("STATUS", _("Status"));
act->setCustomEngineActionEvent(kActionStatus);
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_LEFT");
interactionKeymap->addAction(act);
act = new Action("TALK", _("Talk"));
act->setCustomEngineActionEvent(kActionTalk);
act->addDefaultInputMapping("t");
act->addDefaultInputMapping("JOY_RIGHT");
interactionKeymap->addAction(act);
act = new Action("ATTACK", _("Attack"));
act->setCustomEngineActionEvent(kActionAttack);
act->addDefaultInputMapping("a");
act->addDefaultInputMapping("JOY_UP");
fightKeymap->addAction(act);
act = new Action("DEFEND", _("Defend"));
act->setCustomEngineActionEvent(kActionDefend);
act->addDefaultInputMapping("d");
act->addDefaultInputMapping("JOY_DOWN");
fightKeymap->addAction(act);
act = new Action("HIDE", _("Hide"));
act->setCustomEngineActionEvent(kActionHide);
act->addDefaultInputMapping("h");
act->addDefaultInputMapping("JOY_LEFT");
fightKeymap->addAction(act);
act = new Action("RUN", _("Run"));
act->setCustomEngineActionEvent(kActionRun);
act->addDefaultInputMapping("r");
act->addDefaultInputMapping("JOY_RIGHT");
fightKeymap->addAction(act);
act = new Action("STATUS", _("Status"));
act->setCustomEngineActionEvent(kActionTeamStatus);
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_Y");
fightKeymap->addAction(act);
// I18N: (Game name: Escape from hell) This action is used to view the terrain during a fight so that the player can see where they can move if they decide to run.
act = new Action("TERRAIN", _("View terrain"));
act->setCustomEngineActionEvent(kActionTerrain);
act->addDefaultInputMapping("t");
act->addDefaultInputMapping("JOY_X");
fightKeymap->addAction(act);
// I18N: (Game name: Escape from hell) Character is a hero in-game
act = new Action("CHARACTER1", _("Select character 1"));
act->setCustomEngineActionEvent(kActionCharacter1);
act->addDefaultInputMapping("1");
act->addDefaultInputMapping("JOY_UP");
characterSelectionKeymap->addAction(act);
// I18N: (Game name: Escape from hell) Character is a hero in-game
act = new Action("CHARACTER2", _("Select character 2"));
act->setCustomEngineActionEvent(kActionCharacter2);
act->addDefaultInputMapping("2");
act->addDefaultInputMapping("JOY_RIGHT");
characterSelectionKeymap->addAction(act);
// I18N: (Game name: Escape from hell) Character is a hero in-game
act = new Action("CHARACTER3", _("Select character 3"));
act->setCustomEngineActionEvent(kActionCharacter3);
act->addDefaultInputMapping("3");
act->addDefaultInputMapping("JOY_DOWN");
characterSelectionKeymap->addAction(act);
act = new Action("CHARACTERSELECTIONCANCEL", _("Cancel character selection"));
act->setCustomEngineActionEvent(kActionCancelCharacterSelection);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("0");
act->addDefaultInputMapping("JOY_B");
characterSelectionKeymap->addAction(act);
act = new Action("ENEMY1", _("Select enemy 1"));
act->setCustomEngineActionEvent(kActionEnemy1);
act->addDefaultInputMapping("a");
act->addDefaultInputMapping("JOY_UP");
enemySelectionKeymap->addAction(act);
act = new Action("ENEMY2", _("Select enemy 2"));
act->setCustomEngineActionEvent(kActionEnemy2);
act->addDefaultInputMapping("b");
act->addDefaultInputMapping("JOY_RIGHT");
enemySelectionKeymap->addAction(act);
act = new Action("ENEMY3", _("Select enemy 3"));
act->setCustomEngineActionEvent(kActionEnemy3);
act->addDefaultInputMapping("c");
act->addDefaultInputMapping("JOY_DOWN");
enemySelectionKeymap->addAction(act);
act = new Action("ENEMY4", _("Select enemy 4"));
act->setCustomEngineActionEvent(kActionEnemy4);
act->addDefaultInputMapping("d");
act->addDefaultInputMapping("JOY_LEFT");
enemySelectionKeymap->addAction(act);
act = new Action("ENEMY5", _("Select enemy 5"));
act->setCustomEngineActionEvent(kActionEnemy5);
act->addDefaultInputMapping("e");
act->addDefaultInputMapping("JOY_Y");
enemySelectionKeymap->addAction(act);
act = new Action("CANCEL", _("Cancel enemy selection"));
act->setCustomEngineActionEvent(kActionCancelEnemySelection);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_B");
enemySelectionKeymap->addAction(act);
act = new Action(kStandardActionLoad, _("Load game"));
act->setCustomEngineActionEvent(kActionLoad);
act->addDefaultInputMapping("l");
act->addDefaultInputMapping("JOY_LEFT");
deathMenuKeymap->addAction(act);
act = new Action(kStandardActionSave, _("Quit game"));
act->setCustomEngineActionEvent(kActionQuit);
act->addDefaultInputMapping("q");
act->addDefaultInputMapping("JOY_RIGHT");
deathMenuKeymap->addAction(act);
act = new Action("RESET", _("Restart game"));
act->setCustomEngineActionEvent(kActionreset);
act->addDefaultInputMapping("r");
act->addDefaultInputMapping("JOY_UP");
deathMenuKeymap->addAction(act);
if (ConfMan.getBool("dump_scripts")) {
act = new Action("SOUND13", _("Play sound type 13"));
act->setCustomEngineActionEvent(kActionSound13);
act->addDefaultInputMapping("4");
engineKeymap->addAction(act);
act = new Action("SOUND14", _("Play sound type 14"));
act->setCustomEngineActionEvent(kActionSound14);
act->addDefaultInputMapping("5");
engineKeymap->addAction(act);
act = new Action("SOUND15", _("Play sound type 15"));
act->setCustomEngineActionEvent(kActionSound15);
act->addDefaultInputMapping("6");
engineKeymap->addAction(act);
act = new Action("SOUND5", _("Play sound type 5"));
act->setCustomEngineActionEvent(kActionSound5);
act->addDefaultInputMapping("7");
engineKeymap->addAction(act);
act = new Action("SOUND10", _("Play sound type 10"));
act->setCustomEngineActionEvent(kActionSound10);
act->addDefaultInputMapping("8");
engineKeymap->addAction(act);
act = new Action("SOUND9", _("Play sound type 9"));
act->setCustomEngineActionEvent(kActionSound9);
act->addDefaultInputMapping("9");
engineKeymap->addAction(act);
act = new Action("SOUND16", _("Play sound type 16"));
act->setCustomEngineActionEvent(kActionSound16);
act->addDefaultInputMapping("0");
engineKeymap->addAction(act);
}
KeymapArray keymap(13);
keymap[0] = engineKeymap;
keymap[1] = menuKeymap;
keymap[2] = quitKeymap;
keymap[3] = skipVideoKeymap;
keymap[4] = skipSongKeymap;
keymap[5] = statusMenuNavigationKeymap;
keymap[6] = statusMenuKeymap;
keymap[7] = statusMenuSubMenuKeymap;
keymap[8] = interactionKeymap;
keymap[9] = fightKeymap;
keymap[10] = characterSelectionKeymap;
keymap[11] = enemySelectionKeymap;
keymap[12] = deathMenuKeymap;
menuKeymap->setEnabled(false);
skipVideoKeymap->setEnabled(false);
skipSongKeymap->setEnabled(false);
statusMenuNavigationKeymap->setEnabled(false);
statusMenuKeymap->setEnabled(false);
statusMenuSubMenuKeymap->setEnabled(false);
interactionKeymap->setEnabled(false);
fightKeymap->setEnabled(false);
characterSelectionKeymap->setEnabled(false);
enemySelectionKeymap->setEnabled(false);
deathMenuKeymap->setEnabled(false);
return keymap;
}
} // End of namespace Efh
#if PLUGIN_ENABLED_DYNAMIC(EFH)
REGISTER_PLUGIN_DYNAMIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine);
#else
REGISTER_PLUGIN_STATIC(EFH, PLUGIN_TYPE_ENGINE, Efh::EfhMetaEngine);
#endif

29
engines/efh/module.mk Normal file
View File

@@ -0,0 +1,29 @@
MODULE := engines/efh
MODULE_OBJS = \
constants.o \
efh.o \
fight.o \
files.o \
graphics.o \
init.o \
menu.o \
metaengine.o \
savegames.o \
script.o \
sound.o \
utils.o
MODULE_DIRS += \
engines/efh
# This module can be built as a plugin
ifeq ($(ENABLE_EFH), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

203
engines/efh/savegames.cpp Normal file
View File

@@ -0,0 +1,203 @@
/* 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 "common/savefile.h"
#include "graphics/scaler.h"
#include "graphics/thumbnail.h"
#include "common/system.h"
#include "graphics/paletteman.h"
#include "efh/efh.h"
namespace Efh {
Common::String EfhEngine::getSavegameFilename(int slot) {
return _targetName + Common::String::format("-%03d.SAV", slot);
}
bool EfhEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return true;
}
bool EfhEngine::canSaveGameStateCurrently(Common::U32String *msg) {
return _saveAuthorized;
}
Common::Error EfhEngine::loadGameState(int slot) {
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(getSaveStateName(slot));
if (!saveFile)
return Common::kReadingFailed;
uint32 signature = saveFile->readUint32LE();
byte version = saveFile->readByte();
if (signature != EFH_SAVE_HEADER || version > kSavegameVersion)
error("Invalid savegame");
// Skip savegame name
uint16 size = saveFile->readUint16LE();
saveFile->skip(size);
// Skip the thumbnail
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*saveFile, thumbnail))
return Common::kReadingFailed;
delete (thumbnail);
// Skip the savegame date
saveFile->skip(10); // year, month, day, hours, minutes (all int16)
Common::Serializer s(saveFile, nullptr);
synchronize(s);
delete saveFile;
_oldMapPosX = _mapPosX;
_oldMapPosY = _mapPosY;
_unkRelatedToAnimImageSetId = 0;
loadTechMapImp(_techId);
_lastMainPlaceId = 0xFFFF;
loadPlacesFile(_fullPlaceId, true);
return Common::kNoError;
}
Common::Error EfhEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
Common::OutSaveFile *out = _system->getSavefileManager()->openForSaving(getSaveStateName(slot));
if (!out)
return Common::kCreatingFileFailed;
out->writeUint32LE(EFH_SAVE_HEADER);
out->writeByte(kSavegameVersion);
// Write savegame name
uint16 size = desc.size();
out->writeUint16LE(size);
for (int i = 0; i < size; ++i)
out->writeByte(desc.c_str()[i]);
// Get the active palette
uint8 thumbPalette[16 * 3];
_system->getPaletteManager()->grabPalette(thumbPalette, 0, 16);
// Create a thumbnail and save it
Graphics::Surface *thumb = new Graphics::Surface();
Graphics::Surface *sf = _mainSurface;
::createThumbnail(thumb, (const byte *)sf->getPixels(), 320, 200, thumbPalette);
Graphics::saveThumbnail(*out, *thumb);
thumb->free();
delete thumb;
// Write out the save date/time
TimeDate td;
g_system->getTimeAndDate(td);
out->writeSint16LE(td.tm_year + 1900);
out->writeSint16LE(td.tm_mon + 1);
out->writeSint16LE(td.tm_mday);
out->writeSint16LE(td.tm_hour);
out->writeSint16LE(td.tm_min);
Common::Serializer s(nullptr, out);
synchronize(s);
out->finalize();
delete out;
return Common::kNoError;
}
void EfhEngine::synchronize(Common::Serializer &s) {
s.syncAsSint16LE(_techId);
s.syncAsUint16LE(_fullPlaceId);
s.syncAsSint16LE(_guessAnimationAmount);
s.syncAsUint16LE(_largeMapFlag);
s.syncAsSint16LE(_teamChar[0]._id);
s.syncAsSint16LE(_teamChar[1]._id);
s.syncAsSint16LE(_teamChar[2]._id);
for (int i = 0; i < 3; ++i) {
s.syncAsSint16LE(_teamChar[i]._status._type);
s.syncAsSint16LE(_teamChar[i]._status._duration);
}
s.syncAsSint16LE(_teamSize);
s.syncAsSint16LE(_alertDelay);
s.syncAsSint16LE(_word2C872);
s.syncAsSint16LE(_imageSetSubFilesIdx);
s.syncAsSint16LE(_mapPosX);
s.syncAsSint16LE(_mapPosY);
s.syncAsSint16LE(_techDataId_MapPosX);
s.syncAsSint16LE(_techDataId_MapPosY);
for (int i = 0; i < 19; ++i) {
int size = ARRAYSIZE(_techDataArr[i]);
for (int j = 0; j < size; ++j)
s.syncAsByte(_techDataArr[i][j]);
s.syncAsByte(_mapBitmapRefArr[i]._setId1);
s.syncAsByte(_mapBitmapRefArr[i]._setId2);
for (int idx = 0; idx < 100; ++idx) {
s.syncAsByte(_mapSpecialTiles[i][idx]._placeId);
s.syncAsByte(_mapSpecialTiles[i][idx]._posX);
s.syncAsByte(_mapSpecialTiles[i][idx]._posY);
s.syncAsByte(_mapSpecialTiles[i][idx]._triggerType);
s.syncAsByte(_mapSpecialTiles[i][idx]._triggerValue);
s.syncAsUint16LE(_mapSpecialTiles[i][idx]._field5_textId);
s.syncAsUint16LE(_mapSpecialTiles[i][idx]._field7_textId);
}
for (int idx = 0; idx < 64; ++idx) {
s.syncAsByte(_mapMonsters[i][idx]._possessivePronounSHL6);
s.syncAsByte(_mapMonsters[i][idx]._npcId);
s.syncAsByte(_mapMonsters[i][idx]._fullPlaceId);
s.syncAsByte(_mapMonsters[i][idx]._posX);
s.syncAsByte(_mapMonsters[i][idx]._posY);
s.syncAsByte(_mapMonsters[i][idx]._weaponItemId);
s.syncAsByte(_mapMonsters[i][idx]._maxDamageAbsorption);
s.syncAsByte(_mapMonsters[i][idx]._monsterRef);
s.syncAsByte(_mapMonsters[i][idx]._additionalInfo);
s.syncAsByte(_mapMonsters[i][idx]._talkTextId);
s.syncAsByte(_mapMonsters[i][idx]._groupSize);
for (int j = 0; j < 9; ++j)
s.syncAsSint16LE(_mapMonsters[i][idx]._hitPoints[j]);
}
for (int x = 0; x < 64; ++x) {
for (int y = 0; y < 64; ++y)
s.syncAsByte(_mapGameMaps[i][x][y]);
}
}
// Dialog flags
for (int i = 0; i < 256; ++i)
s.syncAsByte(_history[i]);
// NPCs
for (int i = 0; i < 99; ++i) {
_npcBuf[i].synchronize(s);
}
s.syncAsByte(_saveAuthorized);
}
} // End of namespace Efh

492
engines/efh/script.cpp Normal file
View File

@@ -0,0 +1,492 @@
/* 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 "common/system.h"
#include "efh/efh.h"
namespace Efh {
const uint8 *EfhEngine::script_readNumberArray(const uint8 *srcBuffer, int16 destArraySize, int16 *destArray) {
debugC(6, kDebugScript, "script_readNumberArray");
const uint8 *buffer = srcBuffer;
for (int i = 0; i < destArraySize; ++i) {
buffer++;
buffer = script_getNumber(buffer, &destArray[i]);
}
return buffer;
}
const uint8 *EfhEngine::script_getNumber(const uint8 *srcBuffer, int16 *retBuf) {
debugC(6, kDebugScript, "script_getNumber");
const uint8 *buffer = srcBuffer;
int16 retVal = 0;
for (;;) {
uint8 curChar = *buffer;
if (curChar < 0x30 || curChar > 0x39) {
break;
}
retVal = retVal * 10 + curChar - 0x30;
buffer++;
}
*retBuf = retVal;
return buffer;
}
int16 EfhEngine::script_parse(Common::String stringBuffer, int16 posX, int16 posY, int16 maxX, int16 maxY, bool scriptExecuteFlag) {
debugC(3, kDebugScript, "script_parse stringBuffer %d-%d %d-%d %s", posX, posY, maxX, maxY, scriptExecuteFlag ? "True" : "False");
debugC(6, kDebugScript, "%s", stringBuffer.c_str());
bool doneFlag = false;
bool noTextFlag = true;
int16 retVal = 0xFF;
int16 joiningNpcId = 0xFF;
uint16 curLineNb = 0;
int16 numbLines = (1 + maxY - posY) / 9;
int16 width = maxX - posX;
int16 spaceWidth = getStringWidth(" ");
const uint8 *buffer = (const uint8 *)stringBuffer.c_str();
char nextWord[80];
Common::String curLine = "";
memset(nextWord, 0, sizeof(nextWord));
int16 curWordPos = 0;
setTextPos(posX, curLineNb * 9 + posY);
while (!doneFlag && !shouldQuit()) {
uint8 curChar = *buffer;
if (curChar != 0x5E && curChar != 0x20 && curChar != 0 && curChar != 0x7C) { // '^', ' ', NUL, '|'
noTextFlag = false;
nextWord[curWordPos++] = curChar;
++buffer;
continue;
}
if (curChar != 0x5E) { // '^'
if (curChar == 0)
doneFlag = true;
else if (curChar == 0x7C) // '|'
noTextFlag = false;
nextWord[curWordPos] = 0;
int16 widthNextWord = getStringWidth(nextWord);
int16 widthCurrentLine = spaceWidth + getStringWidth(curLine);
if (widthCurrentLine + widthNextWord > width || curChar == 0x7C) { // '|'
if (curLineNb >= numbLines) {
doneFlag = true;
} else {
if (!noTextFlag)
displayStringAtTextPos(curLine);
curLine = Common::String(nextWord) + " ";
++curLineNb;
setTextPos(posX, posY + curLineNb * 9);
curWordPos = 0;
}
} else {
curLine += Common::String(nextWord) + " ";
curWordPos = 0;
}
++buffer;
continue;
}
// At this point, curChar == 0x5E '^'
++buffer;
int16 opCode = 0;
buffer = script_getNumber(buffer, &opCode);
int16 scriptNumberArray[10];
memset(scriptNumberArray, 0, sizeof(scriptNumberArray));
switch (opCode) {
case 0x00:
// Enter room { full Place Id, posX, posY }
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
if (_largeMapFlag) {
_largeMapFlag = false;
_techDataId_MapPosX = _mapPosX;
_techDataId_MapPosY = _mapPosY;
}
_oldMapPosX = _mapPosX = scriptNumberArray[1];
_oldMapPosY = _mapPosY = scriptNumberArray[2];
loadPlacesFile(scriptNumberArray[0], false);
_checkTileDisabledByScriptFl = true;
_redrawNeededFl = true;
}
break;
case 0x01:
// Exit room { }
if (scriptExecuteFlag) {
_largeMapFlag = true;
_oldMapPosX = _mapPosX = _techDataId_MapPosX;
_oldMapPosY = _mapPosY = _techDataId_MapPosY;
_checkTileDisabledByScriptFl = true;
_redrawNeededFl = true;
}
break;
case 0x02:
// Change map. { map number, posX, posY }
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
_oldMapPosX = _mapPosX = scriptNumberArray[1];
_oldMapPosY = _mapPosY = scriptNumberArray[2];
loadTechMapImp(scriptNumberArray[0]);
_largeMapFlag = true;
_checkTileDisabledByScriptFl = true;
_redrawNeededFl = true;
doneFlag = true;
}
break;
case 0x03:
buffer = script_readNumberArray(buffer, 4, scriptNumberArray);
if (scriptExecuteFlag) {
int16 rangeX = scriptNumberArray[2] - scriptNumberArray[0];
int16 rangeY = scriptNumberArray[3] - scriptNumberArray[1];
_mapPosX = getRandom(rangeX) + scriptNumberArray[0] - 1;
_mapPosY = getRandom(rangeY) + scriptNumberArray[1] - 1;
_checkTileDisabledByScriptFl = true;
_redrawNeededFl = true;
}
break;
case 0x04:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
_mapPosX = scriptNumberArray[0];
_mapPosY = scriptNumberArray[1];
_checkTileDisabledByScriptFl = true;
_redrawNeededFl = true;
}
break;
case 0x05:
buffer = script_readNumberArray(buffer, 4, scriptNumberArray);
if (scriptExecuteFlag) {
int16 npcId = _teamChar[scriptNumberArray[0]]._id;
if (npcId != -1) {
int16 scoreId = scriptNumberArray[1];
_npcBuf[npcId]._activeScore[scoreId] += scriptNumberArray[2] & 0xFF;
_npcBuf[npcId]._activeScore[scoreId] -= scriptNumberArray[3] & 0xFF;
}
}
break;
case 0x06:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
int16 npcId = _teamChar[scriptNumberArray[0]]._id;
if (npcId != -1) {
int16 scoreId = scriptNumberArray[1];
_npcBuf[npcId]._activeScore[scoreId] = scriptNumberArray[2] & 0xFF;
}
}
break;
case 0x07:
if (scriptExecuteFlag) {
totalPartyKill();
}
break;
case 0x08:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag && scriptNumberArray[0] != -1) {
_npcBuf[_teamChar[scriptNumberArray[0]]._id]._hitPoints = 0;
}
break;
case 0x09:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
int16 npcId = _teamChar[scriptNumberArray[0]]._id;
if (npcId != -1) {
_npcBuf[npcId]._hitPoints += getRandom(scriptNumberArray[1]);
if (_npcBuf[npcId]._hitPoints > _npcBuf[npcId]._maxHP)
_npcBuf[npcId]._hitPoints = _npcBuf[npcId]._maxHP;
}
}
break;
case 0x0A:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
int16 npcId = _teamChar[scriptNumberArray[0]]._id;
if (npcId != -1) {
_npcBuf[npcId]._hitPoints = _npcBuf[npcId]._maxHP;
}
}
break;
case 0x0B:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
int16 npcId = _teamChar[scriptNumberArray[0]]._id;
if (npcId != -1) {
_npcBuf[npcId]._hitPoints -= getRandom(scriptNumberArray[1]);
if (_npcBuf[npcId]._hitPoints < 0)
_npcBuf[npcId]._hitPoints = 0;
}
}
break;
case 0x0C:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
int16 scriptItemId = scriptNumberArray[0];
bool found = false;
for (int counter = 0; counter < _teamSize && !found; ++counter) {
for (uint objectId = 0; objectId < 10; ++objectId) {
if (_npcBuf[_teamChar[counter]._id]._inventory[objectId]._ref == scriptItemId) {
removeObject(_teamChar[counter]._id, objectId);
found = true;
break;
}
}
}
}
break;
case 0x0D:
// Put item in inventory { objectId }
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
int16 scriptObjectId = scriptNumberArray[0];
for (int counter = 0; counter < _teamSize; ++counter) {
if (giveItemTo(_teamChar[counter]._id, scriptObjectId, 0xFF))
break;
}
}
break;
case 0x0E:
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
int16 scriptItemId = scriptNumberArray[0];
bool found = false;
for (int counter = 0; counter < _teamSize && !found; ++counter) {
for (uint objectId = 0; objectId < 10; ++objectId) {
if (_npcBuf[_teamChar[counter]._id]._inventory[objectId]._ref == scriptItemId) {
found = true;
break;
}
}
}
if (found)
retVal = scriptNumberArray[1];
else
retVal = scriptNumberArray[2];
}
break;
case 0x0F:
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
if (isNpcATeamMember(scriptNumberArray[0]))
retVal = scriptNumberArray[1];
else
retVal = scriptNumberArray[2];
}
break;
case 0x10:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag)
retVal = scriptNumberArray[0];
break;
case 0x11:
if (scriptExecuteFlag)
_alertDelay = 0;
break;
case 0x12:
// Disable special tile
if (scriptExecuteFlag) {
int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY);
if (tileId != -1)
_mapSpecialTiles[_techId][tileId]._posX = 0xFF;
}
break;
case 0x13:
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag && _largeMapFlag) {
_textBoxDisabledByScriptFl = true;
loadPlacesFile(scriptNumberArray[0], false);
transitionMap(scriptNumberArray[1], scriptNumberArray[2]);
setSpecialTechZone(scriptNumberArray[0], scriptNumberArray[1], scriptNumberArray[2]);
retVal = -1;
}
break;
case 0x14:
// Add character to team { charId }
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
int16 scriptNpcId = scriptNumberArray[0];
if (!isNpcATeamMember(scriptNpcId))
joiningNpcId = scriptNpcId;
retVal = -1;
}
break;
case 0x15:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
_oldMapPosX = _mapPosX = scriptNumberArray[0];
_oldMapPosY = _mapPosY = scriptNumberArray[1];
_largeMapFlag = true;
_redrawNeededFl = true;
}
break;
case 0x16:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
int16 scriptNpcId = scriptNumberArray[0];
for (uint counter = 0; counter < 3; ++counter) {
if (_teamChar[counter]._id == scriptNpcId) {
removeCharacterFromTeam(counter);
break;
}
}
}
break;
case 0x17:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
int16 animId = scriptNumberArray[0];
displayAnimFrames(animId, true);
}
break;
case 0x18:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
bool found = false;
int16 scriptRandomItemId = getRandom(scriptNumberArray[1] - scriptNumberArray[0] + 1) + scriptNumberArray[0] - 1;
int16 counter;
for (counter = 0; counter < _teamSize; ++counter) {
if (giveItemTo(_teamChar[counter]._id, scriptRandomItemId, 0xFF)) {
found = true;
break;
}
}
if (!found) {
drawMapWindow();
displayFctFullScreen();
drawMapWindow();
scriptRandomItemId = displayBoxWithText("Nothing...", 1, 2, true);
displayFctFullScreen();
} else {
_enemyNamePt2 = _npcBuf[_teamChar[counter]._id]._name;
_nameBuffer = _items[scriptRandomItemId]._name;
curLine = Common::String::format("%s finds a %s!", _enemyNamePt2.c_str(), _nameBuffer.c_str());
drawMapWindow();
displayFctFullScreen();
drawMapWindow();
scriptRandomItemId = displayBoxWithText(curLine, 1, 2, true);
displayFctFullScreen();
}
int16 tileId = findMapSpecialTileIndex(_mapPosX, _mapPosY);
if (tileId != -1) {
// Disable special tile
_mapSpecialTiles[_techId][tileId]._posX = 0xFF;
}
_redrawNeededFl = true;
}
break;
case 0x19:
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
if (_largeMapFlag) {
_mapGameMaps[_techId][scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF;
} else {
_curPlace[scriptNumberArray[0]][scriptNumberArray[1]] = scriptNumberArray[2] & 0xFF;
}
}
break;
case 0x1A:
buffer = script_readNumberArray(buffer, 2, scriptNumberArray);
if (scriptExecuteFlag) {
int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]);
if (tileId != -1) {
// Disable tile
_mapSpecialTiles[_techId][tileId]._posX = 0xFF;
}
}
break;
case 0x1B:
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
int16 tileId = findMapSpecialTileIndex(scriptNumberArray[0], scriptNumberArray[1]);
if (tileId != -1) {
// Disable tile
_mapSpecialTiles[_techId][tileId]._posX = 0xFF;
}
_mapSpecialTiles[_techId][scriptNumberArray[2]]._posX = scriptNumberArray[0];
_mapSpecialTiles[_techId][scriptNumberArray[2]]._posY = scriptNumberArray[1];
}
break;
case 0x1C:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
_history[scriptNumberArray[0]] = 0xFF;
}
break;
case 0x1D:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag) {
_history[scriptNumberArray[0]] = 0;
}
break;
case 0x1E:
// Dialog with condition { historyId, dialogId1, dialogId2 }
buffer = script_readNumberArray(buffer, 3, scriptNumberArray);
if (scriptExecuteFlag) {
if (_history[scriptNumberArray[0]] == 0)
retVal = scriptNumberArray[2];
else
retVal = scriptNumberArray[1];
}
break;
case 0x1F:
buffer = script_readNumberArray(buffer, 1, scriptNumberArray);
if (scriptExecuteFlag)
_alertDelay = scriptNumberArray[0];
break;
case 0x20:
if (scriptExecuteFlag) {
handleWinSequence();
_system->quit();
}
default:
break;
}
}
if (!curLine.empty() && curLineNb < numbLines && !noTextFlag)
displayStringAtTextPos(curLine);
if (joiningNpcId != 0xFF) {
displayLowStatusScreen(true);
int16 teamSlot = handleCharacterJoining();
if (teamSlot > -1) {
_teamChar[teamSlot]._id = joiningNpcId;
}
refreshTeamSize();
_sayLowStatusScreen = true;
}
return retVal;
}
} // End of namespace Efh

280
engines/efh/sound.cpp Normal file
View File

@@ -0,0 +1,280 @@
/* 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 "efh/efh.h"
namespace Efh {
void EfhEngine::songDelay(int delay) {
debugC(3, kDebugEngine, "songDelay %d", delay);
int remainingDelay = delay / 2;
while (remainingDelay > 0 && !shouldQuit()) {
remainingDelay -= 3;
_system->delayMillis(3);
}
}
void EfhEngine::playNote(int frequencyIndex, int totalDelay) {
debugC(3, kDebugEngine, "playNote %d %d", frequencyIndex, totalDelay);
if (frequencyIndex > 0 && frequencyIndex < 72) {
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, 0x1234DD / kSoundFrequency[frequencyIndex], -1);
songDelay(totalDelay);
_speaker->stop();
} else {
warning("playNote - Skip note with frequency index %d", frequencyIndex);
}
}
Common::CustomEventType EfhEngine::playSong(uint8 *buffer) {
debugC(3, kDebugEngine, "playSong");
_speaker = new Audio::PCSpeaker();
_speaker->init();
Common::CustomEventType inputAction = kActionNone;
int totalDelay = 0;
int8 stopFl;
uint8 varC = *buffer++;
Common::Event event;
do {
stopFl = *buffer & 0x3F;
if (stopFl != 0) {
int delay = stopFl * varC * 0x2200 / 1000;
if (*buffer > 0x7F)
delay /= 2;
if (*buffer & 0x40)
delay = (delay * 2) / 3;
++buffer;
uint8 frequencyIndex = *buffer;
++buffer;
if (frequencyIndex > 0x7F)
totalDelay += delay;
else if (frequencyIndex == 0)
songDelay(delay);
else {
playNote(frequencyIndex, totalDelay + delay);
totalDelay = 0;
}
}
songDelay(10);
_system->getEventManager()->pollEvent(event);
if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
inputAction = event.customType;
// Hack, sometimes there's a ghost event after the 2nd note
if (inputAction == kActionSkipSong || inputAction == kActionSkipSongAndIntro)
stopFl = 0;
}
} while (stopFl != 0 && !shouldQuit());
delete _speaker;
_speaker = nullptr;
return inputAction;
}
void EfhEngine::generateSound1(int lowFreq, int highFreq, int duration) {
debugC(3, kDebugEngine, "generateSound1 %d %d %d - suspicious code", lowFreq, highFreq, duration);
if (lowFreq < 19)
lowFreq = 19;
if (highFreq < 19)
highFreq = 19;
uint16 var2 = 0;
duration /= 20;
_speaker = new Audio::PCSpeaker();
_speaker->init();
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, highFreq, -1);
songDelay(10);
_speaker->stop();
for (int i = 0; i < duration; ++i) {
var2 = ROR(var2 + 0x9248, 3);
int val = (var2 * (highFreq - lowFreq)) >> 16;
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, lowFreq + val, -1);
songDelay(10);
_speaker->stop();
}
delete _speaker;
_speaker = nullptr;
}
void EfhEngine::generateSound2(int startFreq, int endFreq, int speed) {
debugC(3, kDebugEngine, "generateSound2 %d %d %d", startFreq, endFreq, speed);
if (startFreq < 19)
startFreq = 19;
if (endFreq < 19)
endFreq = 19;
int delta;
// The original is using -/+1 but it takes ages even with speed / 10, so I switched to -/+5
if (startFreq > endFreq)
delta = -50;
else
delta = 50;
_speaker = new Audio::PCSpeaker();
_speaker->init();
int curFreq = startFreq;
do {
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, curFreq, -1);
// The original is just looping, making the sound improperly timed as the length of a loop is directly related to the speed of the CPU
// Dividing by 10 is just a guess based on how it sounds. I suspect it may be still too much
songDelay(speed);
_speaker->stop();
curFreq += delta;
} while (curFreq < endFreq && !shouldQuit());
delete _speaker;
_speaker = nullptr;
}
void EfhEngine::generateSound3() {
debugC(3, kDebugEngine, "generateSound3");
_speaker = new Audio::PCSpeaker();
_speaker->init();
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, 88, -1);
// The original makes me think the delay is so short it's not possible to hear. So that delay is guessed (and short)
songDelay(30);
_speaker->stop();
delete _speaker;
_speaker = nullptr;
}
void EfhEngine::generateSound4(int repeat) {
debugC(3, kDebugEngine, "generateSound4 %d", repeat);
for (int i = 0; i < repeat; ++i)
//It looks identical, so I'm reusing generateSound1
generateSound1(256, 4096, 10);
}
void EfhEngine::generateSound5(int repeat) {
debugC(3, kDebugEngine, "generateSound5 %d", repeat);
for (int i = 0; i < repeat; ++i)
//It looks identical, so I'm reusing generateSound2
generateSound2(256, 4096, 2);
}
void EfhEngine::generateSound(int16 soundType) {
debugC(3, kDebugEngine, "generateSound %d", soundType);
switch (soundType) {
case 5:
generateSound3();
break;
case 9:
generateSound1(20, 888, 500);
g_system->delayMillis(100);
generateSound1(20, 888, 500);
break;
case 10:
generateSound5(1);
break;
case 13:
generateSound2(256, 4096, 2);
break;
case 14:
generateSound2(20, 400, 20);
break;
case 15:
generateSound2(100, 888, 10);
break;
case 16:
generateSound1(2000, 6096, 1500);
break;
case 17:
generateSound4(1);
break;
default:
debug("generateSound %d - Not implemented because not used by the engine", soundType);
break;
}
}
void EfhEngine::genericGenerateSound(int16 soundType, int16 repeatCount) {
debugC(3, kDebugEngine, "genericGenerateSound %d %d", soundType, repeatCount);
if (repeatCount <= 0)
return;
switch (soundType) {
case 0:
case 1:
case 2:
generateSound(5);
break;
case 3:
case 4:
case 6:
generateSound(9);
break;
case 5:
case 7:
generateSound(13);
break;
case 8:
case 9:
case 10:
generateSound(10);
g_system->delayMillis(100);
generateSound(9);
break;
case 14:
generateSound(14);
break;
case 11:
case 12:
case 13:
for (int counter = 0; counter < repeatCount; ++counter) {
generateSound(17);
g_system->delayMillis(100);
}
break;
case 15:
generateSound(16);
default:
break;
}
}
} // End of namespace Efh

297
engines/efh/utils.cpp Normal file
View File

@@ -0,0 +1,297 @@
/* 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 "common/config-manager.h"
#include "common/system.h"
#include "common/random.h"
#include "efh/efh.h"
#include "backends/keymapper/keymapper.h"
namespace Efh {
void EfhEngine::decryptImpFile(bool techMapFl) {
debugC(1, kDebugUtils, "decryptImpFile %s", techMapFl ? "True" : "False");
uint16 counter = 0;
uint16 target;
uint8 *curPtr;
if (!techMapFl) {
_imp2PtrArray[counter++] = curPtr = _imp2;
target = 431;
} else {
_imp1PtrArray[counter++] = curPtr = _imp1;
target = 99;
}
do {
*curPtr = (*curPtr - 3) ^ 0xD7;
if (*curPtr == 0x40) {
curPtr += 3;
if (!techMapFl)
_imp2PtrArray[counter++] = curPtr;
else
_imp1PtrArray[counter++] = curPtr;
} else
++curPtr;
} while (*curPtr != 0x60 && counter <= target && !shouldQuit());
if (ConfMan.getBool("dump_scripts")) {
// Dump the decompressed IMP file
Common::DumpFile dump;
if (!techMapFl) {
dump.open("imp2_unc.dump");
dump.write(_imp2, curPtr - _imp2);
} else {
dump.open("imp1_unc.dump");
dump.write(_imp1, curPtr - _imp1);
}
dump.flush();
dump.close();
}
}
void EfhEngine::loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer) {
debugC(1, kDebugUtils, "loadImageSet %d", imageSetId);
Common::Path fileName(Common::String::format("imageset.%d", imageSetId));
rImageFile(fileName, buffer, subFilesArray, destBuffer);
}
uint32 EfhEngine::uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf) {
debugC(1, kDebugUtils, "uncompressBuffer");
if (compressedBuf == nullptr || destBuf == nullptr)
error("uncompressBuffer - Invalid pointer used in parameter list");
uint8 *curPtrDest = destBuf;
uint16 compSize = READ_LE_UINT16(compressedBuf) + 1;
uint8 *curPtrCompressed = compressedBuf + 2;
// Not in the original. This has been added for debug purposes (the original function doesn't return a value)
uint32 decompSize = 0;
for (;;) {
uint8 next = *curPtrCompressed++;
if (--compSize <= 0)
break;
if (next != 0xC3) {
*curPtrDest++ = next;
++decompSize;
continue;
}
next = *curPtrCompressed++;
if (--compSize <= 0)
break;
if (next == 0) {
*curPtrDest++ = 0xC3;
++decompSize;
continue;
}
uint8 loopVal = next;
next = *curPtrCompressed++;
for (int i = 0; i < loopVal; ++i) {
*curPtrDest++ = next;
++decompSize;
}
--compSize;
if (compSize == 0)
break;
}
curPtrDest[0] = curPtrDest[1] = 0;
decompSize += 2;
return decompSize;
}
int16 EfhEngine::getRandom(int16 maxVal) {
debugC(1, kDebugUtils, "getRandom %d", maxVal);
if (maxVal <= 0)
return 0;
return 1 + _rnd->getRandomNumber(maxVal - 1);
}
Common::CustomEventType EfhEngine::getLastCharAfterAnimCount(int16 delay, bool waitForTTS) {
debugC(1, kDebugUtils, "getLastCharAfterAnimCount %d", delay);
if (delay == 0)
return kActionNone;
Common::CustomEventType action = kActionNone;
uint32 lastMs = _system->getMillis();
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
while ((delay > 0 || (waitForTTS && ttsMan && ttsMan->isSpeaking())) && action == kActionNone && !shouldQuit()) {
_system->delayMillis(20);
uint32 newMs = _system->getMillis();
if (newMs - lastMs >= 200) {
lastMs = newMs;
--delay;
handleAnimations();
}
action = handleAndMapInput(false);
}
if (waitForTTS) {
stopTextToSpeech();
}
return action;
}
Common::CustomEventType EfhEngine::getInput(int16 delay) {
debugC(1, kDebugUtils, "getInput %d", delay);
if (delay == 0)
return kActionNone;
Common::CustomEventType lastAction = kActionNone;
Common::CustomEventType retVal = kActionNone;
uint32 lastMs = _system->getMillis();
Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
while ((delay > 0 || (ttsMan && ttsMan->isSpeaking())) && !shouldQuit()) {
_system->delayMillis(20);
uint32 newMs = _system->getMillis();
if (newMs - lastMs >= 200) {
lastMs = newMs;
--delay;
handleAnimations();
}
lastAction = handleAndMapInput(false);
if (lastAction != kActionNone)
retVal = lastAction;
}
return retVal;
}
Common::CustomEventType EfhEngine::waitForKey() {
debugC(1, kDebugUtils, "waitForKey");
Common::CustomEventType retVal = kActionNone;
Common::Event event;
uint32 lastMs = _system->getMillis();
while (retVal == kActionNone && !shouldQuit()) {
_system->delayMillis(20);
uint32 newMs = _system->getMillis();
if (newMs - lastMs >= 200) {
lastMs = newMs;
handleAnimations();
}
_system->getEventManager()->pollEvent(event);
switch (event.type) {
case Common::EVENT_KEYUP:
retVal = kActionNo;
break;
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
if (event.customType == kActionQuit) {
quitGame();
} else
retVal = event.customType;
break;
default:
break;
}
}
return retVal;
}
Common::CustomEventType EfhEngine::handleAndMapInput(bool animFl) {
debugC(1, kDebugUtils, "handleAndMapInput %s", animFl ? "True" : "False");
// The original checks for the joystick input
Common::Event event;
_system->getEventManager()->pollEvent(event);
Common::CustomEventType retVal = kActionNone;
uint32 lastMs = _system->getMillis();
while (retVal == kActionNone && !shouldQuit()) {
_system->getEventManager()->pollEvent(event);
if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
if (event.customType == kActionQuit)
quitGame();
else
retVal = event.customType;
}
if (animFl) {
_system->delayMillis(20);
uint32 newMs = _system->getMillis();
if (newMs - lastMs >= 200) {
lastMs = newMs;
handleAnimations();
}
} else
break;
}
return retVal;
}
bool EfhEngine::getValidationFromUser() {
debugC(1, kDebugUtils, "getValidationFromUser");
setKeymap(kKeymapMenu);
Common::CustomEventType action = handleAndMapInput(true);
setKeymap(kKeymapDefault);
if (action == kActionYes) // or if joystick button 1
return true;
return false;
}
uint32 EfhEngine::ROR(uint32 val, uint8 shiftVal) {
return val >> shiftVal | val << (32 - shiftVal);
}
Common::String EfhEngine::getArticle(int pronoun) {
if (pronoun == 2)
return "The ";
return "";
}
void EfhEngine::setKeymap(EfhKeymapCode keymapCode) {
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
keymapper->disableAllGameKeymaps();
keymapper->getKeymap("efh-quit")->setEnabled(true);
for(int i = 0;i < ARRAYSIZE(_efhKeymaps); ++i) {
if (_efhKeymaps[i]._keymap == keymapCode) {
keymapper->getKeymap(_efhKeymaps[i]._id)->setEnabled(true);
break;
}
}
}
} // End of namespace Efh