[Scummvm-git-logs] scummvm master -> 6e098aad9525e1a0815d6bfd3ccec02e1f945b55
dreammaster
noreply at scummvm.org
Sun Jan 4 05:53:40 UTC 2026
This automated email contains information about 62 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
b53ed944a9 ULTIMA: ULTIMA0: Engine import
d81d1d8942 ULTIMA: ULTIMA0: Added view-based engine skeleton
eb132e9f72 ULTIMA: ULTIMA0: Added GfxSurface and Font classes
4137c59b52 ULTIMA: ULTIMA0: Data cleanup, startup screen text
76481b8c5f ULTIMA: ULTIMA0: Reduce resolution to make font match original
1756d22e49 ULTIMA: ULTIMA0: Title screen
f3c3c74c85 ULTIMA: ULTIMA0: Show mouse cursor on mouse move
cc2262aa12 ULTIMA: ULTIMA0: Add mouse handling to title screen
17de45134d ULTIMA: ULTIMA0: Added Create Character view
bae71ae790 ULTIMA: ULTIMA0: Added Town view
6a8d468d24 ULTIMA: ULTIMA0: Beginnings of world map rendering
e439b5c05f ULTIMA: ULTIMA0: Added map status display
3154e69b96 ULTIMA: ULTIMA0: Adding savegame code
eb6b0dc7e9 ULTIMA: ULTIMA0: Don't set Level field of PLAYER structure
04b4a94336 ULTIMA: ULTIMA0: Further savegame code
db6bb3ef1e ULTIMA: ULTIMA0: Starting on world map commands
3445ec9302 ULTIMA: ULTIMA0: Added Info screen
b65aac6c30 ULTIMA: ULTIMA0: More keybindings setup
7dd069ed7d ULTIMA: ULTIMA0: Added Dead view
49b282d50c ULTIMA: ULTIMA0: Adding overworld movement
857632dacf ULTIMA: ULTIMA0: Dungeon creation logic
c4416b982f ULTIMA: ULTIMA0: Added Castle view
df502806e1 ULTIMA: ULTIMA0: Savegame fixes, keybinding fix
45901d3446 ULTIMA: ULTIMA0: Extra console commands
20ead6582a ULTIMA: ULTIMA0: In progress dungeon drawing
5dd272725a ULTIMA: ULTIMA0: Further dungeon drawing work
68bca61e00 ULTIMA: ULTIMA0: Fix aspect ratio of dungeon rendering
cb44874c2a ULTIMA: ULTIMA0: Display direction in Dungeon status area
fe5368591a ULTIMA: ULTIMA0: Adding dungeon movement
5819ba67dc ULTIMA: ULTIMA0: Dungeon rendering cleanup
b7e0257de7 ULTIMA: ULTIMA0: Fix ladder display
5fecb72f18 ULTIMA: ULTIMA0: Implement dungeon status messages
15d2deed5a ULTIMA: ULTIMA0: Fix entering/exiting dungeon
55dbb7831c ULTIMA: ULTIMA0: Fixes for monster rendering
68860b26e8 ULTIMA: ULTIMA0: Added monster attacking logic
a47c659181 ULTIMA: ULTIMA0: Cleanup of monster attack logic
27e0a2d51a ULTIMA: ULTIMA0: Adding keybinding modes
1b42abbaf5 ULTIMA: ULTIMA0: Beginnings of attack selection view
f44ad9a93b ULTIMA: ULTIMA0: Fleshing out attack details view
1ea0551b6f ULTIMA: ULTIMA0: Add Akalabeth project author to credits
5c57c86765 ULTIMA: ULTIMA0: Remove original project files
bb5560ce62 ULTIMA: ULTIMA0: Added Overworld minimap
97d1befc51 ULTIMA: ULTIMA0: Added dungeon minimap
09cb65ce8a ULTIMA: ULTIMA0: Janitorial
3e04f40bbb ULTIMA: ULTIMA0: Janitorial
679c39ec13 ULTIMA: ULTIMA0: Change monster list to use Common::Array
7067bf938e ULTIMA: ULTIMA0: Further janitorial
80813edddf ULTIMA: ULTIMA0: Renaming structure fields
40efc19b9b ULTIMA: ULTIMA0: Add missing monster data from savegames
77da654dd6 ULTIMA: ULTIMA0: Method renaming janitorial
4fd2c21ca7 ULTIMA: ULTIMA0: Comments cleanup
b70459b351 ULTIMA: ULTIMA0: Fix monster appearance probability
a24abbebbd ULTIMA: ULTIMA0: Fix mixed up x/y params in monster drawing code
c6ffbce7bb ULTIMA: ULTIMA0: Monster rendering fixes
74a39a6805 ULTIMA: ULTIMA0: Fix dungeon messages to start at X = 1
9b0753d16f ULTIMA: ULTIMA0: Intro screen
81a48f6a64 ULTIMA: ULTIMA0: Added Acknowledgements view
eedc281132 ULTIMA: ULTIMA0: Switching more keys to keybinder
d1d7e7ed1d ULTIMA: ULTIMA0: Implement Title screen Journey Onwards option
d77d243dfa ULTIMA: ULTIMA0: Keybinder fixes
0410d08f75 ULTIMA: ULTIMA0: Added missing pages to Intro view
6e098aad95 ULTIMA: ULTIMA0: Add music player
Commit: b53ed944a911f45ddfd9fa379b5a098bab5eb71c
https://github.com/scummvm/scummvm/commit/b53ed944a911f45ddfd9fa379b5a098bab5eb71c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:22+11:00
Commit Message:
ULTIMA: ULTIMA0: Engine import
Changed paths:
A engines/ultima/ultima0/akalabeth.h
A engines/ultima/ultima0/attack.cpp
A engines/ultima/ultima0/british.cpp
A engines/ultima/ultima0/ddraw.cpp
A engines/ultima/ultima0/dead.cpp
A engines/ultima/ultima0/defines.h
A engines/ultima/ultima0/draw.cpp
A engines/ultima/ultima0/draw2.cpp
A engines/ultima/ultima0/draw3.cpp
A engines/ultima/ultima0/dungeon.cpp
A engines/ultima/ultima0/globals.cpp
A engines/ultima/ultima0/hardware.cpp
A engines/ultima/ultima0/main.cpp
A engines/ultima/ultima0/monst.cpp
A engines/ultima/ultima0/move.cpp
A engines/ultima/ultima0/player.cpp
A engines/ultima/ultima0/sdw.cpp
A engines/ultima/ultima0/sdw.h
A engines/ultima/ultima0/struct.h
A engines/ultima/ultima0/town.cpp
A engines/ultima/ultima0/ultima0.cpp
A engines/ultima/ultima0/ultima0.h
A engines/ultima/ultima0/world.cpp
R engines/ultima/ultima0/core/resources.cpp
R engines/ultima/ultima0/core/resources.h
R engines/ultima/ultima0/game.cpp
R engines/ultima/ultima0/game.h
R engines/ultima/ultima0/resources.cpp
R engines/ultima/ultima0/resources.h
engines/ultima/configure.engine
engines/ultima/detection.cpp
engines/ultima/detection_tables.h
engines/ultima/metaengine.cpp
engines/ultima/module.mk
diff --git a/engines/ultima/configure.engine b/engines/ultima/configure.engine
index 48b47d54563..3be6c69e0bb 100644
--- a/engines/ultima/configure.engine
+++ b/engines/ultima/configure.engine
@@ -1,6 +1,7 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
-add_engine ultima "Ultima" yes "ultima1 ultima4 ultima6 ultima8" "" "midi"
+add_engine ultima "Ultima" yes "akalabeth ultima1 ultima4 ultima6 ultima8" "" "midi"
+add_engine akalabeth "Akalabeth" no "" "" ""
add_engine ultima1 "Ultima I - The First Age of Darkness" no "" "" ""
add_engine ultima4 "Ultima IV - Quest of the Avatar" yes "" "" "16bit"
add_engine ultima6 "Ultima VI = The False Prophet" yes "" "" "highres 16bit lua"
diff --git a/engines/ultima/detection.cpp b/engines/ultima/detection.cpp
index c3df3b1cc77..3128203618c 100644
--- a/engines/ultima/detection.cpp
+++ b/engines/ultima/detection.cpp
@@ -27,29 +27,6 @@
#include "ultima/detection_tables.h"
#include "ultima/ultima.h"
-namespace Ultima {
-
-static const PlainGameDescriptor ULTIMA_GAMES[] = {
-#ifndef RELEASE_BUILD
- { "ultima1", "Ultima I: The First Age of Darkness" },
-#endif
- { "ultima4", "Ultima IV: Quest of the Avatar" },
- { "ultima4_enh", "Ultima IV: Quest of the Avatar - Enhanced" },
- { "ultima6", "Ultima VI: The False Prophet" },
- { "ultima6_enh", "Ultima VI: The False Prophet - Enhanced" },
- { "ultima8", "Ultima VIII: Pagan" },
- { "remorse", "Crusader: No Remorse" },
- { "regret", "Crusader: No Regret" },
-
- { "martiandreams", "Worlds of Ultima: Martian Dreams" },
- { "martiandreams_enh", "Worlds of Ultima: Martian Dreams - Enhanced" },
- { "thesavageempire", "Worlds of Ultima: The Savage Empire" },
- { "thesavageempire_enh", "Worlds of Ultima: The Savage Empire - Enhanced" },
- { 0, 0 }
-};
-
-} // End of namespace Ultima
-
const DebugChannelDef UltimaMetaEngineDetection::debugFlagList[] = {
{Ultima::kDebugPath, "Path", "Pathfinding debug level"},
{Ultima::kDebugGraphics, "Graphics", "Graphics debug level"},
diff --git a/engines/ultima/detection_tables.h b/engines/ultima/detection_tables.h
index 4e72f9f1091..4d3917b69fc 100644
--- a/engines/ultima/detection_tables.h
+++ b/engines/ultima/detection_tables.h
@@ -21,6 +21,7 @@
namespace Ultima {
+#define GUI_OPTIONS_ULTIMA0 GUIO0()
#define GUI_OPTIONS_ULTIMA1 GUIO0()
#define GUI_OPTIONS_ULTIMA4 GUIO1(GUIO_NOSPEECH)
#define GUI_OPTIONS_ULTIMA6 GUIO0()
@@ -45,7 +46,42 @@ namespace Ultima {
// Ultima 6 normal mode only - unstable (currently only used for the PC98 version)
#define ENTRY_ULTIMA6_NORMAL_UNSTABLE(FILENAME, MD5, FILESIZE, LANG, PLATFORM) {{"ultima6", 0, AD_ENTRY1s(FILENAME, MD5, FILESIZE), LANG, PLATFORM, ADGF_UNSTABLE, GUI_OPTIONS_ULTIMA6}, GAME_ULTIMA6, 0}
+static const PlainGameDescriptor ULTIMA_GAMES[] = {
+ { "akalabeth", "Akalabeth: World of Doom" },
+#ifndef RELEASE_BUILD
+ { "ultima1", "Ultima I: The First Age of Darkness" },
+#endif
+ { "ultima4", "Ultima IV: Quest of the Avatar" },
+ { "ultima4_enh", "Ultima IV: Quest of the Avatar - Enhanced" },
+ { "ultima6", "Ultima VI: The False Prophet" },
+ { "ultima6_enh", "Ultima VI: The False Prophet - Enhanced" },
+ { "ultima8", "Ultima VIII: Pagan" },
+ { "remorse", "Crusader: No Remorse" },
+ { "regret", "Crusader: No Regret" },
+
+ { "martiandreams", "Worlds of Ultima: Martian Dreams" },
+ { "martiandreams_enh", "Worlds of Ultima: Martian Dreams - Enhanced" },
+ { "thesavageempire", "Worlds of Ultima: The Savage Empire" },
+ { "thesavageempire_enh", "Worlds of Ultima: The Savage Empire - Enhanced" },
+ { 0, 0 }
+};
+
static const UltimaGameDescription GAME_DESCRIPTIONS[] = {
+ {
+ // Akalabeth: World of Doom
+ {
+ "akalabeth",
+ nullptr,
+ AD_ENTRY1s("ak.dat", "f083346a49f450319a624d170a55d9e3", 17241),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUI_OPTIONS_ULTIMA0
+ },
+ GAME_AKALABETH,
+ 0
+ },
+
{
// Ultima I - The First Age of Darkness
{
diff --git a/engines/ultima/metaengine.cpp b/engines/ultima/metaengine.cpp
index bb6d7599e61..11cf23ac78b 100644
--- a/engines/ultima/metaengine.cpp
+++ b/engines/ultima/metaengine.cpp
@@ -27,6 +27,9 @@
#include "common/str-array.h"
#include "common/memstream.h"
#include "common/translation.h"
+#ifdef ENABLE_AKALABETH
+#include "ultima/ultima0/ultima0.h"
+#endif
#ifdef ENABLE_ULTIMA1
#include "ultima/shared/early/ultima_early.h"
#endif
@@ -181,6 +184,11 @@ const ADExtraGuiOptionsMap *UltimaMetaEngine::getAdvancedExtraGuiOptions() const
Common::Error UltimaMetaEngine::createInstance(OSystem *syst, Engine **engine, const Ultima::UltimaGameDescription *gd) const {
switch (gd->gameId) {
+#ifdef ENABLE_AKALABETH
+ case Ultima::GAME_AKALABETH:
+ *engine = new Ultima::Ultima0::Ultima0Engine(syst, gd);
+ break;
+#endif
#ifdef ENABLE_ULTIMA1
case Ultima::GAME_ULTIMA1:
*engine = new Ultima::Shared::UltimaEarlyEngine(syst, gd);
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index bd979093b3b..763851d3d50 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -6,6 +6,29 @@ MODULE_OBJS := \
shared/conf/xml_tree.o \
shared/engine/data_archive.o
+ifdef ENABLE_AKALABETH
+MODULE_OBJS += \
+ ultima0/ultima0.o \
+ ultima0/attack.o \
+ ultima0/british.o \
+ ultima0/ddraw.o \
+ ultima0/dead.o \
+ ultima0/draw.o \
+ ultima0/draw2.o \
+ ultima0/draw3.o \
+ ultima0/dungeon.o \
+ ultima0/globals.o \
+ ultima0/hardware.o \
+ ultima0/hdr.o \
+ ultima0/main.o \
+ ultima0/monst.o \
+ ultima0/move.o \
+ ultima0/player.o \
+ ultima0/sdw.o \
+ ultima0/town.o \
+ ultima0/world.o
+endif
+
ifdef ENABLE_ULTIMA1
MODULE_OBJS += \
shared/actions/action.o \
@@ -53,9 +76,6 @@ MODULE_OBJS += \
shared/maps/map_tile.o \
shared/maps/map_widget.o \
shared/maps/creature.o \
- ultima0/core/resources.o \
- ultima0/game.o \
- ultima0/resources.o \
ultima1/actions/action.o \
ultima1/actions/attack.o \
ultima1/actions/move.o \
diff --git a/engines/ultima/ultima0/akalabeth.h b/engines/ultima/ultima0/akalabeth.h
new file mode 100644
index 00000000000..c725eacdf4e
--- /dev/null
+++ b/engines/ultima/ultima0/akalabeth.h
@@ -0,0 +1,91 @@
+/* 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 ULTIMA_ULTIMA0_AKALABETH_H
+#define ULTIMA_ULTIMA0_AKALABETH_H
+
+#include "common/str.h"
+#include "ultima/ultima0/struct.h" /* Our structure file */
+
+namespace Ultima {
+namespace Ultima0 {
+
+void HWInitialise(void); /* HARDWARE.C prototyping */
+void HWTerminate(void);
+void HWColour(int);
+void HWLine(int, int, int, int);
+void HWStatus(double, int, int);
+void HWChar(int);
+int HWGetKey(void);
+void HWClear(void);
+
+void DRAWTile(RECT *, int); /* DRAW.C prototyping */
+void DRAWSetRect(RECT *, int, int, int, int);
+void DRAWMonster(int, int, int, double);
+void DRAWDungeon(RECT *, RECT *, int, int, int, int, int);
+void DRAWText(const char *, ...);
+
+void MONSTAttack(PLAYER *, DUNGEONMAP *); /* MONST.C prototyping */
+
+int MAINSuper(void); /* MAIN.C prototyping */
+void MAINSetup(void);
+void MAINStart(void);
+
+void PLAYERInit(PLAYER *); /* PLAYER.C prototyping */
+void PLAYERDebug(PLAYER *);
+void PLAYERDemo(PLAYER *);
+void PLAYERCharacter(PLAYER *);
+void PLAYERInv(PLAYER *);
+
+void DEADCode(PLAYER *); /* DEAD.C prototyping */
+int DEADGetYesNo(void);
+
+const char *GLOObjName(int); /* GLOBAL.C prototyping */
+const char *GLOAttribName(int);
+const char *GLOClassName(char);
+const char *GLOMonsterName(int);
+int GLOMonsterLevel(int);
+void GLOGetInfo(int n, int *, int *, int *);
+
+void TOWNEnter(WORLDMAP *, PLAYER *); /* TOWN.C prototyping */
+
+void BRITISHEnter(WORLDMAP *, PLAYER *); /* BRITISH.C prototyping */
+
+void WORLDCreate(PLAYER *, WORLDMAP *); /* WORLD.C prototyping */
+void WORLDDraw(PLAYER *, WORLDMAP *, int);
+int WORLDRead(WORLDMAP *, int, int);
+
+void DUNGEONCreate(PLAYER *, DUNGEONMAP *); /* DUNGEON.C prototyping */
+
+void DDRAWDraw(PLAYER *, DUNGEONMAP *); /* DDRAW.C prototyping */
+int DDRAWFindMonster(DUNGEONMAP *, COORD *);
+
+void ATTACKMonster(PLAYER *, DUNGEONMAP *); /* ATTACK.C prototyping */
+
+/* MOVE.C prototyping */
+void MOVEEnterExit(WORLDMAP *, PLAYER *, DUNGEONMAP *);
+void MOVEMove(int, WORLDMAP *, PLAYER *, DUNGEONMAP *, int, int);
+void MOVERotLeft(COORD *);
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/attack.cpp b/engines/ultima/ultima0/attack.cpp
new file mode 100644
index 00000000000..88e84e094fd
--- /dev/null
+++ b/engines/ultima/ultima0/attack.cpp
@@ -0,0 +1,263 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Attack any nearby monsters */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+static void _ATTACKWeapon(PLAYER *, DUNGEONMAP *, int);
+static int _ATTACKMissile(PLAYER *, DUNGEONMAP *, int);
+static void _ATTACKKill(MONSTER *, PLAYER *);
+static void _ATTACKAmulet(PLAYER *, DUNGEONMAP *);
+static void _ATTACKHitMonster(PLAYER *, DUNGEONMAP *, int, COORD *);
+
+/************************************************************************/
+/* */
+/* Attack any nearby monsters */
+/* */
+/************************************************************************/
+
+void ATTACKMonster(PLAYER *p, DUNGEONMAP *d) {
+ int c, Key, i, n, Damage;
+ DRAWText("With what ? "); /* Which weapon */
+ c = HWGetKey();
+ n = -1; /* Discover which. */
+ for (i = 0; i < p->Objects; i++)
+ {
+ GLOGetInfo(i, nullptr, nullptr, &Key); /* Get the associated key */
+ if (toupper(Key) == c) /* Found the object ? */
+ if (i != OB_FOOD) n = i;/* Not food ! */
+ }
+ if (n < 0) /* Check the result */
+ {
+ Damage = 0; DRAWText("Hands.\n");
+ } else
+ {
+ DRAWText("%s.\n", GLOObjName(n));
+ GLOGetInfo(n, &Damage, nullptr, nullptr);
+ }
+
+ if (p->Object[n] == 0) /* Must own an object */
+ {
+ DRAWText("Not owned.\n");
+ return;
+ }
+ if (p->Class == 'M' && /* Mages are limited */
+ (n == OB_BOW || n == OB_RAPIER))
+ {
+ DRAWText("Mages can't use\n%ss.\n", GLOObjName(n));
+ return;
+ }
+
+ if (n == OB_AMULET) /* Use an amulet */
+ {
+ _ATTACKAmulet(p, d);
+ return;
+ }
+
+ if (n == OB_BOW || n == OB_AXE) /* Check for axe work */
+ {
+ if (_ATTACKMissile(p, d, n) == 0) /* Throw code */
+ _ATTACKWeapon(p, d, n); /* if not thrown, use as weapon */
+ } else
+ _ATTACKWeapon(p, d, n); /* use as bashing weapon */
+}
+
+/************************************************************************/
+/* */
+/* Attack using object as a hand held weapon */
+/* */
+/************************************************************************/
+
+static void _ATTACKWeapon(PLAYER *p, DUNGEONMAP *d, int Weapon) {
+ COORD c;
+ c.x = p->Dungeon.x + p->DungDir.x; /* Look at what's there */
+ c.y = p->Dungeon.y + p->DungDir.y;
+ _ATTACKHitMonster(p, d, Weapon, &c);
+}
+
+/************************************************************************/
+/* */
+/* Use weapon on monster */
+/* */
+/************************************************************************/
+
+static void _ATTACKHitMonster(PLAYER *p, DUNGEONMAP *d, int Weapon, COORD *c) {
+ int n = 0, Monster, Damage;
+ MONSTER *m = nullptr;
+
+ Monster = DDRAWFindMonster(d, c); /* Is there a monster there ? */
+ if (Monster >= 0) /* Set up a pointer */
+ {
+ m = &(d->Monster[Monster]);
+ n = m->Type;
+ }
+
+ Damage = 0; /* Get weaponry info */
+ if (Weapon >= 0 && Weapon != OB_AMULET)
+ GLOGetInfo(Weapon, &Damage, nullptr, nullptr);
+ if (Weapon == OB_AMULET) /* Amulet Special Case */
+ Damage = 10 + p->Level;
+
+ if (Monster < 0 || /* If no, or not dexterous */
+ p->Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + p->Level)
+ {
+ DRAWText("You missed !!\n"); /* Then a miss. */
+ return;
+ }
+
+ DRAWText("Hit !!!\n"); /* Scored a hit */
+ n = 0; /* Calculate HPs lost */
+ if (Damage > 0) n = (urand() % Damage);
+ n = n + p->Attr[AT_STRENGTH] / 5;
+ m->Strength = m->Strength - n; /* Lose them */
+ if (m->Strength < 0) m->Strength = 0;
+ DRAWText("%s's Hit\nPoints now %d.\n", /* Display the HP Value */
+ GLOMonsterName(m->Type), m->Strength);
+ if (m->Strength == 0)_ATTACKKill(m, p); /* Killed it ? */
+
+}
+
+/************************************************************************/
+/* */
+/* Kill off a monster */
+/* */
+/************************************************************************/
+
+static void _ATTACKKill(MONSTER *m, PLAYER *p) {
+ int n;
+ m->Alive = 0; /* Deaded */
+ n = (m->Type + p->Level); /* Amount of Gold */
+ DRAWText("You get %d\npieces of eight.\n", n);
+ p->Attr[AT_GOLD] += n;
+ p->HPGain += (m->Type * p->Level) / 2; /* Calculate Gain */
+ if (m->Type == p->Task) /* Check done LB's task */
+ p->TaskCompleted = 1;
+}
+
+/************************************************************************/
+/* */
+/* Attack using object as a missile */
+/* */
+/************************************************************************/
+
+static int _ATTACKMissile(PLAYER *p, DUNGEONMAP *d, int Weapon) {
+ int n, y, Dist;
+ char ch;
+ COORD c, c1;
+ if (Weapon == OB_AXE) /* Axes can be thrown or swung */
+ {
+ DRAWText("Throw or Swing ? ");
+ while (ch = HWGetKey(), ch != 'T' && ch != 'S') {
+ }
+ DRAWText(ch == 'T' ? "Throw.\n" : "Swing.\n");
+ if (ch == 'S') return 0;
+ p->Object[OB_AXE]--; /* Lose a thrown axe */
+ }
+ c.x = p->Dungeon.x; /* See what's to hit */
+ c.y = p->Dungeon.y;
+ Dist = -1;
+ for (y = 0; y < 5; y++) /* A maximum distance of 5 */
+ {
+ c.x = c.x + p->DungDir.x; /* Next position */
+ c.y = c.y + p->DungDir.y;
+ n = DDRAWFindMonster(d, &c); /* Monster there ? */
+ if (n >= 0) {
+ c1 = c; Dist = n;
+ } /* If so , record that */
+ if (!ISDRAWOPEN /* If wall, or door, stop */
+ (d->Map[c.x][c.y])) y = 99;
+ }
+ if (Dist < 0) /* Hit nothing */
+ DRAWText("You missed !!\n"); /* Then a miss. */
+ else
+ _ATTACKHitMonster(p, d, Weapon, &c1);
+ return 1;
+}
+
+/************************************************************************/
+/* */
+/* Use an amulet */
+/* */
+/************************************************************************/
+
+static void _ATTACKAmulet(PLAYER *p, DUNGEONMAP *d) {
+ int i, Magic = urand() % 4;
+ if (p->Class == 'M') /* Mages use them properly ! */
+ {
+ DRAWText("1] Ladder Up\n");
+ DRAWText("2] Ladder Down\n");
+ DRAWText("3] Attack Monster\n");
+ DRAWText("4] Bad Magic\n");
+ do
+ Magic = HWGetKey() - '1';
+ while (Magic < 0 || Magic > 3);
+ }
+ if (urand() % 5 == 0) /* Last charge */
+ {
+ DRAWText("Last charge on this Amulet.\n");
+ p->Object[OB_AMULET]--;
+ }
+ switch (Magic)
+ {
+ case 0: /* Ladder up */
+ d->Map[p->Dungeon.x][p->Dungeon.y] = DT_LADDERUP;
+ break;
+ case 1: /* Ladder down */
+ d->Map[p->Dungeon.x][p->Dungeon.y] = DT_LADDERDN;
+ break;
+ case 2: /* Amulet Attack */
+ _ATTACKMissile(p, d, OB_AMULET);
+ break;
+ case 3: /* Bad Magic */
+ switch (urand() % 3)
+ {
+ case 0:
+ DRAWText("You have been turned into a Toad.\n");
+ for (i = AT_STRENGTH; i <= AT_WISDOM; i++)
+ p->Attr[i] = 3;
+ break;
+ case 1:
+ DRAWText("You have been turned into a Lizard Man.\n");
+ for (i = AT_HP; i <= AT_WISDOM; i++)
+ p->Attr[i] = floor(p->Attr[i] * 5 / 2);
+ break;
+ case 2:
+ DRAWText("Backfire !!\n");
+ p->Attr[AT_HP] = floor(p->Attr[AT_HP]) / 2;
+ break;
+ }
+ break;
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/british.cpp b/engines/ultima/ultima0/british.cpp
new file mode 100644
index 00000000000..d48dc4345c8
--- /dev/null
+++ b/engines/ultima/ultima0/british.cpp
@@ -0,0 +1,129 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Lord British's Castle */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+static char *_BRITISHName(int);
+
+/************************************************************************/
+/* */
+/* Visit Lord British */
+/* */
+/************************************************************************/
+
+void BRITISHEnter(WORLDMAP *w, PLAYER *p) {
+ int NextTask = p->Task + 1;
+ int c, i;
+
+ if (*p->Name == '\0') /* Require the player name */
+ {
+ DRAWText("Welcome, peasant into\nthe Halls of the\nmighty Lord British.");
+ DRAWText("Herein thou may choose\nto do battle with\nthe evil creatures of the\ndepths, for great\nreward.\n\n");
+ DRAWText("What is thy name,\npeasant ?\n");
+
+ do /* Read the name. */
+ {
+ c = HWGetKey();
+ if (Common::isAlpha(c) && strlen(p->Name) < MAX_NAME)
+ {
+ if (*p->Name != '\0') c = tolower(c);
+ Common::sprintf_s(p->Name + strlen(p->Name), 9 - strlen(p->Name), "%c", c);
+ HWChar(c);
+ }
+ } while (c >= ' ');
+ DRAWText("\n\n");
+ /* Great adventure question */
+ DRAWText("Doest thou wish\nfor great adventure ?\n\n");
+ if (DEADGetYesNo() == 0)
+ {
+ DRAWText("Then leave and begone!\n\n");
+ Common::strcpy_s(p->Name, "");
+ return;
+ }
+ }
+
+ if (p->Task > 0) /* Set a task before ? */
+ {
+ if (p->TaskCompleted == 0) /* Outstanding task */
+ {
+ DRAWText("%s, why hast\nthou returned ?\nThou must kill\n%s.\nGo now and complete\nthy quest !\n",
+ p->Name, _BRITISHName(p->Task));
+ } else
+ {
+ DRAWText("\nAaaahhhh....\n%s.\n\n", p->Name);
+ DRAWText("Thou has accomplished\nthy quest.\n\n");
+ if (p->Task == MAX_MONSTERS)
+ {
+ DRAWText("Lord %s,thou\nhast proved thyself worthy of\nKnighthood, continue\nif thou doth wish\nbut thou hast \naccomplished the\nmain objective of\nthe game.\n\n");
+ DRAWText("Now, maybe thou art\nfoolhardy enough to\ntry difficulty level %d.\n\n", p->Skill + 1);
+ } else
+ {
+ DRAWText("Unfortunately, this\nis not enough to\nbecome a knight.\n\n");
+ p->Task = 0; /* We need another task */
+ }
+ }
+ }
+ if (p->Task == 0) /* Need a new task..... */
+ {
+ if (NextTask == 1)
+ {
+ DRAWText("Good ! Thou shalt try\nto become a knight.\nThy first task is to\ngointo the dungeons\nand return only after\nkilling %s.\n\n",
+ _BRITISHName(NextTask));
+ } else
+ {
+ DRAWText("Thou must now kill\n%s.\n\n", _BRITISHName(NextTask));
+ }
+ DRAWText("Go now upon this\nQuest, and may lady\nluck fair be upon you\nAlso I, Lord British\n,have increased each\nof your attributes\nby one.\n\n");
+ p->Task = NextTask;
+ p->TaskCompleted = 0;
+ for (i = 0; i < p->Attributes; i++) /* LB gives you extra attribs */
+ p->Attr[i]++;
+ }
+}
+
+/************************************************************************/
+/* */
+/* Get name modified with a or an */
+/* */
+/************************************************************************/
+
+static char *_BRITISHName(int m) {
+ static char _Buffer[64];
+ const char *p = GLOMonsterName(m);
+ Common::sprintf_s(_Buffer, "%s %s",
+ (strchr("aeiou", tolower(*p)) != nullptr) ? "an" : "a",
+ p);
+ return(_Buffer);
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/core/resources.cpp b/engines/ultima/ultima0/core/resources.cpp
deleted file mode 100644
index c2f67eff4a4..00000000000
--- a/engines/ultima/ultima0/core/resources.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* 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 "ultima/ultima0/core/resources.h"
-
-namespace Ultima {
-
-} // End of namespace Ultima
diff --git a/engines/ultima/ultima0/core/resources.h b/engines/ultima/ultima0/core/resources.h
deleted file mode 100644
index 6e9fa9421d5..00000000000
--- a/engines/ultima/ultima0/core/resources.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* 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 ULTIMA_ULTIMA0_RESOURCES_H
-#define ULTIMA_ULTIMA0_RESOURCES_H
-
-#include "ultima/shared/engine/resources.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-class Resources : public Shared::LocalResourceFile {
-
-};
-
-} // End of namespace Ultima0
-} // End of namespace Ultima
-
-#endif
diff --git a/engines/ultima/ultima0/ddraw.cpp b/engines/ultima/ultima0/ddraw.cpp
new file mode 100644
index 00000000000..3f7b2346ee7
--- /dev/null
+++ b/engines/ultima/ultima0/ddraw.cpp
@@ -0,0 +1,112 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Dungeon Drawing Code */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+static void _DDRAWCalcRect(RECT *, double);
+
+/************************************************************************/
+/* */
+/* Draw the dungeon */
+/* */
+/************************************************************************/
+
+void DDRAWDraw(PLAYER *p, DUNGEONMAP *d) {
+ double Level = 0;
+ RECT rOut, rIn;
+ COORD Dir, Pos, Next;
+ int Monster, Front, Left, Right;
+ DRAWSetRect(&rOut, 0, 1023, 1260, 10);
+ _DDRAWCalcRect(&rOut, 0);
+ Pos = p->Dungeon; /* Get position */
+ do
+ {
+ Level++; /* Next level */
+ _DDRAWCalcRect(&rIn, Level);
+ Next.x = Pos.x + p->DungDir.x; /* Next position */
+ Next.y = Pos.y + p->DungDir.y;
+
+ Dir = p->DungDir; MOVERotLeft(&Dir); /* To the left */
+ Left = d->Map[Pos.x + Dir.x][Pos.y + Dir.y];
+ MOVERotLeft(&Dir); MOVERotLeft(&Dir);/* To the right */
+ Right = d->Map[Pos.x + Dir.x][Pos.y + Dir.y];
+ Front = d->Map[Next.x][Next.y]; /* What's in front ? */
+
+ Monster = DDRAWFindMonster(d, &Pos); /* Find ID of monster here */
+ if (Monster >= 0) /* Find Type if Found */
+ {
+ Monster = d->Monster[Monster].Type;
+ }
+ DRAWDungeon(&rOut, &rIn, /* Draw the dungeon */
+ Left, Front, Right,
+ d->Map[Pos.x][Pos.y], Monster);
+
+ Pos = Next; /* Next position down */
+ rOut = rIn; /* Last in is new out */
+ } while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(Front));
+}
+
+/************************************************************************/
+/* */
+/* Calculate display rectangle */
+/* */
+/************************************************************************/
+
+static void _DDRAWCalcRect(RECT *r, double Level) {
+ int xWidth, yWidth;
+ xWidth = (int) /* Calculate frame size */
+ (atan(1.0 / (Level + 1)) / atan(1.0) * 1279 + 0.5);
+ xWidth = 1279 / (Level + 1);
+ yWidth = xWidth * 10 / 13;
+ r->left = 640 - xWidth / 2; /* Calculate drawing rectangle */
+ r->right = 640 + xWidth / 2;
+ r->top = 512 + yWidth / 2;
+ r->bottom = 512 - yWidth / 2;
+}
+
+/************************************************************************/
+/* */
+/* Find Monster ID at given location */
+/* */
+/************************************************************************/
+
+int DDRAWFindMonster(DUNGEONMAP *d, COORD *c) {
+ int i, n = -1;
+ for (i = 0; i < d->MonstCount; i++)
+ if (c->x == d->Monster[i].Loc.x &&
+ c->y == d->Monster[i].Loc.y &&
+ d->Monster[i].Alive != 0) n = i;
+ return n;
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/dead.cpp b/engines/ultima/ultima0/dead.cpp
new file mode 100644
index 00000000000..96d08dd5cb3
--- /dev/null
+++ b/engines/ultima/ultima0/dead.cpp
@@ -0,0 +1,69 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Dead Code */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/* */
+/* You have died */
+/* */
+/************************************************************************/
+
+void DEADCode(PLAYER *p) {
+ const char *s = p->Name;
+ if (*s == '\0') s = "the peasant";
+ DRAWText("\nWe mourn the passing of %s and his computer.\n\n", s);
+ DRAWText("Dost thou wish resurrection ?\n\n");
+
+ if (DEADGetYesNo())
+ {
+ DRAWText("Yes.\n");
+ MAINSetup();
+ }
+}
+
+/************************************************************************/
+/* */
+/* Get a yes or no */
+/* */
+/************************************************************************/
+
+int DEADGetYesNo(void) {
+ char c;
+ do
+ c = HWGetKey();
+ while (c != 'Y' && c != 'N');
+ return (c == 'Y');
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/defines.h b/engines/ultima/ultima0/defines.h
new file mode 100644
index 00000000000..c1de0781715
--- /dev/null
+++ b/engines/ultima/ultima0/defines.h
@@ -0,0 +1,118 @@
+/* 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 ULTIMA_ULTIMA0_DEFINES_H
+#define ULTIMA_ULTIMA0_DEFINES_H
+
+#include "common/scummsys.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+#define RND_MAX 0x7fffffff
+#define RND() (((double)g_engine->getRandomNumber())/RND_MAX)
+#define urand() g_engine->getRandomNumber()
+#define AKVERSION (1.000) /* Version number */
+
+#define WORLD_MAP_SIZE (21) /* Size of world map */
+#define DUNGEON_MAP_SIZE (11) /* Size of dungeon map */
+#define MAX_MONSTERS (10) /* Number of Monsters */
+#define MAX_ATTR (6) /* Attributes */
+#define MAX_OBJ (6) /* Objects */
+#define WORLD_GRID_SIZE (3) /* Visible part of map is axa */
+#define MAX_NAME (8) /* Max size player name */
+#define MAX_VIEW_DEPTH (9) /* Max viewing depth */
+
+ /* Convert RGB to Colour Code */
+#define RGB(r,g,b) ((r?4:0)+(g?2:0)+(b?1:0))
+
+#define C_BLACK RGB(0,0,0) /* Some Colours */
+#define C_RED RGB(1,0,0)
+#define C_GREEN RGB(0,1,0)
+#define C_BLUE RGB(0,0,1)
+#define C_YELLOW RGB(1,1,0)
+#define C_WHITE RGB(1,1,1)
+#define C_CYAN RGB(0,1,1)
+
+#define WT_SPACE (0) /* World Tiles */
+#define WT_MOUNTAIN (1)
+#define WT_TREE (2)
+#define WT_TOWN (3)
+#define WT_DUNGEON (4)
+#define WT_BRITISH (5)
+#define WT_PLAYER (-1) /* Used for the player graphic */
+
+#define DT_SPACE (0) /* Dungeon tiles */
+#define DT_SOLID (1)
+#define DT_TRAP (2)
+#define DT_HIDDENDOOR (3)
+#define DT_DOOR (4)
+#define DT_GOLD (5)
+#define DT_LADDERDN (7)
+#define DT_LADDERUP (8)
+#define DT_PIT (9)
+
+#define ISWALKTHRU(x) ((x) != DT_SOLID) /* Tests for them */
+#define ISDRAWWALL(x) ((x) == DT_SOLID || (x) == DT_HIDDENDOOR)
+#define ISDRAWDOOR(x) ((x) == DT_DOOR)
+#define ISDRAWOPEN(x) (ISDRAWWALL(x) == 0 && ISDRAWDOOR(x) == 0)
+
+#define COL_WALL (C_GREEN) /* Object Colours */
+#define COL_LADDER (C_RED)
+#define COL_DOOR (C_BLUE)
+#define COL_HOLE (C_RED)
+#define COL_MONSTER (C_WHITE)
+#define COL_MOUNTAIN (C_YELLOW)
+#define COL_TREE (C_GREEN)
+#define COL_DUNGEON (C_RED)
+#define COL_TOWN (C_BLUE)
+#define COL_BRITISH (C_WHITE)
+#define COL_PLAYER (C_CYAN)
+
+#define MN_SKELETON (1) /* Monster types */
+#define MN_THIEF (2)
+#define MN_RAT (3)
+#define MN_ORC (4)
+#define MN_VIPER (5)
+#define MN_CARRION (6)
+#define MN_GREMLIN (7)
+#define MN_MIMIC (8)
+#define MN_DAEMON (9)
+#define MN_BALROG (10)
+
+#define AT_HP (0) /* Player attributes */
+#define AT_STRENGTH (1)
+#define AT_DEXTERITY (2)
+#define AT_STAMINA (3)
+#define AT_WISDOM (4)
+#define AT_GOLD (5)
+
+#define OB_FOOD (0) /* Object Attributes */
+#define OB_RAPIER (1)
+#define OB_AXE (2)
+#define OB_SHIELD (3)
+#define OB_BOW (4)
+#define OB_AMULET (5)
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/draw.cpp b/engines/ultima/ultima0/draw.cpp
new file mode 100644
index 00000000000..5df4bd97fcb
--- /dev/null
+++ b/engines/ultima/ultima0/draw.cpp
@@ -0,0 +1,121 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Draw World Objects */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h" /* Our prototypes */
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/* */
+/* Draw object in a given rectangle */
+/* */
+/************************************************************************/
+
+#define X(n) (x1 + w * (n)/10)
+#define Y(n) (y1 + h * (n)/10)
+#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
+
+void DRAWTile(RECT *r, int Obj) {
+ int x1 = r->left; /* Extract values */
+ int y1 = r->top;
+ int w = r->right - r->left; /* Calculate width and height */
+ int h = r->bottom - r->top;
+
+ switch (Obj) /* Decide on the object */
+ {
+ case WT_SPACE: /* Space does nothing at all */
+ break;
+
+ case WT_MOUNTAIN: /* Mountain the cracked effect */
+ HWColour(COL_MOUNTAIN);
+ HWLine(X(2), Y(6), X(2), Y(10));
+ HWLine(X(0), Y(8), X(2), Y(8));
+ HWLine(X(2), Y(6), X(4), Y(6));
+ HWLine(X(4), Y(6), X(4), Y(4));
+ HWLine(X(2), Y(2), X(4), Y(4));
+ HWLine(X(2), Y(2), X(2), Y(0));
+ HWLine(X(2), Y(2), X(0), Y(2));
+ HWLine(X(8), Y(4), X(4), Y(4));
+ HWLine(X(8), Y(4), X(8), Y(0));
+ HWLine(X(8), Y(2), X(10), Y(2));
+ HWLine(X(6), Y(4), X(6), Y(8));
+ HWLine(X(10), Y(8), X(6), Y(8));
+ HWLine(X(8), Y(8), X(8), Y(10));
+ break;
+
+ case WT_TREE: /* Tree is just a box */
+ HWColour(COL_TREE);
+ BOX(3, 3, 7, 7);
+ break;
+
+ case WT_TOWN: /* Down is 5 boxes */
+ HWColour(COL_TOWN);
+ BOX(2, 2, 4, 4); BOX(4, 4, 6, 6); BOX(6, 6, 8, 8);
+ BOX(6, 2, 8, 4); BOX(2, 6, 4, 8);
+ break;
+
+ case WT_DUNGEON: /* Dungeon is a cross */
+ HWColour(COL_DUNGEON);
+ HWLine(X(3), Y(3), X(7), Y(7));
+ HWLine(X(7), Y(3), X(3), Y(7));
+ break;
+
+ case WT_BRITISH: /* British castle */
+ HWColour(COL_BRITISH);
+ HWLine(X(2), Y(2), X(8), Y(8));
+ HWLine(X(8), Y(2), X(2), Y(8));
+ BOX(0, 0, 10, 10);
+ BOX(2, 2, 8, 8);
+ break;
+
+ case WT_PLAYER:
+ HWColour(COL_PLAYER);
+ HWLine(X(4), Y(5), X(6), Y(5));
+ HWLine(X(5), Y(4), X(5), Y(6));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/************************************************************************/
+/* */
+/* Copy values into a rectangle */
+/* */
+/************************************************************************/
+
+void DRAWSetRect(RECT *r, int x1, int y1, int x2, int y2) {
+ r->left = x1; r->right = x2;
+ r->top = y1; r->bottom = y2;
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/draw2.cpp b/engines/ultima/ultima0/draw2.cpp
new file mode 100644
index 00000000000..e21722fd58f
--- /dev/null
+++ b/engines/ultima/ultima0/draw2.cpp
@@ -0,0 +1,249 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Draw Dungeon View Part */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+static void _DRAWRect(int, int, int, int);
+static void _DRAWSetRange(int, int, int, int, int);
+static void _DRAWConvert(int *, int *);
+static void _DRAWWall(int);
+static void _DRAWPit(RECT *, int);
+
+int xLeft, xRight, yBottom, /* Slanted drawing constants */
+yDiffLeft, yDiffRight;
+
+/************************************************************************/
+/* */
+/* Draw part of dungeon */
+/* */
+/************************************************************************/
+
+void DRAWDungeon(RECT *rOut, RECT *rIn,
+ int Left, int Centre, int Right,
+ int Room, int Monster) {
+ int x1, y1, x, y, y2;
+ RECT r;
+ double Scale;
+
+ HWColour(COL_WALL); /* Start on the walls */
+
+ if (ISDRAWOPEN(Left)) /* Do we draw the left edge */
+ {
+ HWLine(rOut->left, rIn->top, rIn->left, rIn->top);
+ HWLine(rOut->left, rIn->bottom, rIn->left, rIn->bottom);
+ HWLine(rOut->left, rOut->top, rOut->left, rOut->bottom);
+ } else /* If closed, draw left diags */
+ {
+ HWLine(rOut->left, rOut->top, rIn->left, rIn->top);
+ HWLine(rOut->left, rOut->bottom, rIn->left, rIn->bottom);
+ }
+
+ if (ISDRAWOPEN(Right)) /* Do we draw the right edge */
+ {
+ HWLine(rOut->right, rIn->top, rIn->right, rIn->top);
+ HWLine(rOut->right, rIn->bottom, rIn->right, rIn->bottom);
+ HWLine(rOut->right, rOut->top, rOut->right, rOut->bottom);
+ } else /* If closed draw right diags */
+ {
+ HWLine(rOut->right, rOut->top, rIn->right, rIn->top);
+ HWLine(rOut->right, rOut->bottom, rIn->right, rIn->bottom);
+ }
+
+ if (!ISDRAWOPEN(Centre)) /* Back wall ? */
+ {
+ HWLine(rIn->left, rIn->top, rIn->right, rIn->top);
+ HWLine(rIn->left, rIn->bottom, rIn->right, rIn->bottom);
+ if (!ISDRAWOPEN(Left)) /* Corner if left,right closed */
+ HWLine(rIn->left, rIn->top, rIn->left, rIn->bottom);
+ if (!ISDRAWOPEN(Right))
+ HWLine(rIn->right, rIn->top, rIn->right, rIn->bottom);
+ }
+
+ _DRAWSetRange(rOut->left, rIn->left, /* Set up for left side */
+ rOut->bottom,
+ rOut->bottom - rOut->top,
+ rIn->bottom - rIn->top);
+ _DRAWWall(Left);
+ _DRAWSetRange(rIn->right, rOut->right, /* Set up for right side */
+ rIn->bottom,
+ rIn->bottom - rIn->top,
+ rOut->bottom - rOut->top);
+ _DRAWWall(Right); /* Set up for centre */
+ _DRAWSetRange(rIn->left, rIn->right,
+ rIn->bottom,
+ rIn->bottom - rIn->top,
+ rIn->bottom - rIn->top);
+ _DRAWWall(Centre);
+
+ if (Room == DT_LADDERUP)
+ {
+ DRAWSetRect(&r, rOut->left, rOut->top, rOut->right, rIn->top);
+ _DRAWPit(&r, 1);
+ }
+ if (Room == DT_LADDERDN || Room == DT_PIT)
+ {
+ DRAWSetRect(&r, rOut->left, rIn->bottom, rOut->right, rOut->bottom);
+ _DRAWPit(&r, -1);
+ }
+
+ DRAWSetRect(&r, /* Get the object area */
+ (rIn->left + rOut->left) / 2,
+ (rIn->top + rOut->top) / 2,
+ (rIn->right + rOut->right) / 2,
+ (rIn->bottom + rOut->bottom) / 2);
+
+ if (Room == DT_LADDERUP || /* Ladder here ? */
+ Room == DT_LADDERDN)
+ {
+ HWColour(COL_LADDER);
+ y1 = r.top; y2 = r.bottom;
+ x = (r.right - r.left) * 3 / 10;
+ HWLine(r.left + x, y1, r.left + x, y2);
+ HWLine(r.right - x, y1, r.right - x, y2);
+ x1 = (y1 - y2) / 5;
+ y = y2 + x1 / 2;
+ while (y < y1)
+ {
+ HWLine(r.left + x, y, r.right - x, y);
+ y = y + x1;
+ }
+ }
+
+ Scale = 0.1; /* Scale (trial and error this :)) */
+ Scale = Scale / (r.right - r.left) * 1059.0;
+
+ if (Monster > 0) /* Monster here ? */
+ {
+ HWColour(COL_MONSTER);
+ DRAWMonster((r.left + r.right) / 2, r.bottom, Monster, Scale);
+ }
+
+ if (Room == DT_GOLD) /* Draw the gold (as a mimic) */
+ {
+ HWColour(COL_MONSTER);
+ DRAWMonster((r.left + r.right) / 2, r.bottom, MN_MIMIC, Scale);
+ }
+
+}
+
+/************************************************************************/
+/* */
+/* Set the oblique drawing routine */
+/* */
+/************************************************************************/
+
+static void _DRAWSetRange(int x1, int x2, int y, int yd1, int yd2) {
+ xLeft = x1; xRight = x2; /* Set x ranges */
+ yBottom = y; /* Set lower left y value */
+ yDiffLeft = yd1; yDiffRight = yd2; /* Set difference for either end */
+}
+
+/************************************************************************/
+/* */
+/* Convert coordinates from oblique to logical */
+/* */
+/************************************************************************/
+
+static void _DRAWConvert(int *px, int *py) {
+ long x, y, yd; /* Longs for overflow in 16 bit */
+ x = (xRight - xLeft); /* Calculate width */
+ x = x * (*px) / 100 + xLeft; /* Work out horiz value */
+ yd = (yDiffRight - yDiffLeft); /* Work out height of vert for x */
+ yd = yd * (*px) / 100;
+ y = yBottom + /* Half of the distance */
+ yd / 2 - /* + Scaled total size */
+ (yd + yDiffLeft) * (*py) / 100;
+
+ *px = (int)x; /* Write back, casting to int */
+ *py = (int)y;
+}
+
+/************************************************************************/
+/* */
+/* Draw a rectangle */
+/* */
+/************************************************************************/
+
+static void _DRAWRect(int x1, int y1, int x2, int y2) {
+ HWLine(x1, y1, x2, y1); HWLine(x1, y1, x1, y2);
+ HWLine(x2, y2, x2, y1); HWLine(x2, y2, x1, y2);
+}
+
+/************************************************************************/
+/* */
+/* Draw the pits/ladder hole */
+/* */
+/************************************************************************/
+
+static void _DRAWPit(RECT *r, int Dir) {
+ int x1, x2, y1;
+ HWColour(COL_HOLE);
+ y1 = (r->top - r->bottom) / 5;
+ r->bottom += y1; r->top -= y1;
+ x1 = (r->right - r->left) / 5;
+ r->left += x1; r->right -= x1;
+ x2 = 0; x1 = x1 / 2;
+ if (Dir > 0)
+ {
+ y1 = x1; x1 = x2; x2 = y1;
+ }
+ HWLine(r->left + x1, r->top, r->right - x1, r->top);
+ HWLine(r->left + x1, r->top, r->left + x2, r->bottom);
+ HWLine(r->left + x2, r->bottom, r->right - x2, r->bottom);
+ HWLine(r->right - x1, r->top, r->right - x2, r->bottom);
+
+}
+
+/************************************************************************/
+/* */
+/* Draw wall object using current setting */
+/* */
+/************************************************************************/
+
+static void _DRAWWall(int n) {
+ int x1, y1, x2, y2;
+ if (n == DT_DOOR)
+ {
+ HWColour(COL_DOOR);
+ x1 = 35; y1 = 0; x2 = 35; y2 = 60;
+ _DRAWConvert(&x1, &y1);
+ _DRAWConvert(&x2, &y2);
+ HWLine(x1, y1, x2, y2);
+ x1 = 65; y1 = 60; _DRAWConvert(&x1, &y1);
+ HWLine(x1, y1, x2, y2);
+ x2 = 65; y2 = 0; _DRAWConvert(&x2, &y2);
+ HWLine(x1, y1, x2, y2);
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/draw3.cpp b/engines/ultima/ultima0/draw3.cpp
new file mode 100644
index 00000000000..20796b80a73
--- /dev/null
+++ b/engines/ultima/ultima0/draw3.cpp
@@ -0,0 +1,246 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Draw Monster Graphics */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+#define PARAMS double x,double y,double d /* Parameters for Draw funcs */
+#define END (-9999.99) /* End marker */
+
+static void _DRAWSkeleton(PARAMS); /* Local Prototypes */
+static void _DRAWThief(PARAMS);
+static void _DRAWRat(PARAMS);
+static void _DRAWOrc(PARAMS);
+static void _DRAWViper(PARAMS);
+static void _DRAWCarrion(PARAMS);
+static void _DRAWGremlin(PARAMS);
+static void _DRAWMimic(PARAMS);
+static void _DRAWDaemon(PARAMS);
+static void _DRAWBalrog(PARAMS);
+
+int xPos = 640; /* Drawing position */
+int yPos = 512;
+
+/************************************************************************/
+/* */
+/* Draw Monster Graphics */
+/* */
+/************************************************************************/
+
+void DRAWMonster(int x, int y, int Monster, double Scale) {
+ xPos = x; yPos = y; /* Save drawing pos */
+ if (Monster == MN_MIMIC) /* Fix for Mimic/Chest */
+ xPos = xPos - 90;
+ switch (Monster) /* Call appropriate function */
+ {
+ case MN_SKELETON: _DRAWSkeleton(0, 0, Scale); break;
+ case MN_THIEF: _DRAWThief(0, 0, Scale); break;
+ case MN_RAT: _DRAWRat(0, 0, Scale); break;
+ case MN_ORC: _DRAWOrc(0, 0, Scale); break;
+ case MN_VIPER: _DRAWViper(0, 0, Scale); break;
+ case MN_CARRION: _DRAWCarrion(0, 0, Scale); break;
+ case MN_GREMLIN: _DRAWGremlin(0, 0, Scale); break;
+ case MN_MIMIC: _DRAWMimic(0, 0, Scale); break;
+ case MN_DAEMON: _DRAWDaemon(0, 0, Scale); break;
+ case MN_BALROG: _DRAWBalrog(0, 0, Scale); break;
+ }
+}
+
+/************************************************************************/
+/* */
+/* Draw a text string. Here because use of ... like HPLOT */
+/* */
+/************************************************************************/
+
+void DRAWText(const char *Format, ...) {
+ va_list alist;
+ char Buffer[512], *p;
+ va_start(alist, Format);
+ Common::vsprintf_s(Buffer, Format, alist);
+ p = Buffer;
+ while (*p != '\0')
+ {
+ if (*p == '\n') HWChar(13), p++;
+ else HWChar(*p++);
+ }
+ va_end(alist);
+}
+
+/************************************************************************/
+/* */
+/* Emulate the Apple ][ HPLOT function */
+/* */
+/************************************************************************/
+
+static void _HPlot(double x, double y, ...) {
+ va_list alist;
+ double y1, x1;
+ va_start(alist, y); /* Start reading values */
+ do
+ {
+ x1 = va_arg(alist, double); /* Get the next two */
+ y1 = va_arg(alist, double);
+ if (x1 != END && y1 != END) /* If legit, draw the line */
+ HWLine(xPos + x, yPos - y, xPos + x1, yPos - y1);
+ x = x1; y = y1;
+ } while (x1 != END && y1 != END);
+ va_end(alist);
+}
+
+/************************************************************************/
+/* */
+/* Drawing functions, grabbed from the Apple II original */
+/* */
+/************************************************************************/
+
+static void _DRAWSkeleton(PARAMS) {
+ _HPlot(y - 23 / d, x, y - 15 / d, x, y - 15 / d, x - 15 / d, y - 8 / d, x - 30 / d, y + 8 / d, x - 30 / d, y + 15 / d, x - 15 / d, y + 15 / d, x, y + 23 / d, x, END, END);
+ _HPlot(y, x - 26 / d, y, x - 65 / d, END, END);
+ _HPlot(y - 2 / d + .5, x - 38 / d, y + 2 / d + .5, x - 38 / d, END, END);
+ _HPlot(y - 3 / d + .5, x - 45 / d, y + 3 / d + .5, x - 45 / d, END, END);
+ _HPlot(y - 5 / d + .5, x - 53 / d, y + 5 / d + .5, x - 53 / d, END, END);
+ _HPlot(y - 23 / d, x - 56 / d, y - 30 / d, x - 53 / d, y - 23 / d, x - 45 / d, y - 23 / d, x - 53 / d, y - 8 / d, x - 38 / d, END, END);
+ _HPlot(y - 15 / d, x - 45 / d, y - 8 / d, x - 60 / d, y + 8 / d, x - 60 / d, y + 15 / d, x - 45 / d, END, END);
+ _HPlot(y + 15 / d, x - 42 / d, y + 15 / d, x - 57 / d, END, END);
+ _HPlot(y + 12 / d, x - 45 / d, y + 20 / d, x - 45 / d, END, END);
+ _HPlot(y, x - 75 / d, y - 5 / d + .5, x - 80 / d, y - 8 / d, x - 75 / d, y - 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 65 / d, END, END);
+ _HPlot(y + 5 / d + .5, x - 65 / d, y + 8 / d, x - 75 / d, y + 5 / d + .5, x - 80 / d, y - 5 / d + .5, x - 80 / d, END, END);
+ _HPlot(y - 5 / d + .5, x - 72 / d, END, END);
+ _HPlot(y + 5 / d + .5, x - 72 / d, END, END);
+}
+
+static void _DRAWThief(PARAMS) {
+ _HPlot(y, x - 56 / d, y, x - 8 / d, y + 10 / d, x, y + 30 / d, x, y + 30 / d, x - 45 / d, y + 10 / d, x - 64 / d, y, x - 56 / d, END, END);
+ _HPlot(y - 10 / d, x - 64 / d, y - 30 / d, x - 45 / d, y - 30 / d, x, y - 10 / d, x, y, x - 8 / d, END, END);
+ _HPlot(y - 10 / d, x - 64 / d, y - 10 / d, x - 75 / d, y, x - 83 / d, y + 10 / d, x - 75 / d, y, x - 79 / d, y - 10 / d, x - 75 / d, y, x - 60 / d, y + 10 / d, x - 75 / d, y + 10 / d, x - 64 / d, END, END);
+}
+
+static void _DRAWRat(PARAMS) {
+ _HPlot(y + 5 / d, x - 30 / d, y, x - 25 / d, y - 5 / d, x - 30 / d, y - 15 / d, x - 5 / d, y - 10 / d, x, y + 10 / d, x, y + 15 / d, x - 5 / d, END, END);
+ _HPlot(y + 20 / d, x - 5 / d, y + 10 / d, x, y + 15 / d, x - 5 / d, y + 5 / d, x - 30 / d, y + 10 / d, x - 40 / d, y + 3 / d + .5, x - 35 / d, y - 3 / d + .5, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 30 / d, END, END);
+ _HPlot(y - 5 / d, x - 33 / d, y - 3 / d + .5, x - 30 / d, END, END);
+ _HPlot(y + 5 / d, x - 33 / d, y + 3 / d + .5, x - 30 / d, END, END);
+ _HPlot(y - 5 / d, x - 20 / d, y - 5 / d, x - 15 / d, END, END);
+ _HPlot(y + 5 / d, x - 20 / d, y + 5 / d, x - 15 / d, END, END);
+ _HPlot(y - 7 / d, x - 20 / d, y - 7 / d, x - 15 / d, END, END);
+ _HPlot(y + 7 / d, x - 20 / d, y + 7 / d, x - 15 / d, END, END);
+}
+
+static void _DRAWOrc(PARAMS) {
+ _HPlot(y, x, y - 15 / d, x, y - 8 / d, x - 8 / d, y - 8 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 23 / d, END, END);
+ _HPlot(y - 23 / d, x - 45 / d, y - 15 / d, x - 53 / d, y - 8 / d, x - 53 / d, y - 15 / d, x - 68 / d, y - 8 / d, x - 75 / d, y, x - 75 / d, END, END);
+ _HPlot(y, x, y + 15 / d, x, y + 8 / d, x - 8 / d, y + 8 / d, x - 15 / d, y + 15 / d, x - 23 / d, y + 15 / d, x - 15 / d, y + 23 / d, x - 23 / d, END, END);
+ _HPlot(y + 23 / d, x - 45 / d, y + 15 / d, x - 53 / d, y + 8 / d, x - 53 / d, y + 15 / d, x - 68 / d, y + 8 / d, x - 75 / d, y, x - 75 / d, END, END);
+ _HPlot(y - 15 / d, x - 68 / d, y + 15 / d, x - 68 / d, END, END);
+ _HPlot(y - 8 / d, x - 53 / d, y + 8 / d, x - 53 / d, END, END);
+ _HPlot(y - 23 / d, x - 15 / d, y + 8 / d, x - 45 / d, END, END);
+ _HPlot(y - 8 / d, x - 68 / d, y, x - 60 / d, y + 8 / d, x - 68 / d, y + 8 / d, x - 60 / d, y - 8 / d, x - 60 / d, y - 8 / d, x - 68 / d, END, END);
+ _HPlot(y, x - 38 / d, y - 8 / d, x - 38 / d, y + 8 / d, x - 53 / d, y + 8 / d, x - 45 / d, y + 15 / d, x - 45 / d, y, x - 30 / d, y, x - 38 / d, END, END);
+}
+
+static void _DRAWViper(PARAMS) {
+ _HPlot(y - 10 / d, x - 15 / d, y - 10 / d, x - 30 / d, y - 15 / d, x - 20 / d, y - 15 / d, x - 15 / d, y - 15 / d, x, y + 15 / d, x, y + 15 / d, x - 15 / d, y - 15 / d, x - 15 / d, END, END);
+ _HPlot(y - 15 / d, x - 10 / d, y + 15 / d, x - 10 / d, END, END);
+ _HPlot(y - 15 / d, x - 5 / d, y + 15 / d, x - 5 / d, END, END);
+ _HPlot(y, x - 15 / d, y - 5 / d, x - 20 / d, y - 5 / d, x - 35 / d, y + 5 / d, x - 35 / d, y + 5 / d, x - 20 / d, y + 10 / d, x - 15 / d, END, END);
+ _HPlot(y - 5 / d, x - 20 / d, y + 5 / d, x - 20 / d, END, END);
+ _HPlot(y - 5 / d, x - 25 / d, y + 5 / d, x - 25 / d, END, END);
+ _HPlot(y - 5 / d, x - 30 / d, y + 5 / d, x - 30 / d, END, END);
+ _HPlot(y - 10 / d, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 45 / d, y + 5 / d, x - 45 / d, y + 10 / d, x - 40 / d, y + 10 / d, x - 35 / d, END, END);
+ _HPlot(y - 10 / d, x - 40 / d, y, x - 45 / d, y + 10 / d, x - 40 / d, END, END);
+ _HPlot(y - 5 / d, x - 40 / d, y + 5 / d, x - 40 / d, y + 15 / d, x - 30 / d, y, x - 40 / d, y - 15 / d, x - 30 / d, y - 5 / d + .5, x - 40 / d, END, END);
+}
+
+static void _DRAWCarrion(PARAMS) {
+ /* 79-dst.recty(d) line here */
+ _HPlot(y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
+ _HPlot(y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
+ _HPlot(y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
+ _HPlot(y - 15 / d, x - 86 / d, y - 20 / d, x - 83 / d, y - 20 / d, x - 78 / d, y - 30 / d, x - 73 / d, y - 30 / d, x - 68 / d, y - 20 / d, x - 63 / d, END, END);
+ _HPlot(y - 10 / d, x - 83 / d, y - 10 / d, x - 58 / d, y, x - 50 / d, END, END);
+ _HPlot(y + 10 / d, x - 83 / d, y + 10 / d, x - 78 / d, y + 20 / d, x - 73 / d, y + 20 / d, x - 40 / d, END, END);
+ _HPlot(y + 15 / d, x - 85 / d, y + 20 / d, x - 78 / d, y + 30 / d, x - 76 / d, y + 30 / d, x - 60 / d, END, END);
+ _HPlot(y, x - 83 / d, y, x - 73 / d, y + 10 / d, x - 68 / d, y + 10 / d, x - 63 / d, y, x - 58 / d, END, END);
+}
+
+static void _DRAWGremlin(PARAMS) {
+ _HPlot(y + 5 / d + .5, x - 10 / d, y - 5 / d + .5, x - 10 / d, y, x - 15 / d, y + 10 / d, x - 20 / d, y + 5 / d + .5, x - 15 / d, y + 5 / d + .5, x - 10 / d, END, END);
+ _HPlot(y + 7 / d + .5, x - 6 / d, y + 5 / d + .5, x - 3 / d, y - 5 / d + .5, x - 3 / d, y - 7 / d + .5, x - 6 / d, y - 5 / d + .5, x - 10 / d, END, END);
+ _HPlot(y + 2 / d + .5, x - 3 / d, y + 5 / d + .5, x, y + 8 / d, x, END, END);
+ _HPlot(y - 2 / d + .5, x - 3 / d, y - 5 / d + .5, x, y - 8 / d, x, END, END);
+ _HPlot(y + 3 / d + .5, x - 8 / d, END, END);
+ _HPlot(y - 3 / d + .5, x - 8 / d, END, END);
+ _HPlot(y + 3 / d + .5, x - 5 / d, y - 3 / d + .5, x - 5 / d, END, END);
+}
+
+static void _DRAWMimic(PARAMS) {
+ double xx = x;
+ _HPlot(139 - 10 / d, xx, 139 - 10 / d, xx - 10 / d, 139 + 10 / d, xx - 10 / d, 139 + 10 / d, xx, 139 - 10 / d, xx, END, END);
+ _HPlot(139 - 10 / d, xx - 10 / d, 139 - 5 / d, xx - 15 / d, 139 + 15 / d, xx - 15 / d, 139 + 15 / d, xx - 5 / d, 139 + 10 / d, xx, END, END);
+ _HPlot(139 + 10 / d, xx - 10 / d, 139 + 15 / d, xx - 15 / d, END, END);
+}
+
+static void _DRAWDaemon(PARAMS) {
+ _HPlot(y - 14 / d, x - 46 / d, y - 12 / d, x - 37 / d, y - 20 / d, x - 32 / d, y - 30 / d, x - 32 / d, y - 22 / d, x - 24 / d, y - 40 / d, x - 17 / d, y - 40 / d, x - 7 / d, y - 38 / d, x - 5 / d, y - 40 / d, x - 3 / d, y - 40 / d, x, END, END);
+ _HPlot(y - 36 / d, x, y - 34 / d, x - 2 / d, y - 32 / d, x, y - 28 / d, x, y - 28 / d, x - 3 / d, y - 30 / d, x - 5 / d, y - 28 / d, x - 7 / d, y - 28 / d, x - 15 / d, y, x - 27 / d, END, END);
+ _HPlot(y + 14 / d, x - 46 / d, y + 12 / d, x - 37 / d, y + 20 / d, x - 32 / d, y + 30 / d, x - 32 / d, y + 22 / d, x - 24 / d, y + 40 / d, x - 17 / d, y + 40 / d, x - 7 / d, y + 38 / d, x - 5 / d, y + 40 / d, x - 3 / d, y + 40 / d, x, END, END);
+ _HPlot(y + 36 / d, x, y + 34 / d, x - 2 / d, y + 32 / d, x, y + 28 / d, x, y + 28 / d, x - 3 / d, y + 30 / d, x - 5 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 15 / d, y, x - 27 / d, END, END);
+ _HPlot(y + 6 / d, x - 48 / d, y + 38 / d, x - 41 / d, y + 40 / d, x - 42 / d, y + 18 / d, x - 56 / d, y + 12 / d, x - 56 / d, y + 10 / d, x - 57 / d, y + 8 / d, x - 56 / d, y - 8 / d, x - 56 / d, y - 10 / d, x - 58 / d, y + 14 / d, x - 58 / d, y + 16 / d, x - 59 / d, END, END);
+ _HPlot(y + 8 / d, x - 63 / d, y + 6 / d, x - 63 / d, y + 2 / d + .5, x - 70 / d, y + 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 70 / d, y - 6 / d, x - 63 / d, y - 8 / d, x - 63 / d, y - 16 / d, x - 59 / d, y - 14 / d, x - 58 / d, END, END);
+ _HPlot(y - 10 / d, x - 57 / d, y - 12 / d, x - 56 / d, y - 18 / d, x - 56 / d, y - 36 / d, x - 47 / d, y - 36 / d, x - 39 / d, y - 28 / d, x - 41 / d, y - 28 / d, x - 46 / d, y - 20 / d, x - 50 / d, y - 18 / d, x - 50 / d, y - 14 / d, x - 46 / d, END, END);
+ _HPlot(y - 28 / d, x - 41 / d, y + 30 / d, x - 55 / d, END, END);
+ _HPlot(y + 28 / d, x - 58 / d, y + 22 / d, x - 56 / d, y + 22 / d, x - 53 / d, y + 28 / d, x - 52 / d, y + 34 / d, x - 54 / d, END, END);
+ _HPlot(y + 20 / d, x - 50 / d, y + 26 / d, x - 47 / d, END, END);
+ _HPlot(y + 10 / d, x - 58 / d, y + 10 / d, x - 61 / d, y + 4 / d, x - 58 / d, END, END);
+ _HPlot(y - 10 / d, x - 58 / d, y - 10 / d, x - 61 / d, y - 4 / d, x - 58 / d, END, END);
+ _HPlot(y + 40 / d, x - 9 / d, y + 50 / d, x - 12 / d, y + 40 / d, x - 7 / d, END, END);
+ _HPlot(y - 8 / d, x - 25 / d, y + 6 / d, x - 7 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 9 / d, y + 20 / d, x - 9 / d, y + 6 / d, x - 25 / d, END, END);
+}
+
+static void _DRAWBalrog(PARAMS) {
+ _HPlot(y + 6 / d, x - 60 / d, y + 30 / d, x - 90 / d, y + 60 / d, x - 30 / d, y + 60 / d, x - 10 / d, y + 30 / d, x - 40 / d, y + 15 / d, x - 40 / d, END, END);
+ _HPlot(y - 6 / d, x - 60 / d, y - 30 / d, x - 90 / d, y - 60 / d, x - 30 / d, y - 60 / d, x - 10 / d, y - 30 / d, x - 40 / d, y - 15 / d, x - 40 / d, END, END);
+ _HPlot(y, x - 25 / d, y + 6 / d, x - 25 / d, y + 10 / d, x - 20 / d, y + 12 / d, x - 10 / d, y + 10 / d, x - 6 / d, y + 10 / d, x, y + 14 / d, x, y + 15 / d, x - 5 / d, y + 16 / d, x, y + 20 / d, x, END, END);
+ _HPlot(y + 20 / d, x - 6 / d, y + 18 / d, x - 10 / d, y + 18 / d, x - 20 / d, y + 15 / d, x - 30 / d, y + 15 / d, x - 45 / d, y + 40 / d, x - 60 / d, y + 40 / d, x - 70 / d, END, END);
+ _HPlot(y + 10 / d, x - 55 / d, y + 6 / d, x - 60 / d, y + 10 / d, x - 74 / d, y + 6 / d, x - 80 / d, y + 4 / d + .5, x - 80 / d, y + 3 / d + .5, x - 82 / d, y + 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
+ _HPlot(y, x - 25 / d, y - 6 / d, x - 25 / d, y - 10 / d, x - 20 / d, y - 12 / d, x - 10 / d, y - 10 / d, x - 6 / d, y - 10 / d, x, y - 14 / d, x, y - 15 / d, x - 5 / d, y - 16 / d, x, y - 20 / d, x, END, END);
+ _HPlot(y - 20 / d, x - 6 / d, y - 18 / d, x - 10 / d, y - 18 / d, x - 20 / d, y - 15 / d, x - 30 / d, y - 15 / d, x - 45 / d, y - 40 / d, x - 60 / d, y - 40 / d, x - 70 / d, END, END);
+ _HPlot(y - 10 / d, x - 55 / d, y - 6 / d, x - 60 / d, y - 10 / d, x - 74 / d, y - 6 / d, x - 80 / d, y - 4 / d + .5, x - 80 / d, y - 3 / d + .5, x - 82 / d, y - 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
+ _HPlot(y - 6 / d, x - 25 / d, y, x - 6 / d, y + 10 / d, x, y + 4 / d + .5, x - 8 / d, y + 6 / d, x - 25 / d, END, END);
+ _HPlot(y - 40 / d, x - 64 / d, y - 40 / d, x - 90 / d, y - 52 / d, x - 80 / d, y - 52 / d, x - 40 / d, END, END);
+ _HPlot(y + 40 / d, x - 86 / d, y + 38 / d, x - 92 / d, y + 42 / d, x - 92 / d, y + 40 / d, x - 86 / d, y + 40 / d, x - 50 / d, END, END);
+ _HPlot(y + 4 / d + .5, x - 70 / d, y + 6 / d, x - 74 / d, END, END);
+ _HPlot(y - 4 / d + .5, x - 70 / d, y - 6 / d, x - 74 / d, END, END);
+ _HPlot(y, x - 64 / d, y, x - 60 / d, END, END);
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/dungeon.cpp b/engines/ultima/ultima0/dungeon.cpp
new file mode 100644
index 00000000000..eb5c031c94a
--- /dev/null
+++ b/engines/ultima/ultima0/dungeon.cpp
@@ -0,0 +1,146 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Dungeon Create and Draw Code */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+static int _DUNGEONContents(int);
+static void _DUNGEONAddMonster(DUNGEONMAP *, PLAYER *, int);
+
+/************************************************************************/
+/* */
+/* Create Dungeon Level */
+/* */
+/************************************************************************/
+
+void DUNGEONCreate(PLAYER *p, DUNGEONMAP *d) {
+ int i, n, x, y, Size;
+
+ g_engine->setRandomSeed(p->LuckyNumber - p->World.x * 40 - /* Seed the random number */
+ p->World.y * 1000 - p->Level);
+ Size = MAINSuper() ? DUNGEON_MAP_SIZE - 1 : 10; /* Calculate map size */
+ d->MapSize = Size; /* Save the map size */
+
+ for (x = 0; x < Size; x++) /* Clear the dungeon */
+ for (y = 0; y < Size; y++)
+ d->Map[x][y] = DT_SPACE;
+
+ for (x = 0; x <= Size; x++) /* Draw the boundaries */
+ {
+ d->Map[Size][x] = DT_SOLID;
+ d->Map[0][x] = DT_SOLID;
+ d->Map[x][Size] = DT_SOLID;
+ d->Map[x][0] = DT_SOLID;
+ }
+ for (x = 2; x < Size; x = x + 2) /* Fill with checkerboard */
+ for (y = 1; y < Size; y++)
+ {
+ d->Map[x][y] = DT_SOLID;
+ d->Map[y][x] = DT_SOLID;
+ }
+ for (x = 2; x < Size; x = x + 2) /* Fill with stuff */
+ for (y = 1; y < Size; y = y + 2)
+ {
+ d->Map[x][y] = _DUNGEONContents(d->Map[x][y]);
+ d->Map[y][x] = _DUNGEONContents(d->Map[y][x]);
+ }
+
+ d->Map[2][1] = DT_SPACE; /* Put stairs in */
+ if (p->Level % 2 == 0) /* Different ends each level */
+ {
+ d->Map[Size - 3][3] = DT_LADDERDN;
+ d->Map[3][Size - 3] = DT_LADDERUP;
+ } else
+ {
+ d->Map[Size - 3][3] = DT_LADDERUP;
+ d->Map[3][Size - 3] = DT_LADDERDN;
+ }
+
+ if (p->Level == 1) /* On first floor */
+ {
+ d->Map[1][1] = DT_LADDERUP; /* Ladder at top left */
+ d->Map[Size - 3][3] = DT_SPACE; /* No other ladder up */
+ }
+
+ d->MonstCount = 0; /* No monsters */
+ n = MAINSuper() ? MAX_MONSTERS : 10; /* How many might there be ? */
+ for (i = 1; i <= n; i++) /* Go through the monsters */
+ _DUNGEONAddMonster(d, p, i); /* Maybe adding them as you go */
+}
+
+/************************************************************************/
+/* */
+/* Generate some contents */
+/* */
+/************************************************************************/
+
+static int _DUNGEONContents(int c) {
+ if (RND() > .95) c = DT_TRAP;
+ if (RND() > .6) c = DT_HIDDENDOOR;
+ if (RND() > .6) c = DT_DOOR;
+ if (RND() > .97) c = DT_PIT;
+ if (RND() > .94) c = DT_GOLD;
+ return c;
+}
+
+/************************************************************************/
+/* */
+/* Maybe add a monster of the given type */
+/* */
+/************************************************************************/
+
+static void _DUNGEONAddMonster(DUNGEONMAP *d, PLAYER *p, int Type) {
+ MONSTER *m;
+ int x, y;
+ int Level = GLOMonsterLevel(Type); /* Read the level */
+
+ if (Level - 2 > p->Level) return; /* Limit monsters to levels */
+ if (RND() > 0.4) return; /* Not always there anyway */
+
+ m = &(d->Monster[(d->MonstCount)++]); /* Get monster record */
+
+ m->Type = Type; /* Fill in details */
+ m->Strength = Level + 3 + p->Level;
+ m->Alive = 1;
+
+ do /* Find a place for it */
+ {
+ x = urand() % d->MapSize;
+ y = urand() % d->MapSize;
+ } while (d->Map[x][y] != DT_SPACE || /* Must be empty, not player */
+ (x == p->Dungeon.x && y == p->Dungeon.y));
+
+ m->Loc.x = x; m->Loc.y = y; /* Record position */
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/game.cpp b/engines/ultima/ultima0/game.cpp
deleted file mode 100644
index f66be8ea2b7..00000000000
--- a/engines/ultima/ultima0/game.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/* 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 "ultima/ultima0/game.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-EMPTY_MESSAGE_MAP(Ultima0Game, Shared::Game);
-
-Ultima0Game::Ultima0Game() : Shared::Game() {
-}
-
-} // End of namespace Ultima0
-} // End of namespace Ultima
diff --git a/engines/ultima/ultima0/globals.cpp b/engines/ultima/ultima0/globals.cpp
new file mode 100644
index 00000000000..f643e857615
--- /dev/null
+++ b/engines/ultima/ultima0/globals.cpp
@@ -0,0 +1,111 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Global Constants : Lists of things, etc. */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+struct _OInfStruct {
+ const char *Name; int Cost; int MaxDamage; char Key;
+};
+struct _MInfStruct {
+ const char *Name; int Level;
+};
+
+static struct _OInfStruct _OInfo[] = {
+ { "Food", 1, 0, 'F' },
+ { "Rapier", 8, 10, 'R' },
+ { "Axe", 5, 5, 'A' },
+ { "Shield", 6, 1, 'S' },
+ { "Bow+Arrow", 3, 4, 'B' },
+ { "Amulet", 15, 0, 'M' }
+};
+
+static struct _MInfStruct _MInfo[] = {
+ { "Skeleton", 1 },
+ { "Thief", 2 },
+ { "Giant Rat", 3 },
+ { "Orc", 4 },
+ { "Viper", 5 },
+ { "Carrion Crawler", 6 },
+ { "Gremlin", 7 },
+ { "Mimic", 8 },
+ { "Daemon", 9 },
+ { "Balrog", 10 }
+};
+
+static const char *_AName[] = { "HP", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
+
+/************************************************************************/
+/* */
+/* Return name of object */
+/* */
+/************************************************************************/
+
+const char *GLOObjName(int n) {
+ return _OInfo[n].Name;
+}
+
+void GLOGetInfo(int n, int *pDamage, int *pCost, int *pKey) {
+ if (pDamage != nullptr) *pDamage = _OInfo[n].MaxDamage;
+ if (pCost != nullptr) *pCost = _OInfo[n].Cost;
+ if (pKey != nullptr) *pKey = _OInfo[n].Key;
+}
+
+/************************************************************************/
+/* */
+/* Return name of attribute */
+/* */
+/************************************************************************/
+
+const char *GLOAttribName(int n) {
+ return _AName[n];
+}
+
+/************************************************************************/
+/* */
+/* Return name of class */
+/* */
+/************************************************************************/
+
+const char *GLOClassName(char c) {
+ return (c == 'F') ? "Fighter" : "Mage";
+}
+
+const char *GLOMonsterName(int n) {
+ return _MInfo[n - 1].Name;
+}
+
+int GLOMonsterLevel(int n) {
+ return _MInfo[n - 1].Level;
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/hardware.cpp b/engines/ultima/ultima0/hardware.cpp
new file mode 100644
index 00000000000..9afbdf13354
--- /dev/null
+++ b/engines/ultima/ultima0/hardware.cpp
@@ -0,0 +1,194 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* System independent routines */
+/* */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h" /* Our prototypes */
+#include "ultima/ultima0/sdw.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+using namespace SDLWrapper;
+
+int CharHeight = 16; /* Height of one character */
+int CharWidth = 16; /* Width of one character */
+int TextLines = 22; /* Number of chars in visible line */
+int TextLeft, xc, yc;
+int TextOrigin;
+int Red, Green, Blue;
+Surface *MainSurface;
+
+/************************************************************************/
+/* */
+/* Initialise all internal graphics routines */
+/* */
+/************************************************************************/
+
+void HWInitialise(void) {
+ MainSurface = new Surface(DEFAULT_SCX, DEFAULT_SCY);
+ TextLeft = DEFAULT_SCX - CharWidth * TextLines;
+ TextOrigin = 224;
+ xc = TextLeft; yc = TextOrigin;
+}
+
+/************************************************************************/
+/* */
+/* Refresh Status Area */
+/* */
+/************************************************************************/
+
+void HWStatus(double Food, int HP, int Gold) {
+ char Temp[32];
+ MainSurface->SetColour(0, 0, 0);
+ MainSurface->FillRect(TextLeft, 0, DEFAULT_SCX, TextOrigin - 1);
+ MainSurface->SetColour(0, 255, 255);
+ Common::sprintf_s(Temp, "%.1f", Food);
+ MainSurface->String(TextLeft + 16, 32, TextLeft + 16 + 32 * strlen(Temp), 32 + 32, Temp);
+ Common::sprintf_s(Temp, "%u", HP);
+ MainSurface->String(TextLeft + 16, 96, TextLeft + 16 + 32 * strlen(Temp), 96 + 32, Temp);
+ Common::sprintf_s(Temp, "%u", Gold);
+ MainSurface->String(TextLeft + 16, 160, TextLeft + 16 + 32 * strlen(Temp), 160 + 32, Temp);
+
+ MainSurface->SetColour(255, 0, 0);
+ MainSurface->String(TextLeft, 8, TextLeft + 64, 24, "Food");
+ MainSurface->String(TextLeft, 72, TextLeft + 16 * 9, 88, "Hit Points");
+ MainSurface->String(TextLeft, 136, TextLeft + 64, 152, "Gold");
+
+ // /* char Temp[32];
+ // setfillstyle(SOLID_FILL,BLACK); /* Set up colours */
+ // setcolor(LIGHTCYAN);
+ // settextstyle(SMALL_FONT,HORIZ_DIR,6);
+ // bar(xText+110,22,xMax-4,yScroll-4); /* Erase old status values */
+ // Common::sprintf_s(Temp,"%.1f",Food); /* Fill in the new ones */
+ // outtextxy(xText+110,22,Temp);
+ // Common::sprintf_s(Temp,"%u",HP);
+ // outtextxy(xText+110,37,Temp);
+ // Common::sprintf_s(Temp,"%u",Gold);
+ // outtextxy(xText+110,52,Temp);
+ // HWColour(CurrentColour); /* Set the current colour */*/
+}
+
+/************************************************************************/
+/* */
+/* Terminate all internal graphics routines */
+/* */
+/************************************************************************/
+
+void HWTerminate(void) {
+}
+
+/************************************************************************/
+/* */
+/* Output text to the scrolling text area */
+/* */
+/************************************************************************/
+
+void HWChar(int ch) {
+ Rect src(TextLeft, TextOrigin + CharHeight, DEFAULT_SCX, DEFAULT_SCY);
+ if (ch >= ' ')
+ {
+ MainSurface->SetColour(0, 255, 0);
+ MainSurface->Char(xc, yc, xc + CharWidth - 1, yc + CharHeight - 1, ch);
+ xc = xc + CharWidth;
+ }
+ if (xc >= DEFAULT_SCX || ch == 13)
+ {
+ xc = TextLeft;
+ yc = yc + CharHeight;
+ if (yc + CharHeight >= DEFAULT_SCY)
+ {
+ MainSurface->Copy(*MainSurface, src, TextLeft, TextOrigin);
+ MainSurface->SetColour(0, 0, 0);
+ MainSurface->FillRect(TextLeft, yc, DEFAULT_SCX, DEFAULT_SCY);
+ yc = yc - CharHeight;
+ }
+ }
+}
+
+/************************************************************************/
+/* */
+/* Select the current drawing colour, should use RGB() */
+/* */
+/************************************************************************/
+
+void HWColour(int c) {
+ Red = (c & 4) ? 255 : 0;
+ Green = (c & 2) ? 255 : 0;
+ Blue = (c & 1) ? 255 : 0;
+}
+
+/************************************************************************/
+/* */
+/* Draw line in current colour */
+/* */
+/************************************************************************/
+
+void HWLine(int x1, int y1, int x2, int y2) {
+ x1 = x1 * TextLeft / 1280; y1 = DEFAULT_SCY - y1 * DEFAULT_SCY / 1024;
+ x2 = x2 * TextLeft / 1280; y2 = DEFAULT_SCY - y2 * DEFAULT_SCY / 1024;
+ MainSurface->SetColour(Red, Green, Blue);
+ MainSurface->Line(x1, y1, x2, y2);
+}
+
+/***********************************************************************/
+/* */
+/* Read an upper case ASCII key, or Carriage Return (13) */
+/* */
+/************************************************************************/
+
+int HWGetKey(void) {
+ int n;
+ MainSurface->Copy();
+ MainSurface->Flip();
+ do
+ {
+ n = GetKey();
+ if (n == 273) n = 'N';
+ if (n == 274) n = 'S';
+ if (n == 275) n = 'E';
+ if (n == 276) n = 'W';
+
+ } while (n < ' ' || n > 127);
+ return toupper(n);
+}
+
+
+/************************************************************************/
+/* */
+/* Clear the graphics area */
+/* */
+/************************************************************************/
+
+void HWClear(void) {
+ MainSurface->SetColour(0, 0, 0);
+ MainSurface->FillRect(0, 0, TextLeft - 1, DEFAULT_SCY);
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/main.cpp b/engines/ultima/ultima0/main.cpp
new file mode 100644
index 00000000000..ad2053ac68c
--- /dev/null
+++ b/engines/ultima/ultima0/main.cpp
@@ -0,0 +1,184 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* M A I N P R O G R A M */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+/************************************************************************/
+/* Outstanding work :- LOAD AND SAVE, FIX THE DOOR PROBLEM.
+************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+PLAYER Player; /* Player data */
+WORLDMAP World; /* Current world map */
+DUNGEONMAP Dungeon; /* Current dungeon map */
+
+static void _MAINIntro(void);
+static void _MAINDisplay(WORLDMAP *, PLAYER *, DUNGEONMAP *);
+static void _MAINCommand(int, WORLDMAP *, PLAYER *, DUNGEONMAP *);
+
+/************************************************************************/
+/* */
+/* Main Program */
+/* */
+/************************************************************************/
+
+void MAINStart(void) {
+ int c;
+ RECT r1, r2;
+ HWInitialise(); /* Initialise the game */
+ HWClear(); /* Clear the graphic display */
+ HWStatus(0, 0, 0); /* Zero the status */
+ _MAINIntro(); /* Print startup information */
+ MAINSetup(); /* Set up the player */
+
+ do
+ {
+ _MAINDisplay(&World, &Player, /* Redraw the main display */
+ &Dungeon);
+ DRAWText("]"); c = HWGetKey(); /* Read the next command */
+ _MAINCommand(c, &World, &Player, /* Do it */
+ &Dungeon);
+ if (Player.Attr[AT_HP] <= 0) /* Died.... */
+ DEADCode(&Player);
+ if (c == 'Q') /* Confirm exit */
+ {
+ DRAWText("Are you sure ?\n");
+ if (DEADGetYesNo() == 0) c = '\0';
+ }
+ } while (c != 'Q' && Player.Attr[AT_HP] > 0);
+ HWTerminate();
+}
+
+/************************************************************************/
+/* */
+/* Set everything up */
+/* */
+/************************************************************************/
+
+void MAINSetup(void) {
+ PLAYERInit(&Player); /* Initialise the player */
+ PLAYERCharacter(&Player); /* Character information */
+ // PLAYERDebug(&Player);
+ WORLDCreate(&Player, &World); /* Create the over world */
+ WORLDDraw(&Player, &World, 0); /* Draw the player map */
+ TOWNEnter(&World, &Player); /* Visit the shops */
+}
+
+/************************************************************************/
+/* */
+/* Execute a command */
+/* */
+/************************************************************************/
+
+static void _MAINCommand(int c, WORLDMAP *w, PLAYER *p, DUNGEONMAP *d) {
+ if (c == 'A' && p->Level == 0) /* Only attack in dungeon */
+ c = '\0';
+ switch (c)
+ {
+ case 'A':
+ DRAWText("Attack.\n");
+ ATTACKMonster(p, d);
+ break;
+
+ case 'N':
+ DRAWText(p->Level == 0 ? "Go North.\n" : "Move.\n");
+ MOVEMove(c, w, p, d, 0, -1);
+ break;
+ case 'S':
+ DRAWText(p->Level == 0 ? "Go South.\n" : "Turn Around.\n");
+ MOVEMove(c, w, p, d, 0, 1);
+ break;
+ case 'E':
+ DRAWText(p->Level == 0 ? "Go East.\n" : "Turn Right.\n");
+ MOVEMove(c, w, p, d, 1, 0);
+ break;
+ case 'W':
+ DRAWText(p->Level == 0 ? "Go West.\n" : "Turn Left.\n");
+ MOVEMove(c, w, p, d, -1, 0);
+ break;
+ case 'I':
+ DRAWText("Inventory.\n");
+ PLAYERInv(&Player);
+ break;
+ case 'Q':
+ DRAWText("Quit.\n");
+ break;
+ case 'X':
+ MOVEEnterExit(w, p, d);
+ break;
+ default:
+ DRAWText("Huh???\n");
+ break;
+ }
+}
+
+/************************************************************************/
+/* */
+/* Introduction text */
+/* */
+/************************************************************************/
+
+static void _MAINIntro(void) {
+ DRAWText("Aklabeth by P Robson\n\n");
+ DRAWText("From the Apple II\n");
+ DRAWText("game by R Garriott\n\n");
+ DRAWText("Press any key.\n\n");
+ HWGetKey();
+}
+
+/************************************************************************/
+/* */
+/* Do we support improved features ? */
+/* */
+/************************************************************************/
+
+int MAINSuper(void) {
+ return 1;
+}
+
+/************************************************************************/
+/* */
+/* Redraw the main display */
+/* */
+/************************************************************************/
+
+static void _MAINDisplay(WORLDMAP *w, PLAYER *p, DUNGEONMAP *d) {
+ HWStatus(p->Object[OB_FOOD], /* Refresh the status bar */
+ p->Attr[AT_HP], p->Attr[AT_GOLD]);
+ HWClear(); /* Clear the screen */
+ if (p->Level == 0) /* Above ground, draw it */
+ WORLDDraw(p, w, 0);
+ else
+ DDRAWDraw(p, d);
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/monst.cpp b/engines/ultima/ultima0/monst.cpp
new file mode 100644
index 00000000000..17a9cad8872
--- /dev/null
+++ b/engines/ultima/ultima0/monst.cpp
@@ -0,0 +1,194 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Attacking Monsters Code */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+static int _MONSTAttack(MONSTER *, PLAYER *);
+static int _MONSTSteal(MONSTER *, PLAYER *);
+static void _MONSTMove(MONSTER *, PLAYER *, DUNGEONMAP *);
+static int _MONSTCanMoveTo(DUNGEONMAP *, int, int);
+
+/************************************************************************/
+/* */
+/* Check Monsters Attacking */
+/* */
+/************************************************************************/
+
+void MONSTAttack(PLAYER *p, DUNGEONMAP *d) {
+ int i, Attacked;
+ double Dist;
+ MONSTER *m;
+ for (i = 0; i < d->MonstCount; i++) /* Go through all monsters */
+ {
+ m = &(d->Monster[i]); /* Pointer to monster */
+ Dist = pow(m->Loc.x - p->Dungeon.x, 2); /* Calculate Distance */
+ Dist = Dist + pow(m->Loc.y - p->Dungeon.y, 2);
+ Dist = sqrt(Dist);
+ if (m->Alive != 0) /* If alive */
+ {
+ Attacked = 0;
+ if (Dist < 1.3) /* If within range */
+ Attacked = _MONSTAttack(m, p);
+ if (Attacked == 0) /* If didn't attack, then move */
+ {
+ if (m->Type != MN_MIMIC || /* Mimics only if near enough */
+ Dist >= 3.0)
+ _MONSTMove(m, p, d);
+ if (m->Strength < /* Recovers if didn't attack */
+ p->Level * p->Skill)
+ m->Strength = m->Strength + p->Level;
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* */
+/* Monster Attacks */
+/* */
+/************************************************************************/
+
+static int _MONSTAttack(MONSTER *m, PLAYER *p) {
+ int n;
+
+ if (m->Type == MN_GREMLIN || /* Special case for Gremlin/Thief */
+ m->Type == MN_THIEF)
+ if (RND() > 0.5) /* Half the time */
+ return _MONSTSteal(m, p);
+
+ DRAWText("You are being attacked by a %s !!!.\n",
+ GLOMonsterName(m->Type));
+
+ n = urand() % 20; /* Calculate hit chance */
+ if (p->Object[OB_SHIELD] > 0) n--;
+ n = n - p->Attr[AT_STAMINA];
+ n = n + m->Type + p->Level;
+ if (n < 0) /* Missed ! */
+ DRAWText("Missed !\n");
+ else /* Hit ! */
+ {
+ n = urand() % (m->Type); /* Calculate damage done. */
+ n = n + p->Level;
+ p->Attr[AT_HP] -= n; /* Adjust hit points */
+ DRAWText("Hit !!!\n");
+ }
+ return 1;
+}
+
+/************************************************************************/
+/* */
+/* Monster Moves */
+/* */
+/************************************************************************/
+
+static void _MONSTMove(MONSTER *m, PLAYER *p, DUNGEONMAP *d) {
+ int x, y, xi, yi;
+
+ xi = yi = 0; /* Calculate direction */
+ if (p->Dungeon.x != m->Loc.x)
+ xi = (p->Dungeon.x > m->Loc.x) ? 1 : -1;
+ if (p->Dungeon.y != m->Loc.y)
+ yi = (p->Dungeon.y > m->Loc.y) ? 1 : -1;
+
+ /* Running away */
+ if (m->Strength < p->Level * p->Skill)
+ {
+ xi = -xi; yi = -yi;
+ }
+ x = m->Loc.x; y = m->Loc.y; /* Get position */
+
+ if (abs(xi) > abs(yi)) /* Check move okay */
+ {
+ if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
+ else if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
+ } else
+ {
+ if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
+ else if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
+ }
+ if (xi == 0 && yi == 0) return; /* No move */
+ x = x + xi; y = y + yi; /* Work out new position */
+ if (_MONSTCanMoveTo(d, x, y) == 0) /* Fail if can't move there */
+ return;
+ if (x == p->Dungeon.x && /* Can't move onto us */
+ y == p->Dungeon.y) return;
+ m->Loc.x = x; m->Loc.y = y; /* Move to new position */
+}
+
+/************************************************************************/
+/* */
+/* Can monster move to a square */
+/* */
+/************************************************************************/
+
+static int _MONSTCanMoveTo(DUNGEONMAP *d, int x, int y) {
+ COORD c;
+ int t = d->Map[x][y]; /* See what's there */
+ if (!ISWALKTHRU(t)) return 0; /* Can't walk through walls */
+ c.x = x; c.y = y; /* Set up coord structure */
+ return DDRAWFindMonster(d, &c) < 0; /* True if no monster here */
+}
+
+/************************************************************************/
+/* */
+/* Monster Stealing */
+/* */
+/************************************************************************/
+
+static int _MONSTSteal(MONSTER *m, PLAYER *p) {
+ int n;
+ const char *s1, *s2;
+
+ if (m->Type == MN_GREMLIN) /* Gremlin */
+ {
+ p->Object[OB_FOOD] = /* HALVES the food.... aargh */
+ floor(p->Object[OB_FOOD]) / 2.0;
+ DRAWText("A Gremlin stole some food.\n");
+ }
+
+ if (m->Type == MN_THIEF) /* Thief */
+ {
+ do /* Figure out what stolen */
+ n = urand() % (p->Objects);
+ while (p->Object[n] == 0);
+ p->Object[n]--; /* Stole one */
+ s2 = GLOObjName(n); s1 = "a";
+ if (strchr("aeiou", tolower(*s2))) s1 = "an";
+ if (n == 0) s1 = "some";
+ DRAWText("A Thief stole %s %s.\n", s1, s2);
+ }
+ return 1;
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/move.cpp b/engines/ultima/ultima0/move.cpp
new file mode 100644
index 00000000000..a1d71e1f454
--- /dev/null
+++ b/engines/ultima/ultima0/move.cpp
@@ -0,0 +1,213 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Moving and Entry/Exit Code */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/* */
+/* Movement code */
+/* */
+/************************************************************************/
+
+void MOVEMove(int c, WORLDMAP *w, PLAYER *p, DUNGEONMAP *d, int xi, int yi) {
+ int z, x1, y1, Moved = 0;
+ const char *s1, *s2;
+ double n;
+ COORD New;
+ if (p->Level == 0) /* If above ground in world map */
+ {
+ x1 = p->World.x + xi; /* Calculate new position */
+ y1 = p->World.y + yi;
+ if (WORLDRead(w, x1, y1) == WT_MOUNTAIN)
+ DRAWText("You can't pass\nthe mountains.\n");
+ else
+ {
+ p->World.x = x1; /* Move */
+ p->World.y = y1;
+ }
+ } else /* If in the dungeon */
+ {
+ switch (c)
+ {
+ case 'N': x1 = p->Dungeon.x + p->DungDir.x;
+ y1 = p->Dungeon.y + p->DungDir.y;
+ New.x = x1; New.y = y1;
+ if (ISWALKTHRU(d->Map[x1][y1]) &&
+ DDRAWFindMonster(d, &New) < 0)
+ {
+ Moved = 1;
+ p->Dungeon = New;
+ }
+ break;
+
+ case 'E': MOVERotLeft(&(p->DungDir));
+ MOVERotLeft(&(p->DungDir));
+ MOVERotLeft(&(p->DungDir));
+ break;
+ case 'W': MOVERotLeft(&(p->DungDir));
+ break;
+ case 'S': MOVERotLeft(&(p->DungDir));
+ MOVERotLeft(&(p->DungDir));
+ break;
+ }
+
+ if (Moved != 0)
+ {
+ n = d->Map[p->Dungeon.x] /* What's here ? */
+ [p->Dungeon.y];
+ if (n == DT_PIT) /* Fell in a pit */
+ {
+ p->Level++; /* Down a level */
+ DRAWText("Aaarrrgghhh! A Trap !\n");
+ p->Attr[AT_HP] -= /* It hurts ! */
+ (3 + urand() % (3 * p->Level));
+ DRAWText("Falling to Level %d.\n", p->Level);
+ DUNGEONCreate(p, d); /* Create the new level */
+ }
+ if (n == DT_GOLD) /* Gold here */
+ {
+ d->Map[p->Dungeon.x] /* Remove the gold */
+ [p->Dungeon.y] = 0;
+ DRAWText("Gold !!!!!\n");
+ z = (urand() % (5 * p->Level)) /* Calculate amount */
+ + p->Level;
+ DRAWText("%d pieces of eight ", z);
+ p->Attr[AT_GOLD] += z; /* Add to total */
+ if (z > 0) /* Object ? */
+ {
+ z = urand() % (p->Objects);/* Decide which object */
+ s2 = GLOObjName(z); /* Get the name */
+ s1 = "a"; /* Decide a,an or some */
+ if (strchr("aeiou", tolower(*s2))) s1 = "an";
+ if (z == 0) s1 = "some";
+ DRAWText("and %s %s.\n", s1, s2);
+ p->Object[z]++; /* Bump the total */
+ }
+ }
+ }
+ MONSTAttack(p, d); /* Monster attacks ? */
+ }
+ n = p->Object[OB_FOOD];
+ p->Object[OB_FOOD] = p->Object[OB_FOOD] /* Consume some food */
+ - ((p->Level > 0) ? 0.1 : 1);
+ p->Object[OB_FOOD] = /* Make it integer */
+ floor(p->Object[OB_FOOD] * 10) / 10;
+ if (p->Object[OB_FOOD] <= 0) /* Starved us ? */
+ {
+ DRAWText("You have starved...\n");
+ p->Attr[AT_HP] = 0; /* Dead */
+ }
+}
+
+
+/************************************************************************/
+/* */
+/* Handle entry,exit */
+/* */
+/************************************************************************/
+
+void MOVEEnterExit(WORLDMAP *w, PLAYER *p, DUNGEONMAP *d) {
+ int t, Done = 0;
+ if (p->Level == 0) /* Entry/Exit on world map */
+ {
+ t = WORLDRead(w, p->World.x, /* Read tile */
+ p->World.y);
+ Done = 1;
+ switch (t)
+ {
+ case WT_TOWN: /* Enter the town */
+ DRAWText("Enter Town.\n");
+ TOWNEnter(w, p);
+ break;
+ case WT_DUNGEON: /* Enter the dungeon */
+ DRAWText("Enter Dungeon.\n");
+ p->Level = 1; /* Go to level 1 */
+ p->Dungeon.x = 1; /* Set initial position */
+ p->Dungeon.y = 1;
+ p->DungDir.x = 1; /* And direction */
+ p->DungDir.y = 0;
+ DUNGEONCreate(p, d); /* Create the dungeon map */
+ break;
+ case WT_BRITISH: /* Enter the castle */
+ DRAWText("Enter Castle.\n");
+ BRITISHEnter(w, p);
+ break;
+ default: /* Nope.... */
+ Done = 0; break;
+ }
+ } else /* Entry/Exit in dungeons */
+ {
+ t = d->Map[p->Dungeon.x] /* Identify what's there */
+ [p->Dungeon.y];
+ if (t == DT_LADDERUP) /* Climbing up a ladder */
+ {
+ p->Level--;
+ Done = 1;
+ if (p->Level == 0)
+ {
+ DRAWText("Leave the Dungeon.\n");
+ DRAWText("Thou has gained %d hit points.\n", p->HPGain);
+ p->Attr[AT_HP] += p->HPGain;
+ p->HPGain = 0;
+ } else
+ DRAWText("Go up to Level %d.\n", p->Level);
+ }
+ if (t == DT_LADDERDN) /* Climbing down a ladder */
+ {
+ p->Level++;
+ Done = 1;
+ DRAWText("Go down to Level %d.\n", p->Level);
+ }
+ if (Done != 0 && p->Level > 0) /* New Dungeon Map Required */
+ DUNGEONCreate(p, d);
+ }
+ if (Done == 0) /* Can't do it */
+ DRAWText("Huh???\n");
+}
+
+/************************************************************************/
+/* */
+/* Rotate a direction left */
+/* */
+/************************************************************************/
+
+void MOVERotLeft(COORD *Dir) {
+ int t;
+ if (Dir->y == 0) Dir->x = -Dir->x;
+ t = Dir->x;
+ Dir->x = Dir->y;
+ Dir->y = t;
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/player.cpp b/engines/ultima/ultima0/player.cpp
new file mode 100644
index 00000000000..5d1b8bb178b
--- /dev/null
+++ b/engines/ultima/ultima0/player.cpp
@@ -0,0 +1,157 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Manage Player Structures */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/* */
+/* Initialise the player character */
+/* */
+/************************************************************************/
+
+void PLAYERInit(PLAYER *p) {
+ int i;
+ memset(p, 0xFF, sizeof(PLAYER)); /* Fill with character $FF */
+ p->Name[0] = '\0';
+ p->World.x = p->World.y = 0;
+ p->Dungeon.x = p->Dungeon.y = 0;
+ p->DungDir.x = p->DungDir.y = 0;
+ p->Class = '?';
+ p->Level = 0; p->Skill = 0;
+ p->Task = 0; p->TaskCompleted = 0;
+ p->HPGain = 0;
+ p->LuckyNumber = urand(); /* We do the lucky number ! */
+ p->Attributes = p->Objects = 6; /* Aklabeth standards */
+ if (MAINSuper()) /* Super Aklabeth : more */
+ {
+ p->Attributes = MAX_ATTR;
+ p->Objects = MAX_OBJ;
+ }
+ for (i = 0; i < p->Attributes; i++) p->Attr[i] = 0;
+ for (i = 0; i < p->Objects; i++) p->Object[i] = 0.0;
+}
+
+/************************************************************************/
+/* */
+/* Manage Player Structures */
+/* */
+/************************************************************************/
+
+void PLAYERDebug(PLAYER *p) {
+ int i;
+ Common::strcpy_s(p->Name, "Debuggo"); /* Characters Name */
+ p->Class = 'F'; /* Fighter */
+ p->LuckyNumber = 42; /* Always the same..... */
+ p->Skill = 1; /* Skill level 1 */
+ for (i = 0; i < p->Attributes; i++) /* Nice high attributes */
+ p->Attr[i] = 99;
+ p->Attr[AT_HP] = 999;
+ p->Attr[AT_GOLD] = 9999;
+ for (i = 0; i < p->Objects; i++) /* Lots of nice objects */
+ p->Object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
+}
+
+void PLAYERDemo(PLAYER *p) {
+ int i;
+ Common::strcpy_s(p->Name, "Demo"); /* Characters Name */
+ p->Class = 'F'; /* Fighter */
+ p->LuckyNumber = 42; /* Always the same..... */
+ p->Skill = 1; /* Skill level 1 */
+ for (i = 0; i < p->Attributes; i++) /* Nice high attributes */
+ p->Attr[i] = 15;
+ p->Attr[AT_HP] = 18;
+ p->Attr[AT_GOLD] = 99;
+ for (i = 0; i < p->Objects; i++) /* Lots of nice objects */
+ p->Object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
+}
+
+/************************************************************************/
+/* */
+/* Player Inventory */
+/* */
+/************************************************************************/
+
+void PLAYERInv(PLAYER *p) {
+ int i;
+ HWStatus(p->Object[OB_FOOD], /* Refresh the status */
+ p->Attr[AT_HP], p->Attr[AT_GOLD]);
+ if (p->Name[0] != '\0') /* Display the name */
+ DRAWText("\n%s the %s.\n\n", p->Name, GLOClassName(p->Class));
+ else
+ DRAWText("\nA %s.\n\n", GLOClassName(p->Class));
+ for (i = 0; i < p->Attributes; i++) /* Display the attributes */
+ if (i != AT_HP && i != AT_GOLD)
+ DRAWText("%s: %d\n", GLOAttribName(i), p->Attr[i]);
+ DRAWText("\n");
+ for (i = 0; i < p->Objects; i++) /* Display the objects */
+ if (i != OB_FOOD)
+ DRAWText("%s: %u\n", GLOObjName(i), (int)p->Object[i]);
+ DRAWText("\n");
+}
+
+/************************************************************************/
+/* */
+/* Create a player character */
+/* */
+/************************************************************************/
+
+void PLAYERCharacter(PLAYER *p) {
+ int i;
+ DRAWText("Select skill level.\n");
+ while (i = HWGetKey(), !Common::isDigit(i)) {
+ };
+ i = i & 15; if (i == 0) i = 10;
+ DRAWText("Level %d.\n\n", i);
+
+ DRAWText("Hit your lucky key.\n\n");
+ p->LuckyNumber = HWGetKey();
+ DRAWText("Game Number %d.\n\n", p->LuckyNumber);
+
+ do
+ {
+ for (i = 0; i < p->Attributes; i++)
+ {
+ p->Attr[i] = floor(sqrt(RND()) * 21 + 4);
+ DRAWText("%s : %d.\n", GLOAttribName(i), p->Attr[i]);
+ }
+ DRAWText("\nWilt thou play with\nthese qualities ?\n\n");
+ } while (DEADGetYesNo() == 0);
+ DRAWText("And shalt thou be a\nFighter or a Mage ?\n\n");
+ do
+ {
+ p->Class = HWGetKey();
+ } while (p->Class != 'M' && p->Class != 'F');
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/resources.cpp b/engines/ultima/ultima0/resources.cpp
deleted file mode 100644
index ccefbaec464..00000000000
--- a/engines/ultima/ultima0/resources.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/* 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 "ultima/shared/engine/resources.h"
-
-namespace Ultima {
-
-} // End of namespace Ultima
diff --git a/engines/ultima/ultima0/sdw.cpp b/engines/ultima/ultima0/sdw.cpp
new file mode 100644
index 00000000000..d12398bfc9a
--- /dev/null
+++ b/engines/ultima/ultima0/sdw.cpp
@@ -0,0 +1,1147 @@
+/* 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 "common/events.h"
+#include "common/file.h"
+#include "audio/decoders/wave.h"
+#include "image/bmp.h"
+#include "graphics/screen.h"
+#include "ultima/ultima0/sdw.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+using namespace SDLWrapper;
+
+Graphics::Screen *Display; // The Display screen
+int GameSpeed = 120; // Scales the system clock.
+constexpr bool Joystick = true; // Do we have a joystick or do we mimic it ?
+//static SDL_Joystick *JoyPtr; // Pointer to a joystick object
+//static SDL_AudioSpec AudioFmt; // Audio system specification
+static AudioObject *SoundList[MAXSOUND]; // Audio objects in use.
+
+static uint32 _GetPixel(Graphics::ManagedSurface *Surface, int x, int y);
+
+static void SoundInitialise(void);
+static void SoundTerminate(void);
+static void SoundCallBack(void *Data, uint8 *Stream, int Length);
+
+// **************************************************************************************************************************
+//
+// Called when ERROR or ASSERT failes
+//
+// **************************************************************************************************************************
+
+void SDLWrapper::FatalError(int Line, const char *File) {
+ error("Fatal Error at line %d of %s", Line, File);
+}
+
+// **************************************************************************************************************************
+//
+// Set the game running speed, percent of normal
+//
+// **************************************************************************************************************************
+
+void SDLWrapper::SetSpeed(int n) {
+ GameSpeed = n;
+}
+
+
+// **************************************************************************************************************************
+//
+// Constructor for a surface
+//
+// **************************************************************************************************************************
+
+Surface::Surface(int x, int y, int Trans, int UseDisplay, const char *File) {
+// unsigned int Flags;
+
+ IsTransparent = Trans; // Save transparency flag
+ IsDisplay = UseDisplay; // Save physical display flag
+ TransColour = 0;
+ SetScale(); // Reset scale and origin
+ SetOrigin();
+#if 0
+ Flags = SDL_SWSURFACE; // Default flags
+ if (IsTransparent) // If transparent.
+ Flags |= SDL_SRCCOLORKEY;
+#endif
+
+ if (File == NULL) // Not loading a bitmap
+ {
+ if (x == 0) x = Display->w; // if x = y = 0 use whole screen
+ if (y == 0) y = Display->h;
+ xSize = x; ySize = y; // Store width and height
+
+ if (IsDisplay == 0)
+ {
+ sSurface = new Graphics::ManagedSurface(x, y);
+ TransColour = 254; // A horrible transparency colour
+// SDL_MapRGB(((SDL_Surface *)sSurface)->format, 220, 20, 130);
+ SetColour(); // Set the colour to the default (normally black)
+ FillRect(); // Erase the surface
+ } else {
+ // Use the display surface
+ sSurface = Display;
+ SetColour();
+ }
+ } else {
+ // Loading a bitmp
+ Common::File f;
+ Image::BitmapDecoder decoder;
+
+ if (!f.open(File) || !decoder.loadStream(f))
+ SDWERROR();
+
+ sSurface = new Graphics::ManagedSurface();
+ sSurface->copyFrom(*decoder.getSurface());
+
+ xSize = sSurface->w;
+ ySize = sSurface->h;
+
+ if (IsTransparent) // The colour is the top left pixel if transparent
+ TransColour = _GetPixel(sSurface, 0, 0);
+
+ SetColour();
+ }
+}
+
+// **************************************************************************************************************************
+//
+// Destructor for a surface
+//
+// **************************************************************************************************************************
+
+
+Surface::~Surface() {
+ if (!IsDisplay)
+ delete sSurface;
+ sSurface = nullptr;
+}
+
+// **************************************************************************************************************************
+//
+// Translate Points
+//
+// **************************************************************************************************************************
+
+void Surface::PointProcess(int &x, int &y) {
+ x = ((x * xScale) >> 8) + xOrigin;
+
+ y = ((y * yScale) >> 8) + yOrigin;
+}
+
+// **************************************************************************************************************************
+//
+// Set drawing colour
+//
+// **************************************************************************************************************************
+
+void Surface::SetColour(int r, int g, int b) {
+ Colour = sSurface->format.RGBToColor(r, g, b);
+#if 0
+ if (r >= 0 && g >= 0 && b >= 0) // Setting a colour normally
+ Colour = SDL_MapRGB(((SDL_Surface *)sSurface)->format, r, g, b);
+ else
+ { // Default behaviour
+ if (IsTransparent) // Transparency, or not.
+ {
+ Colour = TransColour;
+ SDL_SetColorKey((SDL_Surface *)sSurface, SDL_SRCCOLORKEY, (uint32)TransColour);
+ } else
+ SetColour(0, 0, 0);
+ }
+#endif
+}
+
+// **************************************************************************************************************************
+//
+// Single Pixel Plot
+//
+// **************************************************************************************************************************
+
+void Surface::Plot(int x1, int y1) {
+ SDL_Rect rc;
+ PointProcess(x1, y1);
+ SortAndValidate(x1, y1, x1, y1); // Doesn't Sort the 2 corners - still validates point
+ rc.x = x1; rc.y = y1; // Copy into the SDL Rectangle
+ rc.w = rc.h = 1;
+ SDL_FillRect((SDL_Surface *)sSurface, &rc, (uint32)Colour);
+}
+
+// **************************************************************************************************************************
+//
+// Fill a solid rectangle
+//
+// **************************************************************************************************************************
+
+void Surface::FillRect(int x1, int y1, int x2, int y2) {
+ SDL_Rect rc;
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+ rc.x = x1; rc.y = y1; // Copy into the SDL Rectangle
+ rc.w = x2 - x1 + 1; rc.h = y2 - y1 + 1;
+ SDL_FillRect((SDL_Surface *)sSurface, &rc, (uint32)Colour);
+}
+
+// **************************************************************************************************************************
+//
+// Frame a rectangle
+//
+// **************************************************************************************************************************
+
+void Surface::FrameRect(int x1, int y1, int x2, int y2) {
+ SDL_Rect rc, rc2;
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+ rc.x = x1; rc.y = y1; // Copy into the SDL Rectangle
+ rc.w = x2 - x1 + 1; rc.h = y2 - y1 + 1;
+
+ rc2 = rc; rc2.h = 1; // Draw the four frame edges
+ SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
+ rc2.y = rc.y + rc.h - 1;
+ SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
+ rc2 = rc; rc2.w = 1;
+ SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
+ rc2.x = rc.x + rc.w - 1;
+ SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
+}
+
+
+// **************************************************************************************************************************
+//
+// Sort coordinates , x and y into order. Check they are in range
+//
+// **************************************************************************************************************************
+
+void Surface::SortAndValidate(int &x1, int &y1, int &x2, int &y2) {
+ int t;
+ if (x1 > x2) {
+ t = x1; x1 = x2; x2 = t;
+ }
+ if (y1 > y2) {
+ t = y1; y1 = y2; y2 = t;
+ }
+ // SDWASSERT(x1 >= 0 && x1 < xSize);
+ // SDWASSERT(y1 >= 0 && y1 < ySize);
+ // SDWASSERT(x2 >= 0 && x2 < xSize);
+ // SDWASSERT(y2 >= 0 && y2 < ySize);
+}
+
+// **************************************************************************************************************************
+//
+// Copying from one surface to another : Copying is ALWAYS Physical Coordinates
+//
+// (1) From this to a target, given a source rectangle and optional position
+// (2) From this to the display, given a source rectangle and optional position
+
+// (3) From this to the display, whole surface, optional position
+// (4) From this to a target, whole surface, optional position
+//
+// **************************************************************************************************************************
+
+static void _SurfaceCopier(SDL_Surface *Src, SDL_Surface *Tgt,
+ int left, int top, int right, int bottom,
+ int x, int y);
+
+void Surface::Copy(Surface &Target, Rect &SrcRect, int x, int y) {
+ _SurfaceCopier((SDL_Surface *)sSurface,
+ (SDL_Surface *)Target.sSurface,
+ SrcRect.Left, SrcRect.Top, SrcRect.Right, SrcRect.Bottom, x, y);
+}
+
+void Surface::Copy(Rect &SrcRect, int x, int y) {
+ _SurfaceCopier((SDL_Surface *)sSurface,
+
+
+ (SDL_Surface *)Display,
+ SrcRect.Left, SrcRect.Top, SrcRect.Right, SrcRect.Bottom, x, y);
+}
+
+void Surface::Copy(int x, int y) {
+ _SurfaceCopier((SDL_Surface *)sSurface,
+ (SDL_Surface *)Display,
+ 0, 0, xSize - 1, ySize - 1, x, y);
+}
+
+void Surface::Copy(Surface &Target, int x, int y) {
+ _SurfaceCopier((SDL_Surface *)sSurface,
+ (SDL_Surface *)Target.sSurface,
+ 0, 0, xSize - 1, ySize - 1, x, y);
+}
+
+static void _SurfaceCopier(SDL_Surface *Src, SDL_Surface *Tgt,
+
+
+ int left, int top, int right, int bottom,
+ int x, int y) {
+ SDL_Rect rc, rc2;
+ rc.x = left; rc.y = top; rc.w = right - left + 1; rc.h = bottom - top + 1;
+ rc2.x = x; rc2.y = y;
+ SDL_BlitSurface(Src, &rc, Tgt, &rc2);
+}
+
+
+
+// **************************************************************************************************************************
+//
+// These routines draw filled and outline ellipses
+
+//
+// **************************************************************************************************************************
+
+static void _EllipsePoint(SDL_Surface *s, // This one draws two points or a line per vertical slice of ellipse
+ int x, int y, int w, uint32 c, int Solid) {
+ SDL_Rect rc;
+ if (Solid)
+ {
+ rc.x = x; rc.y = y; rc.w = w; rc.h = 1;
+ SDL_FillRect(s, &rc, c);
+ } else
+ {
+
+ rc.x = x; rc.y = y; rc.w = 1; rc.h = 1;
+ SDL_FillRect(s, &rc, c);
+ rc.x = x + w;
+ SDL_FillRect(s, &rc, c);
+ }
+}
+
+static void _DrawEllipse(SDL_Surface *s, // A Bresenham Algorithm I found originated by gerd.platl at siemens.at
+ int mx, int my, int a, int b, uint32 c, int Solid) {
+ int x, mx1, mx2, my1, my2;
+ int aq, bq, dx, dy, r, rx, ry;
+
+ _EllipsePoint(s, mx - a, my, a * 2, c, Solid);
+
+ mx1 = mx - a; my1 = my;
+ mx2 = mx + a; my2 = my;
+
+
+ aq = a * a; bq = b * b;
+
+ dx = aq * 2; dy = bq * 2;
+ r = a * bq;
+ rx = r * 2;
+ ry = 0;
+ x = a;
+
+ while (x > 0)
+ {
+ if (r > 0)
+
+ {
+ my1++; my2--;
+ ry = ry + dx;
+ r = r - ry;
+ }
+ if (r <= 0)
+ {
+ x--;
+ mx1++; mx2--;
+ rx = rx - dy;
+ r = r + rx;
+
+ }
+
+ _EllipsePoint(s, mx1, my1, mx2 - mx1, c, Solid);
+ _EllipsePoint(s, mx1, my2, mx2 - mx1, c, Solid);
+ }
+}
+
+void Surface::FillEllipse(int x1, int y1, int x2, int y2) {
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+ _DrawEllipse((SDL_Surface *)sSurface, // Draw filled ellipse
+ (x1 + x2) / 2, (y1 + y2) / 2,
+ (x2 - x1) / 2, (y2 - y1) / 2,
+ (uint32)Colour, 1);
+}
+
+void Surface::FrameEllipse(int x1, int y1, int x2, int y2) {
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+ _DrawEllipse((SDL_Surface *)sSurface, // Draw outline ellipse
+ (x1 + x2) / 2, (y1 + y2) / 2,
+ (x2 - x1) / 2, (y2 - y1) / 2,
+ (uint32)Colour, 0);
+}
+
+
+// **************************************************************************************************************************
+//
+// This is a Bresenham Line Algorithm for drawing lines
+//
+// **************************************************************************************************************************
+
+static void _LinePixel(SDL_Surface *s, int x, int y, int c) {
+ SDL_Rect rc;
+ if (x >= 0 && y >= 0 && x < s->w && y < s->h)
+ {
+ rc.x = x; rc.y = y; rc.w = rc.h = 1;
+ SDL_FillRect(s, &rc, (uint32)c);
+ }
+}
+
+void Surface::Line(int x1, int y1, int x2, int y2) {
+ int x, y, dx, dy, s1, s2;
+ int i, dp, temp, swap = 0;
+
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+
+ x = x1; y = y1;
+ _LinePixel((SDL_Surface *)sSurface, x1, y1, Colour);
+ dx = abs(x2 - x1);
+ dy = abs(y2 - y1);
+
+ if (x2 < x1) s1 = -1;
+ else if (x2 > x1) s1 = 1;
+ else s1 = 0;
+
+ if (y2 < y1) s2 = -1;
+ else if (y2 > y1) s2 = 1;
+ else s2 = 0;
+
+ dp = 2 * dy - dx;
+ if (dy > dx)
+ {
+ temp = dx; dx = dy; dy = temp; swap = 1;
+ }
+ for (i = 1; i <= dx; i++)
+ {
+ if (dp < 0)
+ {
+ if (swap)
+
+ _LinePixel((SDL_Surface *)sSurface, x, y = y + s2, Colour);
+ else
+ _LinePixel((SDL_Surface *)sSurface, x = x + s1, y, Colour);
+ dp = dp + 2 * dy;
+ } else
+ {
+ _LinePixel((SDL_Surface *)sSurface, x = x + s1, y = y + s2, Colour);
+ dp = dp + 2 * dy - 2 * dx;
+ }
+ }
+}
+
+// **************************************************************************************************************************
+
+//
+// An 8x8 pixel font, just alphanumeric characters
+//
+// **************************************************************************************************************************
+
+unsigned char font1[2048] =
+{
+ 124,130,186,162,186,130,124,0,126,129,165,129,165,153,129,126,
+ 126,129,165,129,153,165,129,126,108,246,246,254,124,56,16,0,
+ 16,56,124,254,124,56,16,0,16,56,84,254,84,16,56,0,
+ 56,124,254,254,108,16,56,0,16,24,20,20,48,112,96,0,
+ 254,254,254,238,254,254,254,0,236,138,138,170,170,170,236,0,
+ 142,136,136,140,136,136,232,0,174,170,170,234,170,170,174,0,
+ 238,136,136,204,136,136,136,0,238,138,138,142,140,138,234,0,
+ 62,34,62,34,102,238,204,0,16,84,40,198,40,84,16,0,
+ 240,248,252,254,252,248,240,0,30,62,126,254,126,62,30,0,
+ 16,56,124,16,124,56,16,0,238,238,238,238,238,0,238,0,
+ 254,68,68,68,68,68,68,0,126,128,188,198,122,2,252,0,
+ 0,0,0,0,255,255,0,0,16,56,124,16,124,56,16,254,
+ 16,56,124,254,56,56,56,0,56,56,56,254,124,56,16,0,
+ 16,24,252,254,252,24,16,0,16,48,126,254,126,48,16,0,
+
+
+
+ 144,72,36,18,36,72,144,0,18,36,72,144,72,36,18,0,
+ 16,40,68,146,40,68,130,0,130,68,40,146,68,40,16,0,
+ 0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,0,
+
+ 40,40,40,0,0,0,0,0,68,254,68,68,68,254,68,0,
+ 16,126,144,124,18,252,16,0,66,164,72,16,36,74,132,0,
+ 56,68,56,112,138,132,122,0,16,16,32,0,0,0,0,0,
+ 8,16,16,16,16,16,8,0,32,16,16,16,16,16,32,0,
+ 16,84,56,254,56,84,16,0,16,16,16,254,16,16,16,0,
+ 0,0,0,0,0,16,16,32,0,0,0,254,0,0,0,0,
+ 0,0,0,0,0,0,16,0,2,4,8,16,32,64,128,0,
+ 124,130,130,130,130,130,124,0,240,16,16,16,16,16,254,0,
+ 252,2,2,124,128,128,254,0,252,2,2,28,2,2,252,0,
+ 130,130,130,126,2,2,2,0,254,128,252,2,2,2,252,0,
+ 126,128,252,130,130,130,124,0,252,2,2,2,2,2,2,0,
+ 124,130,130,124,130,130,124,0,126,130,130,126,2,2,252,0,
+ 0,0,0,16,0,0,16,0,0,0,0,16,0,0,16,32,
+ 8,16,32,64,32,16,8,0,0,0,0,254,0,254,0,0,
+ 64,32,16,8,16,32,64,0,56,68,4,8,16,0,16,0,
+ 60,66,154,170,156,64,62,0,124,130,130,254,130,130,130,0,
+ 252,130,130,252,130,130,252,0,124,130,128,128,128,130,124,0,
+ 252,130,130,130,130,130,252,0,254,128,128,240,128,128,254,0,
+ 254,128,128,240,128,128,128,0,124,130,128,142,130,130,124,0,
+ 130,130,130,254,130,130,130,0,254,16,16,16,16,16,254,0,
+ 62,2,2,2,130,130,124,0,130,132,136,240,136,132,130,0,
+ 128,128,128,128,128,128,254,0,252,146,146,146,146,146,146,0,
+ 130,194,162,146,138,134,130,0,124,130,130,130,130,130,124,0,
+ 252,130,130,252,128,128,128,0,124,130,130,130,138,134,126,0,
+ 252,130,130,252,130,130,130,0,126,128,128,124,2,2,252,0,
+ 254,16,16,16,16,16,16,0,130,130,130,130,130,130,124,0,
+ 130,130,68,68,40,40,16,0,130,130,130,146,146,146,108,0,
+ 130,68,40,16,40,68,130,0,130,130,130,126,2,2,252,0,
+ 254,4,8,16,32,64,254,0,56,32,32,32,32,32,56,0,
+ 128,64,32,16,8,4,2,0,56,8,8,8,8,8,56,0,
+ 16,40,68,130,0,0,0,0,0,0,0,0,0,0,0,255,
+ 32,32,16,0,0,0,0,0,0,0,56,68,124,68,68,0,
+ 0,0,120,68,120,68,120,0,0,0,60,64,64,64,60,0,
+ 0,0,120,68,68,68,120,0,0,0,124,64,112,64,124,0,
+ 0,0,124,64,112,64,64,0,0,0,60,64,76,68,60,0,
+ 0,0,68,68,124,68,68,0,0,0,124,16,16,16,124,0,
+ 0,0,28,4,4,68,56,0,0,0,68,72,112,72,68,0,
+ 0,0,64,64,64,64,124,0,0,0,120,84,84,84,84,0,
+ 0,0,120,68,68,68,68,0,0,0,56,68,68,68,56,0,
+ 0,0,120,68,120,64,64,0,0,0,56,68,68,76,54,0,
+ 0,0,120,68,120,68,68,0,0,0,60,64,56,4,120,0,
+ 0,0,124,16,16,16,16,0,0,0,68,68,68,68,56,0,
+ 0,0,68,68,40,40,16,0,0,0,68,68,84,108,68,0,
+ 0,0,68,40,16,40,68,0,0,0,68,68,60,4,120,0,
+ 0,0,124,8,16,32,124,0,8,16,16,32,16,16,8,0,
+ 16,16,16,0,16,16,16,0,32,16,16,8,16,16,32,0,
+ 80,40,0,0,0,0,0,0,0,16,40,68,130,130,254,0,
+ 254,254,254,254,254,254,254,0,0,0,0,0,0,254,254,0,
+ 0,0,124,124,124,124,124,0,0,0,0,0,0,0,124,0,
+ 128,128,128,128,128,128,128,0,0,64,64,64,64,64,64,0,
+ 16,24,28,30,28,24,16,0,16,48,112,240,112,48,16,0,
+ 62,30,30,62,114,224,64,0,4,14,156,248,240,240,248,0,
+ 64,224,114,62,30,30,62,0,248,240,240,248,156,14,4,0,
+ 56,68,130,130,130,68,56,0,56,124,254,254,254,124,56,0,
+ 0,124,68,68,68,124,0,0,0,124,124,124,124,124,0,0,
+ 0,60,110,126,112,126,60,0,0,60,118,126,14,126,60,0,
+ 0,60,126,106,126,126,106,0,0,60,126,86,126,126,86,0,
+ 0,0,0,24,24,0,0,0,0,0,24,60,60,24,0,0,
+
+ 0,12,52,36,36,108,72,0,0,0,0,0,0,0,0,0,
+ 60,126,198,231,255,224,126,60,60,126,227,231,255,7,126,60,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,52,118,118,94,126,60,0,0,60,110,126,112,126,60,0,
+ 0,60,126,122,110,110,44,0,0,60,126,14,126,118,60,0,
+ 0,0,0,0,0,0,0,0,126,126,126,126,60,0,0,0,
+ 0,15,31,31,31,31,15,0,126,127,127,127,127,127,63,0,
+ 0,0,0,60,126,126,126,126,126,126,126,126,126,126,126,126,
+ 0,63,127,127,127,127,127,126,126,127,127,127,127,127,127,126,
+
+
+ 0,240,248,248,248,248,240,0,126,254,254,254,254,254,252,0,
+ 0,255,255,255,255,255,255,0,126,255,255,255,255,255,255,0,
+ 0,252,254,254,254,254,254,126,126,254,254,254,254,254,254,126,
+ 0,255,255,255,255,255,255,126,126,255,255,255,255,255,255,126,
+ 0,0,63,63,48,55,52,52,0,0,255,255,0,255,0,0,
+ 0,0,248,248,24,216,88,88,88,88,88,88,88,88,88,88,
+ 88,216,24,248,248,0,0,0,0,255,0,255,255,0,0,0,
+ 52,55,48,63,63,0,0,0,52,52,52,52,52,52,52,52,
+ 0,0,0,31,24,24,24,24,0,0,0,255,0,0,0,0,
+ 0,0,0,240,48,48,48,48,48,48,48,48,48,48,48,48,
+ 48,48,48,240,0,0,0,0,0,0,0,255,0,0,0,0,
+ 24,24,24,31,0,0,0,0,24,24,24,24,24,24,24,24,
+ 136,34,136,34,136,34,136,34,85,170,85,170,85,170,85,170,
+ 68,170,68,170,68,170,68,170,51,102,204,153,51,102,204,153,
+ 204,102,51,153,204,102,51,153,199,143,31,62,124,248,241,227,
+ 227,241,248,124,62,31,143,199,174,128,186,2,234,8,171,32,
+ 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,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,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,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,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,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,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,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,
+ 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,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,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,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,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,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,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,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,
+ 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,0,0,0,0,0,0,
+};
+
+
+// **************************************************************************************************************************
+//
+// Check if pixel is set in character
+//
+// **************************************************************************************************************************
+
+static int _FONTPixelSet(unsigned char *Data, int x, int y) {
+ if (x < 0 || y < 0 || x > 7 || y > 7) return 0;
+
+ return (Data[y] & (0x80 >> x)) ? 1 : 0;
+}
+
+// **************************************************************************************************************************
+
+//
+// Draw an angled line - this stops the squared corners on diagonals showing
+//
+// **************************************************************************************************************************
+
+static void _FONTAngleDraw(SDL_Surface *s, SDL_Rect *rc, int w, int h, uint32 Colour) {
+ int i, m;
+ SDL_Rect rc3;
+
+ m = abs(w); if (abs(h) > m) m = abs(h);
+ for (i = 0; i < m; i++)
+ {
+ rc3.x = rc->x + w * i / m;
+ rc3.y = rc->y + h * i / m;
+ rc3.w = rc->w; rc3.h = rc->h;
+ SDL_FillRect(s, &rc3, Colour);
+ }
+}
+
+// **************************************************************************************************************************
+//
+// Draw an 8x8 pixellated character (for fonts), does some rounding etc.
+//
+// **************************************************************************************************************************
+
+static void _FONTChar(SDL_Surface *s, SDL_Rect *rc, uint32 Colour, int Char) {
+ int x, y, w, h;
+ unsigned char *GfxData;
+ SDL_Rect rc2;
+ w = rc->w / 8; h = rc->h / 8; // work out the box sizes
+ SDWASSERT(w != 0 && h != 0); // At least one pixel !
+ if (Char == ' ') return; // Don't do anything for spaces
+ GfxData = font1 + Char * 8;
+ for (x = 0; x < 8; x++) // Work through the 64 pixel array
+ for (y = 0; y < 8; y++)
+
+ if (_FONTPixelSet(GfxData, x, y)) // If set.
+ {
+ rc2.x = rc->x + rc->w * x / 8; // Calculate the bounding rectangle
+ rc2.y = rc->y + rc->h * y / 8;
+ rc2.w = rc->x + rc->w * (x + 1) / 8 - rc2.x;
+
+ rc2.h = rc->y + rc->h * (y + 1) / 8 - rc2.y;
+ SDL_FillRect(s, &rc2, Colour); // Draw an pixel there
+
+ // Neaten the diagonals
+ if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
+ _FONTPixelSet(GfxData, x - 1, y) == 0 &&
+ _FONTPixelSet(GfxData, x - 1, y + 1) != 0)
+ _FONTAngleDraw(s, &rc2, -w, h, Colour);
+
+ if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
+ _FONTPixelSet(GfxData, x + 1, y) == 0 &&
+ _FONTPixelSet(GfxData, x + 1, y + 1) != 0)
+ _FONTAngleDraw(s, &rc2, w, h, Colour);
+ }
+}
+
+// **************************************************************************************************************************
+//
+// Draw a single character using the bevelled font
+//
+// **************************************************************************************************************************
+
+void Surface::Char(int x1, int y1, int x2, int y2, char c) {
+ SDL_Rect rc;
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+
+ rc.x = x1; rc.y = y1; // Set up bounding rectangle
+ rc.w = x2 - x1 + 1; rc.h = y2 - y1 + 1;
+
+ _FONTChar((SDL_Surface *)sSurface, &rc, (uint32)Colour, c);
+}
+
+
+// **************************************************************************************************************************
+//
+// Draw a string using the bevelled font
+//
+// **************************************************************************************************************************
+
+
+void Surface::String(int x1, int y1, int x2, int y2, const char *s) {
+ int i, n;
+ if (s == NULL) SDWERROR(); // Don't pass me NULL !
+ if (*s == '\0') return; // Empty string.
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+ n = strlen(s); // Length of string
+ for (i = 0; i < n; i++)
+ Char(x1 + i * (x2 - x1) / n, y1, x1 + (i + 1) * (x2 - x1) / n, y2, s[i]);
+}
+
+// **************************************************************************************************************************
+//
+// Pixel Reader (from the SDL Documentation)
+//
+// **************************************************************************************************************************
+
+static uint32 _GetPixel(SDL_Surface *Surface, int x, int y) {
+ const byte *p = (const byte *)Surface->getBasePtr(x, y);
+ int bpp = Surface->format.bytesPerPixel;
+
+ switch (bpp) {
+ case 1:
+ return *p;
+ case 2:
+ return READ_LE_UINT16(p);
+ case 3:
+ return p[0] << 16 | p[1] << 8 | p[2];
+ case 4:
+ return READ_LE_UINT32(p);
+ default:
+ return 0;
+ }
+}
+
+// **************************************************************************************************************************
+//
+// Flip a surface (Double Buffering)
+//
+// **************************************************************************************************************************
+
+void Surface::Flip(void) {
+ Display->update();
+}
+
+// **************************************************************************************************************************
+//
+
+// Mirroring functions
+//
+// **************************************************************************************************************************
+
+void Surface::HorizontalMirror(int x1, int y1, int x2, int y2) {
+ int x, y;
+ uint32 c1, c2;
+ SDL_Rect rc;
+ SDL_Surface *s = (SDL_Surface *)sSurface;
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+ rc.w = rc.h = 1;
+ for (y = y1; y <= y2; y++)
+ for (x = 0; x < (x2 - x1) / 2; x++)
+ {
+ c1 = _GetPixel(s, x1 + x, y);
+ c2 = _GetPixel(s, x2 - x, y);
+
+ rc.x = x1 + x; rc.y = y;
+
+
+ SDL_FillRect(s, &rc, c2);
+ rc.x = x2 - x;
+ SDL_FillRect(s, &rc, c1);
+ }
+}
+
+void Surface::VerticalMirror(int x1, int y1, int x2, int y2) {
+ int x, y;
+ uint32 c1, c2;
+ SDL_Rect rc;
+ SDL_Surface *s = (SDL_Surface *)sSurface;
+ if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
+ if (y2 == 0) y2 = ySize - 1;
+ PointProcess(x1, y1);
+ PointProcess(x2, y2);
+ SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
+
+ rc.w = rc.h = 1;
+ for (x = x1; x <= x2; x++)
+
+ for (y = 0; y < (y2 - y1) / 2; y++)
+ {
+ c1 = _GetPixel(s, x, y1 + y);
+ c2 = _GetPixel(s, x, y2 - y);
+ rc.x = x; rc.y = y1 + y;
+ SDL_FillRect(s, &rc, c2);
+ rc.y = y2 - y;
+ SDL_FillRect(s, &rc, c1);
+
+ }
+}
+
+
+// **************************************************************************************************************************
+//
+// Function returns system timer, game timer
+//
+// **************************************************************************************************************************
+
+int SDLWrapper::GameClock(void) {
+ return g_system->getMillis() * GameSpeed / 100;
+}
+
+int SDLWrapper::SystemClock(void) {
+ return g_system->getMillis();
+}
+
+
+// **************************************************************************************************************************
+//
+// Timer Class
+//
+// **************************************************************************************************************************
+
+Timer::Timer(int TimeOut) // Create it
+{
+ StartClock = GameClock(); // When we started
+ EventTime = TimeOut; // When the timer times out
+ ResetTimer(); // Set the end time
+}
+
+void Timer::ResetTimer(int t) // Reset it. If default param (0) use same time as before
+{
+ if (t != 0) EventTime = t;
+ EndClock = GameClock() + EventTime;
+}
+
+unsigned int Timer::Elapsed(void) // Time elapsed since creation
+{
+ return GameClock() - StartClock;
+}
+
+int Timer::TimedOut(void) // Has the timer timed out
+{
+ int t = (GameClock() > EndClock);
+ if (t) ResetTimer(0);
+ return t;
+}
+
+void Timer::WaitTimer(void) // Wait for the timer to time out
+
+{
+ while (!TimedOut()) {
+ }
+}
+
+// **************************************************************************************************************************
+//
+// Read a joystick - if there is one - or emulate it from the keyboard
+//
+// **************************************************************************************************************************
+
+static int _Process(int Pos) // Converts an analogue position to a digital directional value
+{
+ if (abs(Pos) < 1024) return 0;
+ return (Pos < 0) ? -1 : 1;
+}
+
+int SDLWrapper::ReadStick(int &A, int &B, int &dx, int &dy) {
+#ifdef TODO
+ SDL_Event e;
+ int r;
+ while (SDL_PollEvent(&e)) {
+ } // Process the event queue
+ if (Joystick && 0) // Joystick available ? (ID#0)
+ {
+ SDL_JoystickUpdate(); // Update everything
+ dx = _Process(SDL_JoystickGetAxis(JoyPtr, 0));
+ dy = _Process(SDL_JoystickGetAxis(JoyPtr, 1));
+ A = r = (SDL_JoystickGetButton(JoyPtr, 0) != 0);
+ B = (SDL_JoystickGetButton(JoyPtr, 1) != 0);
+ } else // No joystick, use keyboard (arrow keys Z and X)
+ {
+ uint8 *Key = SDL_GetKeyState(NULL);
+ dx = dy = 0; // ZXCF or Arrow keys
+ if (Key[SDLK_LEFT]) dx = -1;
+ if (Key[SDLK_RIGHT]) dx = 1;
+ if (Key[SDLK_DOWN]) dy = 1;
+ if (Key[SDLK_UP]) dy = -1;
+ // A & B are G and H or 1 and 2 on the keypad
+ A = r = (Key[SDLK_LCTRL] != 0);
+ B = (Key[SDLK_LALT] != 0);
+
+ }
+ return r;
+#else
+ error("TODO: Read joystick");
+#endif
+}
+
+// **************************************************************************************************************************
+//
+// Game Over Key Pressed ?
+//
+// **************************************************************************************************************************
+
+int SDLWrapper::ExitKey() {
+ Common::Event e;
+ bool escFlag = false;
+
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_KEYDOWN && e.kbd.keycode == Common::KEYCODE_ESCAPE)
+ escFlag = true;
+ }
+
+ return escFlag;
+}
+
+int SDLWrapper::GetKey(void) {
+ Common::Event e;
+
+ while (!Engine::shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_KEYDOWN)
+ return e.kbd.keycode;
+ }
+ }
+
+ return -1;
+}
+
+// **************************************************************************************************************************
+//
+// Display Pointer, Follow Mouse around, Wait for Click.
+//
+// **************************************************************************************************************************
+
+int SDLWrapper::MouseClick(int &x, int &y) {
+ Common::Event e;
+
+ g_system->showMouse(true);
+
+ while (!Engine::shouldQuit()) {
+ if (g_system->getEventManager()->pollEvent(e) &&
+ e.type == Common::EVENT_LBUTTONUP)
+ break;
+ }
+
+ g_system->showMouse(false);
+ return true;
+}
+
+// **************************************************************************************************************************
+//
+// Mix data from an audio object into the Stream - used by callback function
+//
+// **************************************************************************************************************************
+
+void AudioObject::CopyStream(void *Stream, int Reqd) {
+#ifdef TODO
+ int Qty = Reqd; // Bytes to copy
+ if (SoundOn == 0) return;
+ if (Qty > Length - Position) // Can't use more than are available
+ {
+ if (LoopSound)
+ Position = 0;
+ else
+ Qty = Length - Position;
+ }
+ if (Qty != 0) // Some data ?
+ {
+ uint8 *Audio = (uint8 *)Data;
+ Audio = Audio + Position;
+ SDL_MixAudio((uint8 *)Stream, Audio, Qty, // If so, mix it in.
+ SDL_MIX_MAXVOLUME);
+ Position = Position + Qty;
+ }
+#endif
+}
+
+// **************************************************************************************************************************
+//
+// Attach and Detach objects from the internal sound object list
+//
+// **************************************************************************************************************************
+
+void AudioObject::Attach(void) {
+ int i = 0;
+ for (i = 0; i < MAXSOUND; i++) // Look for empty slot
+ if (SoundList[i] == NULL) // If found, copy reference in
+ {
+ SoundList[i] = this;
+ return;
+ }
+}
+
+void AudioObject::Detach(void) {
+ for (int i = 0; i < MAXSOUND; i++) // Look for it and delete it.
+
+ if (SoundList[i] == this) SoundList[i] = NULL;
+}
+
+// **************************************************************************************************************************
+//
+// Load a .WAV file
+//
+// **************************************************************************************************************************
+
+void AudioWave::Load(const char *File) {
+ Common::File *f = new Common::File();
+
+ if (f->open(File)) {
+ _stream = Audio::makeWAVStream(f, DisposeAfterUse::YES);
+ assert(_stream);
+ } else {
+ delete f;
+ error("Failed to load %s", File);
+ }
+}
+
+// **************************************************************************************************************************
+//
+// Create a beep.
+//
+// **************************************************************************************************************************
+
+void AudioBeep::CreateBeep(int sPitch, int sLength) {
+#ifdef TODO
+ int Size = AudioFmt.freq * sLength / 1000;
+ SDWASSERT(AudioFmt.format = AUDIO_S16); // We must be using 16 bit signed here ?
+ Uint16 *Wave = (Uint16 *)malloc(Size * 2); // Allocate a buffer for it
+ CreateWave(Wave, Size, sPitch); // Create the wave
+ SDL_LockAudio(); // Copy data into structure
+ Data = Wave;
+ Length = Size * 2;
+ Position = 0;
+ SDL_UnlockAudio();
+#else
+ error("TODO: CreateBeep");
+#endif
+}
+
+void AudioObject::Write(int Pos, int Dat) {
+#ifdef TODO
+ if (Pos >= 0 && Pos < Length / 2)
+ {
+ Uint16 *Wave = (Uint16 *)Data;
+ Wave[Pos] = Dat;
+ }
+#else
+ error("TODO: AudioObject::Write");
+#endif
+}
+
+// **************************************************************************************************************************
+//
+// Wave Creators for beeps and hisses - one square wave, one white noise
+//
+// **************************************************************************************************************************
+
+void AudioBeep::CreateWave(void *data, int Size, int sPitch) {
+#ifdef TODO
+ Uint16 *Wave = (Uint16 *)data;
+ int PCount = 0;
+ int PValue = 32700;
+ int PMax = 0;
+ if (sPitch > 0) PMax = AudioFmt.freq / sPitch / 2;
+ for (int i = 0; i < Size; i++)
+ {
+ Wave[i] = (sPitch == 0 ? rand() : PValue);
+ if (++PCount == PMax)
+ {
+ PCount = 0; PValue = -PValue;
+ }
+ }
+#else
+ error("TODO: AudioBeep::CreateWave");
+#endif
+}
+
+
+// **************************************************************************************************************************
+//
+// Mixing Callback function
+//
+// **************************************************************************************************************************
+
+
+static void SoundCallBack(void *Data, uint8 *Stream, int Length) {
+#ifdef TODO
+ Data = Data; // Stops nagging :)
+ for (int i = 0; i < MAXSOUND; i++) // Work through all the sounds
+ {
+ if (SoundList[i] != NULL) // Call the handler function to copy them.
+ SoundList[i]->CopyStream(Stream, Length);
+ }
+#endif
+}
+
+// **************************************************************************************************************************
+//
+// Initialise Sound System
+//
+// **************************************************************************************************************************
+
+static void SoundInitialise(void) {
+#ifdef TODO
+ for (int i = 0; i < MAXSOUND; i++) // Erase all sound objects
+ SoundList[i] = NULL;
+ AudioFmt.freq = 22050; // Frequency of reproduction
+ AudioFmt.format = AUDIO_S16; // 16 bit sound
+ AudioFmt.channels = 1; // No of channels
+ AudioFmt.samples = 1024; // Sample length
+ AudioFmt.callback = SoundCallBack; // Callback function
+ AudioFmt.userdata = NULL; // Don't use this :)
+ if (SDL_OpenAudio(&AudioFmt, NULL) < 0) // Open the audio devices
+ SDWERROR(); // ... or not.
+ SDL_PauseAudio(0); // Turn the audio system on.
+#endif
+}
+
+// **************************************************************************************************************************
+//
+// Terminate sound systems
+//
+// **************************************************************************************************************************
+
+static void SoundTerminate(void) {
+ //SDL_CloseAudio(); // Close the audio devices
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/sdw.h b/engines/ultima/ultima0/sdw.h
new file mode 100644
index 00000000000..35de7bc2b6f
--- /dev/null
+++ b/engines/ultima/ultima0/sdw.h
@@ -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/>.
+ *
+ */
+
+#ifndef ULTIMA_ULTIMA0_SDW_H
+#define ULTIMA_ULTIMA0_SDW_H
+
+#include "audio/mixer.h"
+#include "audio/audiostream.h"
+#include "graphics/managed_surface.h"
+#include "graphics/screen.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+extern Graphics::Screen *Display; // The Display screen
+extern int GameSpeed; // Scales the system clock.
+
+// It's all nicely in a namespace SDLWrapper
+namespace SDLWrapper {
+
+#define DEFAULT_SCX (1024) // Default Screen Size and Depth
+#define DEFAULT_SCY (768)
+#define DEFAULT_SCBPP (0)
+#define MAXSOUND (16) // Maximum number of sounds
+
+#define SDWASSERT(x) if (!(x)) SDWERROR() // ASSERT and ERROR macros
+#define SDWERROR() FatalError(__LINE__,__FILE__)
+
+extern void SetSpeed(int n);
+extern void FatalError(int line, const char *filename); // Prototyping
+
+extern int GameClock(void); // No point in wrapping this, it just goes to SDL_GetTicks()
+extern int SystemClock(void); // This one is unaffected by the game speed.
+
+extern int ReadStick(int &A, int &B, int &dx, int &dy); // Read a joystick
+extern int MouseClick(int &x, int &y); // Read a mouse select - and - click
+extern int ExitKey(void);
+extern int GetKey(void);
+
+struct SDL_Rect {
+ int x = 0;
+ int y = 0;
+ int w = 0;
+ int h = 0;
+
+ operator const Common::Rect() const {
+ return Common::Rect(x, y, x + w, y + h);
+ }
+};
+
+typedef Graphics::ManagedSurface SDL_Surface;
+
+class Rect {
+public:
+ Rect() {} // Constructors
+ Rect(int x1, int y1, int x2, int y2) {
+ Left = x1; Top = y1; Right = x2; Bottom = y2;
+ }
+ int Left, Top, Right, Bottom; // The rectangle
+};
+
+// A basic Surface
+class Surface {
+public:
+ Surface(int x = 0, int y = 0, int Trans = 0, int UseDisplay = 0, const char *File = nullptr);
+ ~Surface();
+
+ void SetColour(int r, int g, int b);
+ void SetColour() {
+ SetColour(-1, -1, -1);
+ }
+ void SetColour(int Col) {
+ Colour = Col;
+ }
+ unsigned int GetColour(void) {
+ return Colour;
+ }
+ int Width(void) {
+ return xSize;
+ }
+ int Height(void) {
+ return ySize;
+ }
+ void SetOrigin(int x = 0, int y = 0) {
+ xOrigin = x; yOrigin = y;
+ }
+ void SetScale(int x = 256, int y = 256) {
+ xScale = x; yScale = y;
+ }
+
+ void Plot(int x1, int y1);
+ void FillRect(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+ void FillRect(Rect &r) {
+ FillRect(r.Left, r.Top, r.Right, r.Bottom);
+ }
+ void FrameRect(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+ void FrameRect(Rect &r) {
+ FrameRect(r.Left, r.Top, r.Right, r.Bottom);
+ }
+ void FillEllipse(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+ void FillEllipse(Rect &r) {
+ FillEllipse(r.Left, r.Top, r.Right, r.Bottom);
+ }
+ void FrameEllipse(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+ void FrameEllipse(Rect &r) {
+ FrameEllipse(r.Left, r.Top, r.Right, r.Bottom);
+ }
+ void Line(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+
+ void Copy(Surface &Target, Rect &SrcRect, int x = 0, int y = 0);
+ void Copy(Rect &SrcRect, int x = 0, int y = 0);
+ void Copy(Surface &Target, int x = 0, int y = 0);
+ void Copy(int x = 0, int y = 0);
+
+ void HorizontalMirror(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+ void VerticalMirror(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
+
+ void Char(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, char c = ' ');
+ void Char(Rect &r, char c) {
+ Char(r.Left, r.Top, r.Right, r.Bottom, c);
+ }
+ void String(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, const char *s = "");
+ void String(Rect &r, char *s) {
+ String(r.Left, r.Top, r.Right, r.Bottom, s);
+ }
+
+ void Flip(void);
+
+
+protected:
+ void SortAndValidate(int &x1, int &y1, int &x2, int &y2);
+ void PointProcess(int &x1, int &y1);
+
+private:
+ SDL_Surface *sSurface;
+ int xSize, ySize; // Surface size (physical)
+ unsigned int Colour; // Drawing colour
+ int IsTransparent; // Set if transparent
+ unsigned int TransColour; // Transparency drawing colour
+ int IsDisplay; // Set if is the physical display object
+ int xOrigin, yOrigin; // Mobile origin and scaling
+ int xScale, yScale;
+};
+
+// A surface but with transparency
+class TransparentSurface : public Surface {
+public:
+ TransparentSurface(int x = 0, int y = 0) : Surface(x, y, 1, 0, nullptr) {
+ }
+};
+
+// A surface with a bitmap on it, one solid, one transparent
+class BitmapSurface : public Surface {
+public:
+ BitmapSurface(const char *File) : Surface(0, 0, 0, 0, File) {
+ }
+};
+
+class TransparentBitmapSurface : public Surface {
+public:
+ TransparentBitmapSurface(const char *File) : Surface(0, 0, 1, 0, File) {
+ }
+};
+
+// The actual physical display
+class DisplaySurface : public Surface {
+public:
+ DisplaySurface(int x = 0, int y = 0) : Surface(0, 0, 0, 1, nullptr) {
+ }
+};
+
+// A simple timer
+class Timer {
+public:
+ Timer(int TimeOut = 0);
+ void ResetTimer(int t = 0);
+ unsigned int Elapsed(void);
+ int TimedOut(void);
+ void WaitTimer(void);
+
+private:
+ int StartClock;
+ int EndClock;
+ int EventTime;
+};
+
+// An audio object
+class AudioObject {
+public:
+ AudioObject() {
+ Data = nullptr; Position = Length = 0; Attach(); SoundOn = 0; LoopSound = 0;
+ }
+ ~AudioObject() {
+ Detach(); if (Data != nullptr) free(Data);
+ }
+ void CopyStream(void *Stream, int Reqd);
+ void Play(void) {
+ Position = 0; SoundOn = 1;
+ }
+ void PlayLoop(void) {
+ Position = 0; SoundOn = 1; LoopSound = 1;
+ }
+ void Stop(void) {
+ SoundOn = 0; LoopSound = 0;
+ }
+ int Size(void) {
+ return Length / 2;
+ }
+ void Write(int Pos, int Dat);
+protected:
+ void Attach(void);
+ void Detach(void);
+ void *Data;
+ int Position;
+ int Length;
+ int SoundOn;
+ int LoopSound;
+};
+
+class AudioWave : public AudioObject {
+private:
+ Audio::SoundHandle _soundHandle;
+ Audio::AudioStream *_stream;
+
+public:
+ AudioWave(const char *File) : AudioObject() {
+ Load(File);
+ }
+protected:
+ void Load(const char *File);
+};
+
+class AudioBeep : public AudioObject {
+public:
+ AudioBeep(int p, int l) : AudioObject() {
+ CreateBeep(p, l);
+ }
+protected:
+ void CreateWave(void *Data, int Size, int sPitch);
+ void CreateBeep(int sPitch, int sLength);
+};
+
+class AudioNoise : public AudioBeep {
+public:
+ AudioNoise(int l) : AudioBeep(0, l) {
+ }
+};
+
+inline void SDL_FillRect(SDL_Surface *surf, const SDL_Rect *rect, uint Color) {
+ surf->fillRect(*rect, Color);
+}
+
+inline void SDL_BlitSurface(SDL_Surface *srcSurf, const SDL_Rect *srcRect,
+ SDL_Surface *destSurf, const SDL_Rect *destRect) {
+ destSurf->blitFrom(*srcSurf, *srcRect, *destRect);
+}
+
+} // namespace SDLWrapper
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/struct.h b/engines/ultima/ultima0/struct.h
new file mode 100644
index 00000000000..088964ac129
--- /dev/null
+++ b/engines/ultima/ultima0/struct.h
@@ -0,0 +1,104 @@
+/* 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 ULTIMA_ULTIMA0_STRUCT_H
+#define ULTIMA_ULTIMA0_STRUCT_H
+
+#include "ultima/ultima0/defines.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Data Structures */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+typedef struct _Coord /* Coordinate structure */
+{
+ int x, y;
+} COORD;
+
+/************************************************************************/
+
+typedef struct _Rect /* Rectangle structure */
+{
+ int left, top, right, bottom; /* Rectangle coords */
+} RECT;
+
+/************************************************************************/
+
+typedef struct _WorldMap /* World Map structure */
+{
+ int MapSize; /* Size of map */
+ unsigned char Map[WORLD_MAP_SIZE] /* Map information */
+ [WORLD_MAP_SIZE];
+} WORLDMAP;
+
+/************************************************************************/
+
+typedef struct _Monster /* Monster structure */
+{
+ COORD Loc; /* Position */
+ int Type; /* Monster type */
+ int Strength; /* Strength */
+ int Alive; /* Alive flag */
+} MONSTER;
+
+/************************************************************************/
+
+typedef struct _DungeonMap /* Dungeon Map Structure */
+{
+ int MapSize; /* Size of Map */
+ unsigned char Map[DUNGEON_MAP_SIZE] /* Map information */
+ [DUNGEON_MAP_SIZE];
+ int MonstCount; /* Number of Monsters */
+ MONSTER Monster[MAX_MONSTERS]; /* Monster records */
+} DUNGEONMAP;
+
+/************************************************************************/
+
+typedef struct _Player /* Player structure */
+{
+ char Name[MAX_NAME + 1]; /* Player Name */
+ COORD World; /* World map position */
+ COORD Dungeon; /* Dungeon map position */
+ COORD DungDir; /* Dungeon direction facing */
+ char Class; /* Player class (F or M) */
+ int HPGain; /* HPs gained in dungeon */
+ int Level; /* Dungeon level, 0 = world map */
+ int Skill; /* Skill level */
+ int Task; /* Task set (-1 = none) */
+ int TaskCompleted; /* Task completed */
+ int LuckyNumber; /* Value used for seeding */
+ int Attributes; /* Number of attributes */
+ int Objects; /* Number of objects */
+ int Attr[MAX_ATTR]; /* Attribute values */
+ double Object[MAX_OBJ]; /* Object counts */
+} PLAYER;
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/town.cpp b/engines/ultima/ultima0/town.cpp
new file mode 100644
index 00000000000..a016c6c6d6f
--- /dev/null
+++ b/engines/ultima/ultima0/town.cpp
@@ -0,0 +1,80 @@
+/* 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 "ultima/ultima0/akalabeth.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* Enter town (shopkeeper code) */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+void TOWNEnter(WORLDMAP *w, PLAYER *p) {
+ int Key, i, Cost, Incr, Item;
+ DRAWText("Welcome to the\nAdventure shop.\n");
+ do /* Keep Buying */
+ {
+ HWStatus(p->Object[OB_FOOD], /* Refresh the status bar */
+ p->Attr[AT_HP], p->Attr[AT_GOLD]);
+ DRAWText("\nWhat shalt thou buy?\n\n");
+ for (i = 0; i < p->Objects; i++) /* Price list */
+ {
+ GLOGetInfo(i, nullptr, &Cost, nullptr);
+ DRAWText("%s: %.0f (%d GP)\n", GLOObjName(i), floor(p->Object[i]), Cost);
+ }
+ Key = HWGetKey(); Item = -1; /* Get item to buy */
+ for (i = 0; i < p->Objects; i++) /* Find which one it was */
+ {
+ GLOGetInfo(i, nullptr, nullptr, &Cost);
+ if (Cost == Key) Item = i;
+ }
+ if (p->Class == 'M') /* Some things mages can't use */
+ if (Item == OB_BOW || Item == OB_RAPIER)
+ {
+ DRAWText("\nI'm sorry, Mages\ncan't use that.\n");
+ Item = -1;
+ }
+
+ if (Item >= 0) /* Something selected */
+ {
+ GLOGetInfo(Item, nullptr, &Cost, nullptr);
+ if (Cost > p->Attr[AT_GOLD])
+ DRAWText("\nM'Lord thou cannot\nafford that item.\n");
+ else
+ {
+ p->Attr[AT_GOLD] -= Cost; /* Lose the money */
+ HWStatus(p->Object[OB_FOOD],/* Refresh the status bar */
+ p->Attr[AT_HP], p->Attr[AT_GOLD]);
+ Incr = 1; if (Item == OB_FOOD) Incr = 10;
+ p->Object[Item] += Incr; /* Add 1 or 10 on */
+ }
+ }
+ } while (Key != 'Q');
+ DRAWText("\nBye.\n\n");
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/resources.h b/engines/ultima/ultima0/ultima0.cpp
similarity index 57%
rename from engines/ultima/ultima0/resources.h
rename to engines/ultima/ultima0/ultima0.cpp
index 6e9fa9421d5..ddb6a2e3f66 100644
--- a/engines/ultima/ultima0/resources.h
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -19,19 +19,37 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_RESOURCES_H
-#define ULTIMA_ULTIMA0_RESOURCES_H
-
-#include "ultima/shared/engine/resources.h"
+#include "engines/util.h"
+#include "ultima/ultima0/sdw.h"
+#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/sdw.h"
namespace Ultima {
namespace Ultima0 {
-class Resources : public Shared::LocalResourceFile {
+Ultima0Engine *g_engine;
+
+Ultima0Engine::Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc) :
+ Engine(syst), _gameDescription(gameDesc), _randomSource("Ultima0") {
+ g_engine = this;
+}
+
+Ultima0Engine::~Ultima0Engine() {
+}
+
+Common::Error Ultima0Engine::run() {
+ initGraphics(DEFAULT_SCX, DEFAULT_SCY);
+ Display = new Graphics::Screen();
+ GameSpeed = 120;
+
+ // Call the real main program
+ MAINStart();
-};
+ delete Display;
-} // End of namespace Ultima0
-} // End of namespace Ultima
+ return Common::kNoError;
+}
-#endif
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/game.h b/engines/ultima/ultima0/ultima0.h
similarity index 51%
rename from engines/ultima/ultima0/game.h
rename to engines/ultima/ultima0/ultima0.h
index b8be26f4cc2..10b69e8e5e4 100644
--- a/engines/ultima/ultima0/game.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -19,24 +19,54 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_GAME_H
-#define ULTIMA_ULTIMA0_GAME_H
+#ifndef ULTIMA_ULTIMA0_H
+#define ULTIMA_ULTIMA0_H
-#include "ultima/shared/early/game.h"
+#include "common/random.h"
+#include "engines/engine.h"
+#include "ultima/detection.h"
+#include "ultima/ultima0/defines.h"
namespace Ultima {
namespace Ultima0 {
-class Ultima0Game : public Shared::Game {
- DECLARE_MESSAGE_MAP;
+class Ultima0Engine : public Engine {
+private:
+ Common::RandomSource _randomSource;
+
+ const UltimaGameDescription *_gameDescription;
+
+protected:
+ // Engine APIs
+ Common::Error run() override;
+
public:
- CLASSDEF;
- Ultima0Game();
- ~Ultima0Game() override {}
+ Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
+ ~Ultima0Engine() override;
+ /**
+ * Returns supported engine features
+ */
+ bool hasFeature(EngineFeature f) const override {
+ return (f == kSupportsReturnToLauncher);
+ }
+
+ /**
+ * Sets the random number seed
+ */
+ void setRandomSeed(uint seed) {
+ _randomSource.setSeed(seed);
+ }
+
+ /**
+ * Get a random number
+ */
+ uint getRandomNumber(uint maxVal = RND_MAX) { return _randomSource.getRandomNumber(maxVal); }
};
-} // End of namespace Ultima0
+extern Ultima0Engine *g_engine;
+
+} // End of namespace Ultima4
} // End of namespace Ultima
#endif
diff --git a/engines/ultima/ultima0/world.cpp b/engines/ultima/ultima0/world.cpp
new file mode 100644
index 00000000000..a29a173c82c
--- /dev/null
+++ b/engines/ultima/ultima0/world.cpp
@@ -0,0 +1,122 @@
+/* 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/>.
+ *
+ */
+
+/************************************************************************/
+/************************************************************************/
+/* */
+/* World Map Code */
+/* */
+/************************************************************************/
+/************************************************************************/
+
+#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+/************************************************************************/
+/* */
+/* Create the world map, set player start position */
+/* */
+/************************************************************************/
+
+void WORLDCreate(PLAYER *p, WORLDMAP *w) {
+ int c, x, y, Size;
+
+ g_engine->setRandomSeed(p->LuckyNumber); /* Seed the random number */
+ Size = MAINSuper() ? WORLD_MAP_SIZE - 1 : 20; /* Calculate map size */
+ w->MapSize = Size; /* Save the map size */
+
+ // Draw the boundaries
+ for (x = 0; x <= Size; x++) {
+ w->Map[Size][x] = WT_MOUNTAIN;
+ w->Map[0][x] = WT_MOUNTAIN;
+ w->Map[x][Size] = WT_MOUNTAIN;
+ w->Map[x][0] = WT_MOUNTAIN;
+ }
+
+ /* Draw the rest of it */
+ for (x = 1; x < Size; x++)
+ for (y = 1; y < Size; y++) {
+ c = (int)(pow(RND(), 5.0) * 4.5); /* Calculate what's there */
+ if (c == WT_TOWN && RND() > .5) /* Remove half the towns */
+ c = WT_SPACE;
+ w->Map[x][y] = c; /* Save in map */
+ }
+ x = urand() % (Size - 1) + 1; /* Calculate player start */
+ y = urand() % (Size - 1) + 1;
+ p->World.x = x; p->World.y = y; /* Save it */
+ w->Map[x][y] = WT_TOWN; /* Make it a town */
+
+ /* Find place for castle */
+ do {
+ x = urand() % Size + 1;
+ y = urand() % Size + 1;
+ } while (w->Map[x][y] != WT_SPACE);
+
+ w->Map[x][y] = WT_BRITISH; /* Put LBs castle there */
+}
+
+/************************************************************************/
+/* */
+/* Read world map value */
+/* */
+/************************************************************************/
+
+int WORLDRead(WORLDMAP *w, int x, int y) {
+ if (x < 0 || y < 0) return WT_MOUNTAIN;
+ if (x > w->MapSize) return WT_MOUNTAIN;
+ if (y > w->MapSize) return WT_MOUNTAIN;
+ return w->Map[x][y];
+}
+
+/************************************************************************/
+/* */
+/* Draw world map */
+/* */
+/************************************************************************/
+
+void WORLDDraw(PLAYER *p, WORLDMAP *m, int ShowAsMap) {
+ int x, y, x1, y1, w, h, Grid;
+ RECT r;
+ Grid = 7; /* Number of cells in grid */
+ if (MAINSuper() == 0) Grid = 3; /* Standard Aklabeth */
+ if (ShowAsMap) Grid = m->MapSize + 1; /* Displaying as a map ? */
+ w = 1280 / Grid; h = 1024 / Grid; /* Get grid sizes */
+ for (x = 0; x < Grid; x++) /* For all grid cells */
+ for (y = 0; y < Grid; y++)
+ {
+ DRAWSetRect(&r, x * w, y * h, /* Work out the drawing rect */
+ x * w + w - 1, y * h + h - 1);
+ x1 = p->World.x - Grid / 2 + x; /* Which cell ? */
+ y1 = p->World.y + Grid / 2 - y;
+ if (ShowAsMap) /* If map, not centred around us */
+ x1 = x, y1 = Grid - 1 - y;
+ DRAWTile(&r, WORLDRead(m, x1, y1));
+ if (x1 == p->World.x && /* Draw us if we're there */
+ y1 == p->World.y)
+ DRAWTile(&r, WT_PLAYER);
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
Commit: d81d1d8942375cabbfa34b631ddae86dee972eee
https://github.com/scummvm/scummvm/commit/d81d1d8942375cabbfa34b631ddae86dee972eee
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:23+11:00
Commit Message:
ULTIMA: ULTIMA0: Added view-based engine skeleton
Changed paths:
A engines/ultima/ultima0/events.cpp
A engines/ultima/ultima0/events.h
A engines/ultima/ultima0/messages.cpp
A engines/ultima/ultima0/messages.h
A engines/ultima/ultima0/views/startup.cpp
A engines/ultima/ultima0/views/startup.h
A engines/ultima/ultima0/views/view.cpp
A engines/ultima/ultima0/views/view.h
A engines/ultima/ultima0/views/views.h
engines/ultima/module.mk
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 763851d3d50..d906094056e 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -9,6 +9,8 @@ MODULE_OBJS := \
ifdef ENABLE_AKALABETH
MODULE_OBJS += \
ultima0/ultima0.o \
+ ultima0/events.o \
+ ultima0/messages.o \
ultima0/attack.o \
ultima0/british.o \
ultima0/ddraw.o \
@@ -26,7 +28,9 @@ MODULE_OBJS += \
ultima0/player.o \
ultima0/sdw.o \
ultima0/town.o \
- ultima0/world.o
+ ultima0/world.o \
+ ultima0/views/view.o \
+ ultima0/views/startup.o
endif
ifdef ENABLE_ULTIMA1
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
new file mode 100644
index 00000000000..989e3dc7419
--- /dev/null
+++ b/engines/ultima/ultima0/events.cpp
@@ -0,0 +1,348 @@
+/* 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 "common/config-manager.h"
+#include "graphics/screen.h"
+#include "ultima/ultima0/events.h"
+#include "ultima/ultima0/views/views.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+Events *g_events;
+
+Events::Events() : UIElement("Root", nullptr) {
+ g_events = this;
+}
+
+Events::~Events() {
+ g_events = nullptr;
+}
+
+void Events::runGame() {
+ uint currTime, nextFrameTime = 0;
+ _screen = new Graphics::Screen();
+ Views::Views views; // Loads all views in the structure
+
+ // Run the game
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot != -1)
+ g_engine->loadGameState(saveSlot);
+
+ addView("Startup");
+
+ Common::Event e;
+ while (!_views.empty() && !shouldQuit()) {
+ while (g_system->getEventManager()->pollEvent(e)) {
+ if (e.type == Common::EVENT_QUIT ||
+ e.type == Common::EVENT_RETURN_TO_LAUNCHER) {
+ _views.clear();
+ break;
+ } else {
+ processEvent(e);
+ }
+ }
+
+ if (_views.empty())
+ break;
+
+ g_system->delayMillis(10);
+ if ((currTime = g_system->getMillis()) >= nextFrameTime) {
+ nextFrameTime = currTime + FRAME_DELAY;
+ tick();
+ drawElements();
+ _screen->update();
+ }
+ }
+
+ delete _screen;
+}
+
+void Events::processEvent(Common::Event &ev) {
+ switch (ev.type) {
+ case Common::EVENT_KEYDOWN:
+ if (ev.kbd.keycode < Common::KEYCODE_NUMLOCK)
+ msgKeypress(KeypressMessage(ev.kbd));
+ break;
+ case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+ msgAction(ActionMessage(ev.customType));
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_MBUTTONDOWN:
+ msgMouseDown(MouseDownMessage(ev.type, ev.mouse));
+ break;
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_MBUTTONUP:
+ msgMouseUp(MouseUpMessage(ev.type, ev.mouse));
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ msgMouseMove(MouseMoveMessage(ev.type, ev.mouse));
+ break;
+ default:
+ break;
+ }
+}
+
+void Events::replaceView(UIElement *ui, bool replaceAllViews) {
+ assert(ui);
+ UIElement *priorView = focusedView();
+
+ if (replaceAllViews) {
+ clearViews();
+
+ } else if (!_views.empty()) {
+ priorView->msgUnfocus(UnfocusMessage());
+ _views.pop();
+ }
+
+ _views.push(ui);
+ ui->redraw();
+ ui->msgFocus(FocusMessage(priorView));
+}
+
+void Events::replaceView(const Common::String &name, bool replaceAllViews) {
+ replaceView(findView(name));
+}
+
+void Events::addView(UIElement *ui) {
+ assert(ui);
+ UIElement *priorView = focusedView();
+
+ if (!_views.empty())
+ priorView->msgUnfocus(UnfocusMessage());
+
+ _views.push(ui);
+ ui->redraw();
+ ui->msgFocus(FocusMessage(priorView));
+}
+
+void Events::addView(const Common::String &name) {
+ addView(findView(name));
+}
+
+void Events::popView() {
+ UIElement *priorView = focusedView();
+ priorView->msgUnfocus(UnfocusMessage());
+ _views.pop();
+
+ for (int i = 0; i < (int)_views.size() - 1; ++i) {
+ _views[i]->redraw();
+ _views[i]->draw();
+ }
+
+ if (!_views.empty()) {
+ UIElement *view = focusedView();
+ view->msgFocus(FocusMessage(priorView));
+ view->redraw();
+ view->draw();
+ }
+}
+
+void Events::redrawViews() {
+ for (uint i = 0; i < _views.size(); ++i) {
+ _views[i]->redraw();
+ _views[i]->draw();
+ }
+}
+
+bool Events::isPresent(const Common::String &name) const {
+ for (uint i = 0; i < _views.size(); ++i) {
+ if (_views[i]->_name == name)
+ return true;
+ }
+
+ return false;
+}
+
+void Events::clearViews() {
+ if (!_views.empty())
+ focusedView()->msgUnfocus(UnfocusMessage());
+
+ _views.clear();
+}
+
+void Events::addKeypress(const Common::KeyCode kc) {
+ Common::KeyState ks;
+ ks.keycode = kc;
+ if (kc >= Common::KEYCODE_SPACE && kc <= Common::KEYCODE_TILDE)
+ ks.ascii = kc;
+
+ focusedView()->msgKeypress(KeypressMessage(ks));
+}
+
+/*------------------------------------------------------------------------*/
+
+Bounds::Bounds(Common::Rect &innerBounds) :
+ _bounds(0, 0, 320, 200),
+ _innerBounds(innerBounds),
+ left(_bounds.left), top(_bounds.top),
+ right(_bounds.right), bottom(_bounds.bottom) {
+}
+
+Bounds &Bounds::operator=(const Common::Rect &r) {
+ _bounds = r;
+ _innerBounds = r;
+ _innerBounds.grow(-_borderSize);
+ return *this;
+}
+
+void Bounds::setBorderSize(size_t borderSize) {
+ _borderSize = borderSize;
+ _innerBounds = *this;
+ _innerBounds.grow(-_borderSize);
+}
+
+/*------------------------------------------------------------------------*/
+
+UIElement::UIElement(const Common::String &name) :
+ _name(name), _parent(g_engine), _bounds(_innerBounds) {
+ g_engine->_children.push_back(this);
+}
+
+UIElement::UIElement(const Common::String &name, UIElement *uiParent) :
+ _name(name), _parent(uiParent),
+ _bounds(_innerBounds) {
+ if (_parent)
+ _parent->_children.push_back(this);
+}
+
+void UIElement::redraw() {
+ _needsRedraw = true;
+
+ for (size_t i = 0; i < _children.size(); ++i)
+ _children[i]->redraw();
+}
+
+void UIElement::drawElements() {
+ if (_needsRedraw) {
+ draw();
+ _needsRedraw = false;
+ }
+
+ for (size_t i = 0; i < _children.size(); ++i)
+ _children[i]->drawElements();
+}
+
+UIElement *UIElement::findViewGlobally(const Common::String &name) {
+ return g_events->findView(name);
+}
+
+void UIElement::focus() {
+ g_events->replaceView(this);
+}
+
+void UIElement::close() {
+ assert(g_events->focusedView() == this);
+ g_events->popView();
+}
+
+bool UIElement::isFocused() const {
+ return g_events->focusedView() == this;
+}
+
+void UIElement::clearSurface() {
+ Graphics::ManagedSurface s = getSurface();
+ s.fillRect(Common::Rect(s.w, s.h), 0);
+}
+
+void UIElement::draw() {
+ for (size_t i = 0; i < _children.size(); ++i) {
+ _children[i]->draw();
+ }
+}
+
+bool UIElement::tick() {
+ if (_timeoutCtr && --_timeoutCtr == 0) {
+ timeout();
+ }
+
+ for (size_t i = 0; i < _children.size(); ++i) {
+ if (_children[i]->tick())
+ return true;
+ }
+
+ return false;
+}
+
+UIElement *UIElement::findView(const Common::String &name) {
+ if (_name.equalsIgnoreCase(name))
+ return this;
+
+ UIElement *result;
+ for (size_t i = 0; i < _children.size(); ++i) {
+ if ((result = _children[i]->findView(name)) != nullptr)
+ return result;
+ }
+
+ return nullptr;
+}
+
+void UIElement::replaceView(UIElement *ui, bool replaceAllViews) {
+ g_events->replaceView(ui, replaceAllViews);
+}
+
+void UIElement::replaceView(const Common::String &name, bool replaceAllViews) {
+ g_events->replaceView(name, replaceAllViews);
+}
+
+void UIElement::addView(UIElement *ui) {
+ g_events->addView(ui);
+}
+
+void UIElement::addView(const Common::String &name) {
+ g_events->addView(name);
+}
+
+void UIElement::addView() {
+ g_events->addView(this);
+}
+
+Graphics::ManagedSurface UIElement::getSurface() const {
+ return Graphics::ManagedSurface(*g_events->getScreen(), _bounds);
+}
+
+int UIElement::getRandomNumber(int minNumber, int maxNumber) {
+ return g_engine->getRandomNumber(maxNumber - minNumber + 1) + minNumber;
+}
+
+int UIElement::getRandomNumber(int maxNumber) {
+ return g_engine->getRandomNumber(maxNumber);
+}
+
+void UIElement::delaySeconds(uint seconds) {
+ _timeoutCtr = seconds * FRAME_RATE;
+}
+
+void UIElement::delayFrames(uint frames) {
+ _timeoutCtr = frames;
+}
+
+void UIElement::timeout() {
+ redraw();
+}
+
+} // namespace Ultima0
+} // namespace Ultima
+
diff --git a/engines/ultima/ultima0/events.h b/engines/ultima/ultima0/events.h
new file mode 100644
index 00000000000..c1b5aca99aa
--- /dev/null
+++ b/engines/ultima/ultima0/events.h
@@ -0,0 +1,417 @@
+/* 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 ULTIMA_ULTIMA0_EVENTS_H
+#define ULTIMA_ULTIMA0_EVENTS_H
+
+#include "common/array.h"
+#include "common/stack.h"
+#include "graphics/screen.h"
+#include "ultima/ultima0/messages.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+#define FRAME_RATE 20
+#define FRAME_DELAY (1000 / FRAME_RATE)
+
+class Events;
+
+/**
+ * Implements a thunk layer around an element's bounds,
+ * allowing access to it as if it were a simple Common::Rect,
+ * but any changes to it will also be applied to a linked inner bounds
+ */
+struct Bounds {
+private:
+ Common::Rect _bounds;
+ Common::Rect &_innerBounds;
+ int _borderSize = 0;
+public:
+ const int16 &left;
+ const int16 ⊤
+ const int16 &right;
+ const int16 ⊥
+public:
+ Bounds(Common::Rect &innerBounds);
+ operator const Common::Rect &() const {
+ return _bounds;
+ }
+ Bounds &operator=(const Common::Rect &r);
+ void setBorderSize(size_t borderSize);
+ size_t borderSize() const {
+ return _borderSize;
+ }
+ int16 width() const {
+ return _bounds.width();
+ }
+ int16 height() const {
+ return _bounds.height();
+ }
+};
+
+/**
+ * User interface element
+ */
+class UIElement {
+ friend class Events;
+private:
+ int _timeoutCtr = 0;
+protected:
+ UIElement *_parent;
+ Common::Array<UIElement *> _children;
+ Common::Rect _innerBounds;
+ Bounds _bounds;
+ bool _needsRedraw = true;
+ Common::String _name;
+protected:
+ /**
+ * Set a delay countdown in seconds, after which timeout() is called
+ */
+ void delaySeconds(uint seconds);
+
+ /**
+ * Set a delay countdown in frames, after which timeout() is called
+ */
+ void delayFrames(uint frames);
+
+ /**
+ * Returns true if a delay is active
+ */
+ bool isDelayActive() const {
+ return _timeoutCtr != 0;
+ }
+
+ /**
+ * Cancels any active delay
+ */
+ void cancelDelay() {
+ _timeoutCtr = 0;
+ }
+
+ /**
+ * Called when an active timeout countdown expired
+ */
+ virtual void timeout();
+
+private:
+ /**
+ * Outer method for doing drawing
+ *
+ */
+ void drawElements();
+
+ /**
+ * Finds a view globally
+ */
+ static UIElement *findViewGlobally(const Common::String &name);
+public:
+ UIElement(const Common::String &name, UIElement *uiParent);
+ UIElement(const Common::String &name);
+ virtual ~UIElement() {
+ }
+
+ /**
+ * Returns true if the elements needs to be redrawn
+ */
+ bool needsRedraw() const {
+ return _needsRedraw;
+ }
+
+ /**
+ * Sets that the element needs to be redrawn
+ */
+ void redraw();
+
+ /**
+ * Focuses the element as the current view
+ */
+ void focus();
+
+ /**
+ * Closes the current view. The view must have been added
+ * via addView, so there's a remaining view afterwards
+ */
+ virtual void close();
+
+ /*
+ * Returns true if the view is focused
+ */
+ bool isFocused() const;
+
+ /**
+ * Sets the focus to a new view
+ */
+ void replaceView(UIElement *ui, bool replaceAllViews = false);
+ void replaceView(const Common::String &name, bool replaceAllViews = false);
+
+ /**
+ * Adds a focused view to the view stack without replacing current one
+ */
+ void addView(UIElement *ui);
+ void addView(const Common::String &name);
+ void addView();
+ void open() {
+ addView();
+ }
+
+ /**
+ * Returns a random number
+ */
+ int getRandomNumber(int minNumber, int maxNumber);
+ int getRandomNumber(int maxNumber);
+
+ /**
+ * Sets the element's bounds
+ */
+ virtual void setBounds(const Common::Rect &r) {
+ _bounds = r;
+ }
+
+ /**
+ * Gets the element's bounds
+ */
+ Common::Rect getBounds() const {
+ return _bounds;
+ }
+
+ /**
+ * Returns a surface for drawing the element
+ */
+ Graphics::ManagedSurface getSurface() const;
+
+ /**
+ * Clear the surface
+ */
+ virtual void clearSurface();
+
+ /**
+ * Draws the element
+ */
+ virtual void draw();
+
+ /**
+ * Called for game frame ticks
+ */
+ virtual bool tick();
+
+ /**
+ * Find a view by name
+ */
+ virtual UIElement *findView(const Common::String &name);
+
+ /**
+ * Handles events
+ */
+ // Mouse move only has a minimal implementation for performance reasons
+protected:
+ virtual bool msgMouseMove(const MouseMoveMessage &msg) {
+ return false;
+ }
+public:
+ bool send(const MouseMoveMessage &msg) {
+ return msgMouseMove(msg);
+ }
+
+#define MESSAGE(NAME) \
+ protected: \
+ virtual bool msg##NAME(const NAME##Message &e) { \
+ for (Common::Array<UIElement *>::iterator it = _children.begin(); \
+ it != _children.end(); ++it) { \
+ if ((*it)->msg##NAME(e)) return true; \
+ } \
+ return false; \
+ } \
+ public: \
+ bool send(const Common::String &viewName, const NAME##Message &msg) { \
+ UIElement *view = UIElement::findViewGlobally(viewName); \
+ assert(view); \
+ return view->msg##NAME(msg); \
+ } \
+ bool send(const NAME##Message &msg) { \
+ return msg##NAME(msg); \
+ } \
+
+ MESSAGE(Focus);
+ MESSAGE(Unfocus);
+ MESSAGE(MouseEnter);
+ MESSAGE(MouseLeave);
+ MESSAGE(Keypress);
+ MESSAGE(MouseDown);
+ MESSAGE(MouseUp);
+ MESSAGE(Action);
+ MESSAGE(Game);
+ MESSAGE(Value);
+#undef MESSAGE
+};
+
+/**
+ * Main events and view manager. This is kept separate from the engine
+ * class because the engine may add a lot of globals and bring in other
+ * classes. So to save on compilation time, classes that only need to
+ * access basic view management methods like addView or replaceView
+ * only need to include events.h rather than the whole engine.
+ */
+class Events : public UIElement {
+private:
+ Graphics::Screen *_screen = nullptr;
+ Common::Stack<UIElement *> _views;
+protected:
+ /**
+ * Process an event
+ */
+ void processEvent(Common::Event &ev);
+
+ /**
+ * Returns true if the game should quit
+ */
+ virtual bool shouldQuit() const = 0;
+
+ /**
+ * Overrides events we want to only go to the focused view
+ */
+#define MESSAGE(NAME) \
+ bool msg##NAME(const NAME##Message &e) override { \
+ return !_views.empty() ? focusedView()->msg##NAME(e) : false; \
+ }
+ MESSAGE(Action);
+ MESSAGE(Focus);
+ MESSAGE(Unfocus);
+ MESSAGE(MouseEnter);
+ MESSAGE(MouseLeave);
+ MESSAGE(Keypress);
+ MESSAGE(MouseDown);
+ MESSAGE(MouseUp);
+ MESSAGE(MouseMove);
+#undef MESSAGE
+public:
+ Events();
+ virtual ~Events();
+
+ /**
+ * Main game loop
+ */
+ void runGame();
+
+ /**
+ * Sets the focus to a new view
+ */
+ void replaceView(UIElement *ui, bool replaceAllViews = false);
+ void replaceView(const Common::String &name, bool replaceAllViews = false);
+
+ /**
+ * Adds a focused view to the view stack without replacing current one
+ */
+ void addView(UIElement *ui);
+ void addView(const Common::String &name);
+
+ /**
+ * Clears the view list
+ */
+ void clearViews();
+
+ /**
+ * Pops a view from the view stack
+ */
+ void popView();
+
+ /**
+ * Redraws the views in order. This is used in rare cases
+ * where a view draws outside it's defined area, and needs
+ * to restore whether the background was before
+ */
+ void redrawViews();
+
+ /**
+ * Returns the currently focused view, if any
+ */
+ UIElement *focusedView() const {
+ return _views.empty() ? nullptr : _views.top();
+ }
+
+ /**
+ * Returns the view prior to the current view, if any
+ */
+ UIElement *priorView() const {
+ return _views.size() < 2 ? nullptr :
+ _views[_views.size() - 2];
+ }
+
+ /**
+ * Returns true if a view of a given name is present
+ * at all in the visible view stack
+ */
+ bool isPresent(const Common::String &name) const;
+
+ /**
+ * Returns true if combat is active
+ */
+ bool isInCombat() const {
+ return isPresent("Combat");
+ }
+
+ /**
+ * Returns the underlying screen
+ */
+ Graphics::Screen *getScreen() const {
+ return _screen;
+ }
+
+ /**
+ * Draws the focused view
+ */
+ void drawElements() {
+ if (!_views.empty())
+ focusedView()->drawElements();
+ }
+
+ /**
+ * Add a keypress to the event queue
+ */
+ void addKeypress(const Common::KeyCode kc);
+
+ /**
+ * Events manager doesn't have any intrinsic drawing
+ */
+ void draw() override {
+ }
+
+ /**
+ * Called once every game frame
+ */
+ bool tick() override {
+ return !_views.empty() ? focusedView()->tick() : false;
+ }
+
+ /**
+ * Calling the close method for g_events closes the active view
+ */
+ void close() override {
+ focusedView()->close();
+ }
+};
+
+extern Events *g_events;
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/messages.cpp b/engines/ultima/ultima0/messages.cpp
new file mode 100644
index 00000000000..bacdbba3728
--- /dev/null
+++ b/engines/ultima/ultima0/messages.cpp
@@ -0,0 +1,45 @@
+/* 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 "ultima/ultima0/messages.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+MouseMessage::MouseMessage(Common::EventType type,
+ const Common::Point &pos) : Message(), _pos(pos) {
+ switch (type) {
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_RBUTTONUP:
+ _button = MB_RIGHT;
+ break;
+ case Common::EVENT_MBUTTONDOWN:
+ case Common::EVENT_MBUTTONUP:
+ _button = MB_MIDDLE;
+ break;
+ default:
+ _button = MB_LEFT;
+ break;
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/messages.h b/engines/ultima/ultima0/messages.h
new file mode 100644
index 00000000000..c33d15420c0
--- /dev/null
+++ b/engines/ultima/ultima0/messages.h
@@ -0,0 +1,133 @@
+/* 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 ULTIMA_ULTIMA0_MESSAGES_H
+#define ULTIMA_ULTIMA0_MESSAGES_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/str.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+class UIElement;
+
+struct Message {};
+
+struct FocusMessage : public Message {
+ UIElement *_priorView = nullptr;
+ FocusMessage() : Message() {
+ }
+ FocusMessage(UIElement *priorView) : Message(),
+ _priorView(priorView) {
+ }
+};
+
+struct UnfocusMessage : public Message {};
+struct MouseEnterMessage : public Message {};
+struct MouseLeaveMessage : public Message {};
+
+struct KeypressMessage : public Message, public Common::KeyState {
+ KeypressMessage() : Message() {
+ }
+ KeypressMessage(const Common::KeyState &ks) :
+ Message(), Common::KeyState(ks) {
+ }
+};
+
+struct MouseMessage : public Message {
+ enum Button {
+ MB_LEFT, MB_RIGHT, MB_MIDDLE
+ };
+ Button _button;
+ Common::Point _pos;
+
+ MouseMessage() : Message(), _button(MB_LEFT) {
+ }
+ MouseMessage(Button btn, const Common::Point &pos) :
+ Message(), _button(btn), _pos(pos) {
+ }
+ MouseMessage(Common::EventType type, const Common::Point &pos);
+};
+struct MouseDownMessage : public MouseMessage {
+ MouseDownMessage() : MouseMessage() {
+ }
+ MouseDownMessage(Button btn, const Common::Point &pos) :
+ MouseMessage(btn, pos) {
+ }
+ MouseDownMessage(Common::EventType type, const Common::Point &pos) :
+ MouseMessage(type, pos) {
+ }
+};
+struct MouseUpMessage : public MouseMessage {
+ MouseUpMessage() : MouseMessage() {
+ }
+ MouseUpMessage(Button btn, const Common::Point &pos) :
+ MouseMessage(btn, pos) {
+ }
+ MouseUpMessage(Common::EventType type, const Common::Point &pos) :
+ MouseMessage(type, pos) {
+ }
+};
+typedef MouseMessage MouseMoveMessage;
+
+struct GameMessage : public Message {
+ Common::String _name;
+ int _value;
+ Common::String _stringValue;
+
+ GameMessage() : Message(), _value(-1) {
+ }
+ GameMessage(const Common::String &name) : Message(),
+ _name(name), _value(-1) {
+ }
+ GameMessage(const Common::String &name, int value) : Message(),
+ _name(name), _value(value) {
+ }
+ GameMessage(const Common::String &name, const Common::String &value) :
+ Message(), _name(name), _stringValue(value) {
+ }
+};
+
+struct ValueMessage : public Message {
+ int _value;
+
+ ValueMessage() : Message(), _value(0) {
+ }
+ ValueMessage(int value) : Message(),
+ _value(value) {
+ }
+};
+
+struct ActionMessage : public Message {
+ int _action;
+ ActionMessage() : Message(), _action(0) {
+ }
+ ActionMessage(int action) : Message(),
+ _action(action) {
+ }
+};
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index ddb6a2e3f66..5da2c577288 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -40,14 +40,18 @@ Ultima0Engine::~Ultima0Engine() {
Common::Error Ultima0Engine::run() {
initGraphics(DEFAULT_SCX, DEFAULT_SCY);
+
+ runGame();
+
+#if 0
Display = new Graphics::Screen();
GameSpeed = 120;
// Call the real main program
- MAINStart();
+// MAINStart();
delete Display;
-
+#endif
return Common::kNoError;
}
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 10b69e8e5e4..0372ece42e9 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -26,11 +26,12 @@
#include "engines/engine.h"
#include "ultima/detection.h"
#include "ultima/ultima0/defines.h"
+#include "ultima/ultima0/events.h"
namespace Ultima {
namespace Ultima0 {
-class Ultima0Engine : public Engine {
+class Ultima0Engine : public Engine, public Events {
private:
Common::RandomSource _randomSource;
@@ -44,6 +45,13 @@ public:
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
+ /**
+ * Returns true if the game should quit
+ */
+ bool shouldQuit() const override {
+ return Engine::shouldQuit();
+ }
+
/**
* Returns supported engine features
*/
diff --git a/engines/ultima/ultima0/views/startup.cpp b/engines/ultima/ultima0/views/startup.cpp
new file mode 100644
index 00000000000..1e14ed0a907
--- /dev/null
+++ b/engines/ultima/ultima0/views/startup.cpp
@@ -0,0 +1,68 @@
+/* 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 "graphics/paletteman.h"
+#include "ultima/ultima0/views/startup.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+bool Startup::msgFocus(const FocusMessage &msg) {
+ Common::fill(&_pal[0], &_pal[256 * 3], 0);
+ _offset = 128;
+ return true;
+}
+
+bool Startup::msgKeypress(const KeypressMessage &msg) {
+ // Any keypress to close the view
+ close();
+ return true;
+}
+
+void Startup::draw() {
+ // Draw a bunch of squares on screen
+ Graphics::ManagedSurface s = getSurface();
+
+ for (int i = 0; i < 100; ++i)
+ s.frameRect(Common::Rect(i, i, 320 - i, 200 - i), i);
+}
+
+bool Startup::tick() {
+ // Cycle the palette
+ ++_offset;
+ for (int i = 0; i < 256; ++i)
+ _pal[i * 3 + 1] = (i + _offset) % 256;
+ g_system->getPaletteManager()->setPalette(_pal, 0, 256);
+
+ // Below is redundant since we're only cycling the palette, but it demonstrates
+ // how to trigger the view to do further draws after the first time, since views
+ // don't automatically keep redrawing unless you tell it to
+ if ((_offset % 256) == 0)
+ redraw();
+
+ return true;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/startup.h b/engines/ultima/ultima0/views/startup.h
new file mode 100644
index 00000000000..8d334cc9cfc
--- /dev/null
+++ b/engines/ultima/ultima0/views/startup.h
@@ -0,0 +1,52 @@
+/* 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 ULTIMA_ULTIMA0_VIEWS_STARTUP_H
+#define ULTIMA_ULTIMA0_VIEWS_STARTUP_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Startup : public View {
+private:
+ byte _pal[256 * 3] = { 0 };
+ int _offset = 0;
+
+public:
+ Startup() : View("Startup") {
+ }
+ virtual ~Startup() {
+ }
+
+ bool msgFocus(const FocusMessage &msg) override;
+ bool msgKeypress(const KeypressMessage &msg) override;
+ void draw() override;
+ bool tick() override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/view.cpp b/engines/ultima/ultima0/views/view.cpp
new file mode 100644
index 00000000000..8ea3789f6d1
--- /dev/null
+++ b/engines/ultima/ultima0/views/view.cpp
@@ -0,0 +1,85 @@
+/* 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 "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+void View::checkFocusedControl(const Common::Point &mousePos) {
+ if (_focusedElement) {
+ if (!_focusedElement->getBounds().contains(mousePos)) {
+ _focusedElement->send(MouseLeaveMessage());
+ _focusedElement = nullptr;
+ }
+
+ } else {
+ for (UIElement *child : _children) {
+ if (child->getBounds().contains(mousePos)) {
+ _focusedElement = child;
+ child->send(MouseEnterMessage());
+ break;
+ }
+ }
+ }
+}
+
+UIElement *View::getElementAtPos(const Common::Point &pos) const {
+ for (UIElement *child : _children) {
+ if (child->getBounds().contains(pos))
+ return child;
+ }
+
+ return nullptr;
+}
+
+
+bool View::msgFocus(const FocusMessage &msg) {
+ _focusedElement = nullptr;
+ return UIElement::msgFocus(msg);
+}
+
+bool View::msgUnfocus(const UnfocusMessage &msg) {
+ if (_focusedElement)
+ _focusedElement->send(MouseLeaveMessage());
+
+ return UIElement::msgUnfocus(msg);
+}
+
+bool View::msgMouseMove(const MouseMoveMessage &msg) {
+ checkFocusedControl(msg._pos);
+ return true;
+}
+
+bool View::msgMouseDown(const MouseDownMessage &msg) {
+ UIElement *child = getElementAtPos(msg._pos);
+ return child ? child->send(msg) : false;
+}
+
+bool View::msgMouseUp(const MouseUpMessage &msg) {
+ UIElement *child = getElementAtPos(msg._pos);
+ return child ? child->send(msg) : false;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/view.h b/engines/ultima/ultima0/views/view.h
new file mode 100644
index 00000000000..a57dd6b65f9
--- /dev/null
+++ b/engines/ultima/ultima0/views/view.h
@@ -0,0 +1,77 @@
+/* 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 ULTIMA_ULTIMA0_VIEWS_VIEW_H
+#define ULTIMA_ULTIMA0_VIEWS_VIEW_H
+
+#include "ultima/ultima0/events.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+/**
+ * Base view class for screens and dialogs that appear on-screen.
+ * The View class takes care of two important things:
+ * 1) By default events get sent to all controls on a view until one
+ * handles it. For mouse events, we instead want only the control the
+ * mouse cursor is over to receive the events, saving the individual
+ * controls from having to check if the mouse is within their bounds.
+ * 2) Individual elements will get a Focus/Unfocus message as the
+ * mouse enters and leaves them. This allows, for example, buttons
+ * that have been pressed to de-select if the mouse leaves their bounds.
+ */
+class View : public UIElement {
+private:
+ UIElement *_focusedElement = nullptr;
+
+ /**
+ * Checks if a control is entered or left
+ */
+ void checkFocusedControl(const Common::Point &mousePos);
+
+ /**
+ * Check for an element at the given position
+ */
+ UIElement *getElementAtPos(const Common::Point &pos) const;
+
+public:
+ View(const Common::String &name, UIElement *uiParent) :
+ UIElement(name, uiParent) {
+ }
+ View(const Common::String &name) :
+ UIElement(name) {
+ }
+ virtual ~View() {
+ }
+
+ bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
+ bool msgMouseMove(const MouseMoveMessage &msg) override;
+ bool msgMouseDown(const MouseDownMessage &msg) override;
+ bool msgMouseUp(const MouseUpMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
new file mode 100644
index 00000000000..7ae511c1b22
--- /dev/null
+++ b/engines/ultima/ultima0/views/views.h
@@ -0,0 +1,39 @@
+/* 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 ULTIMA_ULTIMA0_VIEWS_H
+#define ULTIMA_ULTIMA0_VIEWS_H
+
+#include "ultima/ultima0/views/startup.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+struct Views {
+ Startup _startup;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
Commit: eb132e9f7230b5a57b3544c067cd6c3378e1d867
https://github.com/scummvm/scummvm/commit/eb132e9f7230b5a57b3544c067cd6c3378e1d867
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:23+11:00
Commit Message:
ULTIMA: ULTIMA0: Added GfxSurface and Font classes
Changed paths:
A engines/ultima/ultima0/gfx/font.cpp
A engines/ultima/ultima0/gfx/font.h
A engines/ultima/ultima0/gfx/gfx_surface.cpp
A engines/ultima/ultima0/gfx/gfx_surface.h
engines/ultima/module.mk
engines/ultima/ultima0/akalabeth.h
engines/ultima/ultima0/defines.h
engines/ultima/ultima0/events.cpp
engines/ultima/ultima0/events.h
engines/ultima/ultima0/messages.h
engines/ultima/ultima0/sdw.h
engines/ultima/ultima0/struct.h
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/startup.cpp
engines/ultima/ultima0/views/startup.h
engines/ultima/ultima0/views/view.h
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index d906094056e..c8412ab5296 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -29,6 +29,8 @@ MODULE_OBJS += \
ultima0/sdw.o \
ultima0/town.o \
ultima0/world.o \
+ ultima0/gfx/font.o \
+ ultima0/gfx/gfx_surface.o \
ultima0/views/view.o \
ultima0/views/startup.o
endif
diff --git a/engines/ultima/ultima0/akalabeth.h b/engines/ultima/ultima0/akalabeth.h
index c725eacdf4e..1414a2628ae 100644
--- a/engines/ultima/ultima0/akalabeth.h
+++ b/engines/ultima/ultima0/akalabeth.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_AKALABETH_H
-#define ULTIMA_ULTIMA0_AKALABETH_H
+#ifndef ULTIMA0_AKALABETH_H
+#define ULTIMA0_AKALABETH_H
#include "common/str.h"
#include "ultima/ultima0/struct.h" /* Our structure file */
diff --git a/engines/ultima/ultima0/defines.h b/engines/ultima/ultima0/defines.h
index c1de0781715..5b9c168d92b 100644
--- a/engines/ultima/ultima0/defines.h
+++ b/engines/ultima/ultima0/defines.h
@@ -19,14 +19,17 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_DEFINES_H
-#define ULTIMA_ULTIMA0_DEFINES_H
+#ifndef ULTIMA0_DEFINES_H
+#define ULTIMA0_DEFINES_H
#include "common/scummsys.h"
namespace Ultima {
namespace Ultima0 {
+constexpr int DEFAULT_SCX = 1024; // Default Screen Size and Depth
+constexpr int DEFAULT_SCY = 768;
+
#define RND_MAX 0x7fffffff
#define RND() (((double)g_engine->getRandomNumber())/RND_MAX)
#define urand() g_engine->getRandomNumber()
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
index 989e3dc7419..602cbc01367 100644
--- a/engines/ultima/ultima0/events.cpp
+++ b/engines/ultima/ultima0/events.cpp
@@ -23,6 +23,7 @@
#include "common/config-manager.h"
#include "graphics/screen.h"
#include "ultima/ultima0/events.h"
+#include "ultima/ultima0/gfx/gfx_surface.h"
#include "ultima/ultima0/views/views.h"
#include "ultima/ultima0/ultima0.h"
@@ -319,8 +320,8 @@ void UIElement::addView() {
g_events->addView(this);
}
-Graphics::ManagedSurface UIElement::getSurface() const {
- return Graphics::ManagedSurface(*g_events->getScreen(), _bounds);
+Gfx::GfxSurface UIElement::getSurface() const {
+ return Gfx::GfxSurface(*g_events->getScreen(), _bounds);
}
int UIElement::getRandomNumber(int minNumber, int maxNumber) {
diff --git a/engines/ultima/ultima0/events.h b/engines/ultima/ultima0/events.h
index c1b5aca99aa..ec020f8377d 100644
--- a/engines/ultima/ultima0/events.h
+++ b/engines/ultima/ultima0/events.h
@@ -19,13 +19,14 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_EVENTS_H
-#define ULTIMA_ULTIMA0_EVENTS_H
+#ifndef ULTIMA0_EVENTS_H
+#define ULTIMA0_EVENTS_H
#include "common/array.h"
#include "common/stack.h"
#include "graphics/screen.h"
#include "ultima/ultima0/messages.h"
+#include "ultima/ultima0/gfx/gfx_surface.h"
namespace Ultima {
namespace Ultima0 {
@@ -196,7 +197,7 @@ public:
/**
* Returns a surface for drawing the element
*/
- Graphics::ManagedSurface getSurface() const;
+ Gfx::GfxSurface getSurface() const;
/**
* Clear the surface
diff --git a/engines/ultima/ultima0/gfx/font.cpp b/engines/ultima/ultima0/gfx/font.cpp
new file mode 100644
index 00000000000..eb90c5a9690
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/font.cpp
@@ -0,0 +1,224 @@
+/* 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 "ultima/ultima0/gfx/font.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+static const byte FONT1[2048] = {
+ 124,130,186,162,186,130,124,0,126,129,165,129,165,153,129,126,
+ 126,129,165,129,153,165,129,126,108,246,246,254,124,56,16,0,
+ 16,56,124,254,124,56,16,0,16,56,84,254,84,16,56,0,
+ 56,124,254,254,108,16,56,0,16,24,20,20,48,112,96,0,
+ 254,254,254,238,254,254,254,0,236,138,138,170,170,170,236,0,
+ 142,136,136,140,136,136,232,0,174,170,170,234,170,170,174,0,
+ 238,136,136,204,136,136,136,0,238,138,138,142,140,138,234,0,
+ 62,34,62,34,102,238,204,0,16,84,40,198,40,84,16,0,
+ 240,248,252,254,252,248,240,0,30,62,126,254,126,62,30,0,
+ 16,56,124,16,124,56,16,0,238,238,238,238,238,0,238,0,
+ 254,68,68,68,68,68,68,0,126,128,188,198,122,2,252,0,
+ 0,0,0,0,255,255,0,0,16,56,124,16,124,56,16,254,
+ 16,56,124,254,56,56,56,0,56,56,56,254,124,56,16,0,
+ 16,24,252,254,252,24,16,0,16,48,126,254,126,48,16,0,
+
+ 144,72,36,18,36,72,144,0,18,36,72,144,72,36,18,0,
+ 16,40,68,146,40,68,130,0,130,68,40,146,68,40,16,0,
+ 0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,0,
+
+ 40,40,40,0,0,0,0,0,68,254,68,68,68,254,68,0,
+ 16,126,144,124,18,252,16,0,66,164,72,16,36,74,132,0,
+ 56,68,56,112,138,132,122,0,16,16,32,0,0,0,0,0,
+ 8,16,16,16,16,16,8,0,32,16,16,16,16,16,32,0,
+ 16,84,56,254,56,84,16,0,16,16,16,254,16,16,16,0,
+ 0,0,0,0,0,16,16,32,0,0,0,254,0,0,0,0,
+ 0,0,0,0,0,0,16,0,2,4,8,16,32,64,128,0,
+ 124,130,130,130,130,130,124,0,240,16,16,16,16,16,254,0,
+ 252,2,2,124,128,128,254,0,252,2,2,28,2,2,252,0,
+ 130,130,130,126,2,2,2,0,254,128,252,2,2,2,252,0,
+ 126,128,252,130,130,130,124,0,252,2,2,2,2,2,2,0,
+ 124,130,130,124,130,130,124,0,126,130,130,126,2,2,252,0,
+ 0,0,0,16,0,0,16,0,0,0,0,16,0,0,16,32,
+ 8,16,32,64,32,16,8,0,0,0,0,254,0,254,0,0,
+ 64,32,16,8,16,32,64,0,56,68,4,8,16,0,16,0,
+ 60,66,154,170,156,64,62,0,124,130,130,254,130,130,130,0,
+ 252,130,130,252,130,130,252,0,124,130,128,128,128,130,124,0,
+ 252,130,130,130,130,130,252,0,254,128,128,240,128,128,254,0,
+ 254,128,128,240,128,128,128,0,124,130,128,142,130,130,124,0,
+ 130,130,130,254,130,130,130,0,254,16,16,16,16,16,254,0,
+ 62,2,2,2,130,130,124,0,130,132,136,240,136,132,130,0,
+ 128,128,128,128,128,128,254,0,252,146,146,146,146,146,146,0,
+ 130,194,162,146,138,134,130,0,124,130,130,130,130,130,124,0,
+ 252,130,130,252,128,128,128,0,124,130,130,130,138,134,126,0,
+ 252,130,130,252,130,130,130,0,126,128,128,124,2,2,252,0,
+ 254,16,16,16,16,16,16,0,130,130,130,130,130,130,124,0,
+ 130,130,68,68,40,40,16,0,130,130,130,146,146,146,108,0,
+ 130,68,40,16,40,68,130,0,130,130,130,126,2,2,252,0,
+ 254,4,8,16,32,64,254,0,56,32,32,32,32,32,56,0,
+ 128,64,32,16,8,4,2,0,56,8,8,8,8,8,56,0,
+ 16,40,68,130,0,0,0,0,0,0,0,0,0,0,0,255,
+ 32,32,16,0,0,0,0,0,0,0,56,68,124,68,68,0,
+ 0,0,120,68,120,68,120,0,0,0,60,64,64,64,60,0,
+ 0,0,120,68,68,68,120,0,0,0,124,64,112,64,124,0,
+ 0,0,124,64,112,64,64,0,0,0,60,64,76,68,60,0,
+ 0,0,68,68,124,68,68,0,0,0,124,16,16,16,124,0,
+ 0,0,28,4,4,68,56,0,0,0,68,72,112,72,68,0,
+ 0,0,64,64,64,64,124,0,0,0,120,84,84,84,84,0,
+ 0,0,120,68,68,68,68,0,0,0,56,68,68,68,56,0,
+ 0,0,120,68,120,64,64,0,0,0,56,68,68,76,54,0,
+ 0,0,120,68,120,68,68,0,0,0,60,64,56,4,120,0,
+ 0,0,124,16,16,16,16,0,0,0,68,68,68,68,56,0,
+ 0,0,68,68,40,40,16,0,0,0,68,68,84,108,68,0,
+ 0,0,68,40,16,40,68,0,0,0,68,68,60,4,120,0,
+ 0,0,124,8,16,32,124,0,8,16,16,32,16,16,8,0,
+ 16,16,16,0,16,16,16,0,32,16,16,8,16,16,32,0,
+ 80,40,0,0,0,0,0,0,0,16,40,68,130,130,254,0,
+ 254,254,254,254,254,254,254,0,0,0,0,0,0,254,254,0,
+ 0,0,124,124,124,124,124,0,0,0,0,0,0,0,124,0,
+ 128,128,128,128,128,128,128,0,0,64,64,64,64,64,64,0,
+ 16,24,28,30,28,24,16,0,16,48,112,240,112,48,16,0,
+ 62,30,30,62,114,224,64,0,4,14,156,248,240,240,248,0,
+ 64,224,114,62,30,30,62,0,248,240,240,248,156,14,4,0,
+ 56,68,130,130,130,68,56,0,56,124,254,254,254,124,56,0,
+ 0,124,68,68,68,124,0,0,0,124,124,124,124,124,0,0,
+ 0,60,110,126,112,126,60,0,0,60,118,126,14,126,60,0,
+ 0,60,126,106,126,126,106,0,0,60,126,86,126,126,86,0,
+ 0,0,0,24,24,0,0,0,0,0,24,60,60,24,0,0,
+
+ 0,12,52,36,36,108,72,0,0,0,0,0,0,0,0,0,
+ 60,126,198,231,255,224,126,60,60,126,227,231,255,7,126,60,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,52,118,118,94,126,60,0,0,60,110,126,112,126,60,0,
+ 0,60,126,122,110,110,44,0,0,60,126,14,126,118,60,0,
+ 0,0,0,0,0,0,0,0,126,126,126,126,60,0,0,0,
+ 0,15,31,31,31,31,15,0,126,127,127,127,127,127,63,0,
+ 0,0,0,60,126,126,126,126,126,126,126,126,126,126,126,126,
+ 0,63,127,127,127,127,127,126,126,127,127,127,127,127,127,126,
+
+ 0,240,248,248,248,248,240,0,126,254,254,254,254,254,252,0,
+ 0,255,255,255,255,255,255,0,126,255,255,255,255,255,255,0,
+ 0,252,254,254,254,254,254,126,126,254,254,254,254,254,254,126,
+ 0,255,255,255,255,255,255,126,126,255,255,255,255,255,255,126,
+ 0,0,63,63,48,55,52,52,0,0,255,255,0,255,0,0,
+ 0,0,248,248,24,216,88,88,88,88,88,88,88,88,88,88,
+ 88,216,24,248,248,0,0,0,0,255,0,255,255,0,0,0,
+ 52,55,48,63,63,0,0,0,52,52,52,52,52,52,52,52,
+ 0,0,0,31,24,24,24,24,0,0,0,255,0,0,0,0,
+ 0,0,0,240,48,48,48,48,48,48,48,48,48,48,48,48,
+ 48,48,48,240,0,0,0,0,0,0,0,255,0,0,0,0,
+ 24,24,24,31,0,0,0,0,24,24,24,24,24,24,24,24,
+ 136,34,136,34,136,34,136,34,85,170,85,170,85,170,85,170,
+ 68,170,68,170,68,170,68,170,51,102,204,153,51,102,204,153,
+ 204,102,51,153,204,102,51,153,199,143,31,62,124,248,241,227,
+ 227,241,248,124,62,31,143,199,174,128,186,2,234,8,171,32,
+ 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,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,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,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,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,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,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,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,
+ 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,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,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,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,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,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,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,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,
+ 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,0,0,0,0,0,0,
+};
+
+
+void Font::writeChar(Graphics::ManagedSurface *dst, uint32 chr,
+ const Common::Point &textPos, byte textColor) {
+ if (chr == ' ')
+ return; // Don't do anything for spaces
+
+ const byte *GfxData = FONT1 + chr * 8;
+ Graphics::Surface charArea = dst->getSubArea(Common::Rect(textPos.x, textPos.y,
+ textPos.x + CHAR_WIDTH, textPos.y + CHAR_HEIGHT));
+ const int w = 1;
+ const int h = 1;
+
+ // Work through the 64 pixel array
+ for (int x = 0; x < 8; ++x) {
+ for (int y = 0; y < 8; ++y) {
+ // Check for whether character has pixel in this position
+ if (_FONTPixelSet(GfxData, x, y)) {
+ Common::Rect rc2(x * 2, y * 2, x * 2 + 2, y * 2 + 2);
+ charArea.fillRect(rc2, textColor);
+
+ // Neaten the diagonals
+ if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
+ _FONTPixelSet(GfxData, x - 1, y) == 0 &&
+ _FONTPixelSet(GfxData, x - 1, y + 1) != 0)
+ _FONTAngleDraw(&charArea, &rc2, -w, h, textColor);
+
+ if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
+ _FONTPixelSet(GfxData, x + 1, y) == 0 &&
+ _FONTPixelSet(GfxData, x + 1, y + 1) != 0)
+ _FONTAngleDraw(&charArea, &rc2, w, h, textColor);
+ }
+ }
+ }
+}
+
+bool Font::_FONTPixelSet(const byte * Data, int x, int y) {
+ if (x < 0 || y < 0 || x > 7 || y > 7)
+ return false;
+ return (Data[y] & (0x80 >> x)) ? 1 : 0;
+}
+
+void Font::_FONTAngleDraw(Graphics::Surface *s, Common::Rect *rc, int w, int h, byte colour) {
+ int i, m;
+ Common::Rect rc3;
+
+ m = ABS(w);
+ if (ABS(h) > m)
+ m = ABS(h);
+
+ for (i = 0; i < m; i++) {
+ rc3.left = rc->left + w * i / m;
+ rc3.top = rc->top + h * i / m;
+ rc3.setWidth(rc->width());
+ rc3.setHeight(rc->height());
+ s->fillRect(rc3, colour);
+ }
+}
+
+} // namespace Gfx
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/font.h b/engines/ultima/ultima0/gfx/font.h
new file mode 100644
index 00000000000..1fbffdcf67d
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/font.h
@@ -0,0 +1,62 @@
+/* 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 ULTIMA0_GFX_FONT_H
+#define ULTIMA0_GFX_FONT_H
+
+#include "graphics/managed_surface.h"
+#include "ultima/ultima0/defines.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+constexpr int CHAR_HEIGHT = 16;
+constexpr int CHAR_WIDTH = 16;
+constexpr int TEXT_WIDTH = DEFAULT_SCX / CHAR_WIDTH;
+constexpr int TEXT_HEIGHT = DEFAULT_SCY / CHAR_HEIGHT;
+
+class Font {
+private:
+ /**
+ * Returns true if a pixel is set in the source font data
+ */
+ static bool _FONTPixelSet(const byte *Data, int x, int y);
+
+ /**
+ * Draw an angled line - this stops the squared corners on diagonals showing
+ */
+ static void _FONTAngleDraw(Graphics::Surface *s, Common::Rect *rc,
+ int w, int h, byte colour);
+
+public:
+ /**
+ * Draws a character onto the passed surface
+ */
+ static void writeChar(Graphics::ManagedSurface *dst, uint32 chr,
+ const Common::Point &textPos, byte textColor);
+};
+
+} // namespace Gfx
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.cpp b/engines/ultima/ultima0/gfx/gfx_surface.cpp
new file mode 100644
index 00000000000..3b59fa9aade
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/gfx_surface.cpp
@@ -0,0 +1,75 @@
+/* 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 "ultima/ultima0/gfx/gfx_surface.h"
+#include "ultima/ultima0/gfx/font.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+
+void GfxSurface::init() {
+ _textColor = g_engine->_palette.findBestColor(0, 255, 0);
+}
+
+void GfxSurface::writeString(const char *fmt, ...) {
+ va_list alist;
+ va_start(alist, fmt);
+ Common::String str = Common::String::vformat(fmt, alist);
+ va_end(alist);
+
+ for (const char *p = str.c_str(); *p; ++p) {
+ if (*p == '\n') {
+ _textPos.x = 0;
+ _textPos.y++;
+ } else {
+ writeChar(*p);
+ }
+ }
+}
+
+void GfxSurface::writeChar(uint32 chr) {
+ if (chr >= ' ') {
+ Font::writeChar(this, chr, Common::Point(_textPos.x * CHAR_WIDTH,
+ _textPos.y * CHAR_HEIGHT), _textColor);
+ ++_textPos.x;
+ }
+
+ if (_textPos.x >= TEXT_WIDTH || chr == '\n') {
+ _textPos.x = 0;
+ _textPos.y++;
+ }
+
+ if (_textPos.y >= TEXT_HEIGHT) {
+ _textPos.y = TEXT_HEIGHT - 1;
+
+ // Scroll the screen contents up
+ blitFrom(*this, Common::Rect(0, CHAR_HEIGHT, DEFAULT_SCX, DEFAULT_SCY),
+ Common::Point(0, 0));
+ fillRect(Common::Rect(0, DEFAULT_SCX - CHAR_HEIGHT, DEFAULT_SCX, DEFAULT_SCY), 0);
+ }
+}
+
+} // namespace Gfx
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.h b/engines/ultima/ultima0/gfx/gfx_surface.h
new file mode 100644
index 00000000000..3b89737717c
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/gfx_surface.h
@@ -0,0 +1,57 @@
+/* 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 ULTIMA0_GFX_SURFACE_H
+#define ULTIMA0_GFX_SURFACE_H
+
+#include "graphics/managed_surface.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+class GfxSurface : public Graphics::ManagedSurface {
+private:
+ Common::Point _textPos;
+ byte _textColor;
+
+ void init();
+
+public:
+ GfxSurface() : Graphics::ManagedSurface() {
+ init();
+ }
+ GfxSurface(Graphics::ManagedSurface &surf, const Common::Rect &bounds) : Graphics::ManagedSurface(surf, bounds) {
+ init();
+ }
+
+ /**
+ * Write some text to the surface
+ */
+ void writeString(const char *format, ...);
+ void writeChar(uint32 chr);
+};
+
+} // namespace Gfx
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/messages.h b/engines/ultima/ultima0/messages.h
index c33d15420c0..58ad20310f2 100644
--- a/engines/ultima/ultima0/messages.h
+++ b/engines/ultima/ultima0/messages.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_MESSAGES_H
-#define ULTIMA_ULTIMA0_MESSAGES_H
+#ifndef ULTIMA0_MESSAGES_H
+#define ULTIMA0_MESSAGES_H
#include "common/array.h"
#include "common/events.h"
diff --git a/engines/ultima/ultima0/sdw.h b/engines/ultima/ultima0/sdw.h
index 35de7bc2b6f..d019d313bae 100644
--- a/engines/ultima/ultima0/sdw.h
+++ b/engines/ultima/ultima0/sdw.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_SDW_H
-#define ULTIMA_ULTIMA0_SDW_H
+#ifndef ULTIMA0_SDW_H
+#define ULTIMA0_SDW_H
#include "audio/mixer.h"
#include "audio/audiostream.h"
@@ -36,8 +36,6 @@ extern int GameSpeed; // Scales the system clock.
// It's all nicely in a namespace SDLWrapper
namespace SDLWrapper {
-#define DEFAULT_SCX (1024) // Default Screen Size and Depth
-#define DEFAULT_SCY (768)
#define DEFAULT_SCBPP (0)
#define MAXSOUND (16) // Maximum number of sounds
diff --git a/engines/ultima/ultima0/struct.h b/engines/ultima/ultima0/struct.h
index 088964ac129..693284b9558 100644
--- a/engines/ultima/ultima0/struct.h
+++ b/engines/ultima/ultima0/struct.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_STRUCT_H
-#define ULTIMA_ULTIMA0_STRUCT_H
+#ifndef ULTIMA0_STRUCT_H
+#define ULTIMA0_STRUCT_H
#include "ultima/ultima0/defines.h"
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 5da2c577288..2cd2cfb0c7c 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -20,6 +20,7 @@
*/
#include "engines/util.h"
+#include "graphics/paletteman.h"
#include "ultima/ultima0/sdw.h"
#include "ultima/ultima0/ultima0.h"
#include "ultima/ultima0/akalabeth.h"
@@ -28,10 +29,22 @@
namespace Ultima {
namespace Ultima0 {
+static const byte PALETTE[8][3] = {
+ { 0, 0, 0 },
+ { 255, 0, 255 },
+ { 255, 0, 0 },
+ { 0, 255, 0 },
+ { 0, 0, 255 },
+ { 255, 255, 0 },
+ { 0, 255, 255 },
+ { 220, 20, 130 }
+};
+
Ultima0Engine *g_engine;
Ultima0Engine::Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc) :
- Engine(syst), _gameDescription(gameDesc), _randomSource("Ultima0") {
+ Engine(syst), _gameDescription(gameDesc), _randomSource("Ultima0"),
+ _palette(&PALETTE[0][0], 8) {
g_engine = this;
}
@@ -40,6 +53,7 @@ Ultima0Engine::~Ultima0Engine() {
Common::Error Ultima0Engine::run() {
initGraphics(DEFAULT_SCX, DEFAULT_SCY);
+ g_system->getPaletteManager()->setPalette(_palette);
runGame();
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 0372ece42e9..c748731e956 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -19,10 +19,11 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_H
-#define ULTIMA_ULTIMA0_H
+#ifndef ULTIMA0_H
+#define ULTIMA0_H
#include "common/random.h"
+#include "graphics/palette.h"
#include "engines/engine.h"
#include "ultima/detection.h"
#include "ultima/ultima0/defines.h"
@@ -42,6 +43,8 @@ protected:
Common::Error run() override;
public:
+ Graphics::Palette _palette;
+
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
diff --git a/engines/ultima/ultima0/views/startup.cpp b/engines/ultima/ultima0/views/startup.cpp
index 1e14ed0a907..9a11bf5816a 100644
--- a/engines/ultima/ultima0/views/startup.cpp
+++ b/engines/ultima/ultima0/views/startup.cpp
@@ -27,12 +27,6 @@ namespace Ultima {
namespace Ultima0 {
namespace Views {
-bool Startup::msgFocus(const FocusMessage &msg) {
- Common::fill(&_pal[0], &_pal[256 * 3], 0);
- _offset = 128;
- return true;
-}
-
bool Startup::msgKeypress(const KeypressMessage &msg) {
// Any keypress to close the view
close();
@@ -40,27 +34,9 @@ bool Startup::msgKeypress(const KeypressMessage &msg) {
}
void Startup::draw() {
- // Draw a bunch of squares on screen
- Graphics::ManagedSurface s = getSurface();
-
- for (int i = 0; i < 100; ++i)
- s.frameRect(Common::Rect(i, i, 320 - i, 200 - i), i);
-}
-
-bool Startup::tick() {
- // Cycle the palette
- ++_offset;
- for (int i = 0; i < 256; ++i)
- _pal[i * 3 + 1] = (i + _offset) % 256;
- g_system->getPaletteManager()->setPalette(_pal, 0, 256);
+ auto s = getSurface();
+ s.writeString("Hello");
- // Below is redundant since we're only cycling the palette, but it demonstrates
- // how to trigger the view to do further draws after the first time, since views
- // don't automatically keep redrawing unless you tell it to
- if ((_offset % 256) == 0)
- redraw();
-
- return true;
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/startup.h b/engines/ultima/ultima0/views/startup.h
index 8d334cc9cfc..b530c509967 100644
--- a/engines/ultima/ultima0/views/startup.h
+++ b/engines/ultima/ultima0/views/startup.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_VIEWS_STARTUP_H
-#define ULTIMA_ULTIMA0_VIEWS_STARTUP_H
+#ifndef ULTIMA0_VIEWS_STARTUP_H
+#define ULTIMA0_VIEWS_STARTUP_H
#include "ultima/ultima0/views/view.h"
@@ -29,20 +29,12 @@ namespace Ultima0 {
namespace Views {
class Startup : public View {
-private:
- byte _pal[256 * 3] = { 0 };
- int _offset = 0;
-
public:
- Startup() : View("Startup") {
- }
- virtual ~Startup() {
- }
+ Startup() : View("Startup") {}
+ ~Startup() override {}
- bool msgFocus(const FocusMessage &msg) override;
bool msgKeypress(const KeypressMessage &msg) override;
void draw() override;
- bool tick() override;
};
} // namespace Views
diff --git a/engines/ultima/ultima0/views/view.h b/engines/ultima/ultima0/views/view.h
index a57dd6b65f9..7bd607456d2 100644
--- a/engines/ultima/ultima0/views/view.h
+++ b/engines/ultima/ultima0/views/view.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_VIEWS_VIEW_H
-#define ULTIMA_ULTIMA0_VIEWS_VIEW_H
+#ifndef ULTIMA0_VIEWS_VIEW_H
+#define ULTIMA0_VIEWS_VIEW_H
#include "ultima/ultima0/events.h"
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 7ae511c1b22..ccc675e03b9 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA_ULTIMA0_VIEWS_H
-#define ULTIMA_ULTIMA0_VIEWS_H
+#ifndef ULTIMA0_VIEWS_H
+#define ULTIMA0_VIEWS_H
#include "ultima/ultima0/views/startup.h"
Commit: 4137c59b52af096b4ab6a93cbe38ec56d3023d25
https://github.com/scummvm/scummvm/commit/4137c59b52af096b4ab6a93cbe38ec56d3023d25
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:23+11:00
Commit Message:
ULTIMA: ULTIMA0: Data cleanup, startup screen text
Changed paths:
A engines/ultima/ultima0/data/data.cpp
A engines/ultima/ultima0/data/data.h
A engines/ultima/ultima0/data/defines.h
R engines/ultima/ultima0/defines.h
engines/ultima/module.mk
engines/ultima/ultima0/events.cpp
engines/ultima/ultima0/gfx/font.h
engines/ultima/ultima0/gfx/gfx_surface.cpp
engines/ultima/ultima0/gfx/gfx_surface.h
engines/ultima/ultima0/struct.h
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/startup.cpp
engines/ultima/ultima0/views/startup.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index c8412ab5296..456da9a7a82 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -29,6 +29,7 @@ MODULE_OBJS += \
ultima0/sdw.o \
ultima0/town.o \
ultima0/world.o \
+ ultima0/data/data.o \
ultima0/gfx/font.o \
ultima0/gfx/gfx_surface.o \
ultima0/views/view.o \
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
new file mode 100644
index 00000000000..5e25ca6838a
--- /dev/null
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -0,0 +1,42 @@
+/* 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 "ultima/ultima0/data/data.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+void PLAYER::init() {
+ LuckyNumber = urand();
+
+ if (g_engine->isEnhanced()) {
+ // Super Aklabeth : more slots
+ Attributes = MAX_ATTR;
+ Objects = MAX_OBJ;
+ } else {
+ // Aklabeth standards
+ Attributes = Objects = 6;
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
new file mode 100644
index 00000000000..c4ef0dcacfe
--- /dev/null
+++ b/engines/ultima/ultima0/data/data.h
@@ -0,0 +1,89 @@
+/* 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 ULTIMA0_DATA_H
+#define ULTIMA0_DATA_H
+
+#include "common/rect.h"
+#include "ultima/ultima0/data/defines.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+// point/rect types
+typedef Common::Point COORD;
+typedef Common::Rect RECT;
+
+/**
+ * World Map structure
+ */
+struct WORLDMAP {
+ int MapSize = 0; // Size of map
+ byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE]; // Map information
+};
+
+/**
+ * Monster structure
+ */
+struct MONSTER {
+ COORD Loc; // Position
+ int Type = 0; // Monster type
+ int Strength = 0; // Strength
+ int Alive = 0; // Alive flag
+};
+
+/**
+ * Dungeon Map Structure
+ */
+struct DUNGEONMAP {
+ int MapSize = 0; // Size of Map
+ byte Map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
+ int MonstCount = 0; // Number of Monsters
+ MONSTER Monster[MAX_MONSTERS]; // Monster records
+};
+
+/**
+ * Player structure
+ */
+struct PLAYER {
+ char Name[MAX_NAME + 1] = {}; // Player Name
+ COORD World; // World map position
+ COORD Dungeon; // Dungeon map position
+ COORD DungDir; // Dungeon direction facing
+ byte Class = '?'; // Player class (F or M)
+ int HPGain = 0; // HPs gained in dungeon
+ int Level = 0; // Dungeon level, 0 = world map
+ int Skill = 0; // Skill level
+ int Task = 0; // Task set (-1 = none)
+ int TaskCompleted = 0; // Task completed
+ uint32 LuckyNumber = 0; // Value used for seeding
+ int Attributes = 0; // Number of attributes
+ int Objects = 0; // Number of objects
+ int Attr[MAX_ATTR] = {}; // Attribute values
+ double Object[MAX_OBJ] = {}; // Object counts
+
+ void init();
+};
+
+} // End of namespace Ultima4
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/defines.h b/engines/ultima/ultima0/data/defines.h
similarity index 98%
rename from engines/ultima/ultima0/defines.h
rename to engines/ultima/ultima0/data/defines.h
index 5b9c168d92b..add57329cd0 100644
--- a/engines/ultima/ultima0/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef ULTIMA0_DEFINES_H
-#define ULTIMA0_DEFINES_H
+#ifndef ULTIMA0_DATA_DEFINES_H
+#define ULTIMA0_DATA_DEFINES_H
#include "common/scummsys.h"
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
index 602cbc01367..d3d88e01206 100644
--- a/engines/ultima/ultima0/events.cpp
+++ b/engines/ultima/ultima0/events.cpp
@@ -196,7 +196,7 @@ void Events::addKeypress(const Common::KeyCode kc) {
/*------------------------------------------------------------------------*/
Bounds::Bounds(Common::Rect &innerBounds) :
- _bounds(0, 0, 320, 200),
+ _bounds(0, 0, DEFAULT_SCX, DEFAULT_SCY),
_innerBounds(innerBounds),
left(_bounds.left), top(_bounds.top),
right(_bounds.right), bottom(_bounds.bottom) {
diff --git a/engines/ultima/ultima0/gfx/font.h b/engines/ultima/ultima0/gfx/font.h
index 1fbffdcf67d..48e48d101c2 100644
--- a/engines/ultima/ultima0/gfx/font.h
+++ b/engines/ultima/ultima0/gfx/font.h
@@ -23,7 +23,7 @@
#define ULTIMA0_GFX_FONT_H
#include "graphics/managed_surface.h"
-#include "ultima/ultima0/defines.h"
+#include "ultima/ultima0/data/defines.h"
namespace Ultima {
namespace Ultima0 {
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.cpp b/engines/ultima/ultima0/gfx/gfx_surface.cpp
index 3b59fa9aade..e1e067e1b21 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.cpp
+++ b/engines/ultima/ultima0/gfx/gfx_surface.cpp
@@ -29,7 +29,8 @@ namespace Gfx {
void GfxSurface::init() {
- _textColor = g_engine->_palette.findBestColor(0, 255, 0);
+ // Default text to Cyan
+ _textColor = g_engine->_palette.findBestColor(0, 255, 255);
}
void GfxSurface::writeString(const char *fmt, ...) {
@@ -38,10 +39,23 @@ void GfxSurface::writeString(const char *fmt, ...) {
Common::String str = Common::String::vformat(fmt, alist);
va_end(alist);
+ writeString(str);
+}
+
+void GfxSurface::writeString(const Common::Point &pt, const char *fmt, ...) {
+ va_list alist;
+ va_start(alist, fmt);
+ Common::String str = Common::String::vformat(fmt, alist);
+ va_end(alist);
+
+ _textPos = pt;
+ writeString(str);
+}
+
+void GfxSurface::writeString(const Common::String &str) {
for (const char *p = str.c_str(); *p; ++p) {
if (*p == '\n') {
- _textPos.x = 0;
- _textPos.y++;
+ newLine();
} else {
writeChar(*p);
}
@@ -56,9 +70,13 @@ void GfxSurface::writeChar(uint32 chr) {
}
if (_textPos.x >= TEXT_WIDTH || chr == '\n') {
- _textPos.x = 0;
- _textPos.y++;
+ newLine();
}
+}
+
+void GfxSurface::newLine() {
+ _textPos.x = 0;
+ _textPos.y++;
if (_textPos.y >= TEXT_HEIGHT) {
_textPos.y = TEXT_HEIGHT - 1;
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.h b/engines/ultima/ultima0/gfx/gfx_surface.h
index 3b89737717c..94c87ebeead 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.h
+++ b/engines/ultima/ultima0/gfx/gfx_surface.h
@@ -34,6 +34,8 @@ private:
byte _textColor;
void init();
+ void writeString(const Common::String &str);
+ void newLine();
public:
GfxSurface() : Graphics::ManagedSurface() {
@@ -46,8 +48,10 @@ public:
/**
* Write some text to the surface
*/
- void writeString(const char *format, ...);
+ void writeString(const char *fmt, ...);
+ void writeString(const Common::Point &pt, const char *fmt, ...);
void writeChar(uint32 chr);
+
};
} // namespace Gfx
diff --git a/engines/ultima/ultima0/struct.h b/engines/ultima/ultima0/struct.h
index 693284b9558..59a8706c0e2 100644
--- a/engines/ultima/ultima0/struct.h
+++ b/engines/ultima/ultima0/struct.h
@@ -22,7 +22,8 @@
#ifndef ULTIMA0_STRUCT_H
#define ULTIMA0_STRUCT_H
-#include "ultima/ultima0/defines.h"
+#include "ultima/ultima0/data/defines.h"
+#include "ultima/ultima0/data/data.h"
namespace Ultima {
namespace Ultima0 {
@@ -35,69 +36,6 @@ namespace Ultima0 {
/************************************************************************/
/************************************************************************/
-typedef struct _Coord /* Coordinate structure */
-{
- int x, y;
-} COORD;
-
-/************************************************************************/
-
-typedef struct _Rect /* Rectangle structure */
-{
- int left, top, right, bottom; /* Rectangle coords */
-} RECT;
-
-/************************************************************************/
-
-typedef struct _WorldMap /* World Map structure */
-{
- int MapSize; /* Size of map */
- unsigned char Map[WORLD_MAP_SIZE] /* Map information */
- [WORLD_MAP_SIZE];
-} WORLDMAP;
-
-/************************************************************************/
-
-typedef struct _Monster /* Monster structure */
-{
- COORD Loc; /* Position */
- int Type; /* Monster type */
- int Strength; /* Strength */
- int Alive; /* Alive flag */
-} MONSTER;
-
-/************************************************************************/
-
-typedef struct _DungeonMap /* Dungeon Map Structure */
-{
- int MapSize; /* Size of Map */
- unsigned char Map[DUNGEON_MAP_SIZE] /* Map information */
- [DUNGEON_MAP_SIZE];
- int MonstCount; /* Number of Monsters */
- MONSTER Monster[MAX_MONSTERS]; /* Monster records */
-} DUNGEONMAP;
-
-/************************************************************************/
-
-typedef struct _Player /* Player structure */
-{
- char Name[MAX_NAME + 1]; /* Player Name */
- COORD World; /* World map position */
- COORD Dungeon; /* Dungeon map position */
- COORD DungDir; /* Dungeon direction facing */
- char Class; /* Player class (F or M) */
- int HPGain; /* HPs gained in dungeon */
- int Level; /* Dungeon level, 0 = world map */
- int Skill; /* Skill level */
- int Task; /* Task set (-1 = none) */
- int TaskCompleted; /* Task completed */
- int LuckyNumber; /* Value used for seeding */
- int Attributes; /* Number of attributes */
- int Objects; /* Number of objects */
- int Attr[MAX_ATTR]; /* Attribute values */
- double Object[MAX_OBJ]; /* Object counts */
-} PLAYER;
-
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index c748731e956..1bebcecc4c9 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -26,7 +26,7 @@
#include "graphics/palette.h"
#include "engines/engine.h"
#include "ultima/detection.h"
-#include "ultima/ultima0/defines.h"
+#include "ultima/ultima0/data/data.h"
#include "ultima/ultima0/events.h"
namespace Ultima {
@@ -44,6 +44,7 @@ protected:
public:
Graphics::Palette _palette;
+ PLAYER _player;
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
@@ -73,6 +74,13 @@ public:
* Get a random number
*/
uint getRandomNumber(uint maxVal = RND_MAX) { return _randomSource.getRandomNumber(maxVal); }
+
+ /**
+ * Returns true if enhancements are turned on
+ */
+ bool isEnhanced() const {
+ return true;
+ }
};
extern Ultima0Engine *g_engine;
diff --git a/engines/ultima/ultima0/views/startup.cpp b/engines/ultima/ultima0/views/startup.cpp
index 9a11bf5816a..b73dddb0fd8 100644
--- a/engines/ultima/ultima0/views/startup.cpp
+++ b/engines/ultima/ultima0/views/startup.cpp
@@ -27,16 +27,20 @@ namespace Ultima {
namespace Ultima0 {
namespace Views {
+void Startup::draw() {
+ auto s = getSurface();
+ s.writeString(Common::Point(5, 10), "Ultima 0 - Akalabeth!");
+ s.writeString(Common::Point(2, 19), "Ready?");
+}
+
bool Startup::msgKeypress(const KeypressMessage &msg) {
- // Any keypress to close the view
close();
return true;
}
-void Startup::draw() {
- auto s = getSurface();
- s.writeString("Hello");
-
+bool Startup::msgMouseDown(const MouseDownMessage &msg) {
+ close();
+ return true;
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/startup.h b/engines/ultima/ultima0/views/startup.h
index b530c509967..f334b302231 100644
--- a/engines/ultima/ultima0/views/startup.h
+++ b/engines/ultima/ultima0/views/startup.h
@@ -34,6 +34,7 @@ public:
~Startup() override {}
bool msgKeypress(const KeypressMessage &msg) override;
+ bool msgMouseDown(const MouseDownMessage &msg) override;
void draw() override;
};
Commit: 76481b8c5f0f5e8e48037c635a81165693dd1b09
https://github.com/scummvm/scummvm/commit/76481b8c5f0f5e8e48037c635a81165693dd1b09
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:23+11:00
Commit Message:
ULTIMA: ULTIMA0: Reduce resolution to make font match original
Changed paths:
engines/ultima/ultima0/data/defines.h
diff --git a/engines/ultima/ultima0/data/defines.h b/engines/ultima/ultima0/data/defines.h
index add57329cd0..69741de0e88 100644
--- a/engines/ultima/ultima0/data/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -27,8 +27,8 @@
namespace Ultima {
namespace Ultima0 {
-constexpr int DEFAULT_SCX = 1024; // Default Screen Size and Depth
-constexpr int DEFAULT_SCY = 768;
+constexpr int DEFAULT_SCX = 640; // Default Screen Size and Depth
+constexpr int DEFAULT_SCY = 400;
#define RND_MAX 0x7fffffff
#define RND() (((double)g_engine->getRandomNumber())/RND_MAX)
Commit: 1756d22e49263b78d1b7ad0496ad9053b6ad9979
https://github.com/scummvm/scummvm/commit/1756d22e49263b78d1b7ad0496ad9053b6ad9979
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:23+11:00
Commit Message:
ULTIMA: ULTIMA0: Title screen
Changed paths:
A engines/ultima/ultima0/metaengine.cpp
A engines/ultima/ultima0/metaengine.h
A engines/ultima/ultima0/views/title.cpp
A engines/ultima/ultima0/views/title.h
engines/ultima/metaengine.cpp
engines/ultima/module.mk
engines/ultima/ultima0/events.cpp
engines/ultima/ultima0/gfx/gfx_surface.cpp
engines/ultima/ultima0/gfx/gfx_surface.h
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/startup.cpp
engines/ultima/ultima0/views/startup.h
engines/ultima/ultima0/views/view.cpp
engines/ultima/ultima0/views/view.h
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/metaengine.cpp b/engines/ultima/metaengine.cpp
index 11cf23ac78b..6a8d2eb92d6 100644
--- a/engines/ultima/metaengine.cpp
+++ b/engines/ultima/metaengine.cpp
@@ -29,6 +29,7 @@
#include "common/translation.h"
#ifdef ENABLE_AKALABETH
#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/metaengine.h"
#endif
#ifdef ENABLE_ULTIMA1
#include "ultima/shared/early/ultima_early.h"
@@ -254,10 +255,14 @@ SaveStateDescriptor UltimaMetaEngine::querySaveMetaInfos(const char *target, int
}
Common::KeymapArray UltimaMetaEngine::initKeymaps(const char *target) const {
-#if defined(ENABLE_ULTIMA4) || defined(ENABLE_ULTIMA6) || defined(ENABLE_ULTIMA8)
+#if defined(ENABLE_AKALABETH) || defined(ENABLE_ULTIMA4) || defined(ENABLE_ULTIMA6) || defined(ENABLE_ULTIMA8)
const Common::String gameId = getGameId(target);
#endif
+#ifdef ENABLE_AKALABETH
+ if (gameId == "akalabeth")
+ return Ultima::Ultima0::MetaEngine::initKeymaps();
+#endif
#ifdef ENABLE_ULTIMA4
if (gameId == "ultima4" || gameId == "ultima4_enh")
return Ultima::Ultima4::MetaEngine::initKeymaps();
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 456da9a7a82..052378cf4a4 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS += \
ultima0/ultima0.o \
ultima0/events.o \
ultima0/messages.o \
+ ultima0/metaengine.o \
ultima0/attack.o \
ultima0/british.o \
ultima0/ddraw.o \
@@ -33,7 +34,8 @@ MODULE_OBJS += \
ultima0/gfx/font.o \
ultima0/gfx/gfx_surface.o \
ultima0/views/view.o \
- ultima0/views/startup.o
+ ultima0/views/startup.o \
+ ultima0/views/title.o
endif
ifdef ENABLE_ULTIMA1
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
index d3d88e01206..cd244282888 100644
--- a/engines/ultima/ultima0/events.cpp
+++ b/engines/ultima/ultima0/events.cpp
@@ -50,7 +50,7 @@ void Events::runGame() {
if (saveSlot != -1)
g_engine->loadGameState(saveSlot);
- addView("Startup");
+ addView("Title");
Common::Event e;
while (!_views.empty() && !shouldQuit()) {
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.cpp b/engines/ultima/ultima0/gfx/gfx_surface.cpp
index e1e067e1b21..bc9fcda45c0 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.cpp
+++ b/engines/ultima/ultima0/gfx/gfx_surface.cpp
@@ -33,28 +33,28 @@ void GfxSurface::init() {
_textColor = g_engine->_palette.findBestColor(0, 255, 255);
}
-void GfxSurface::writeString(const char *fmt, ...) {
- va_list alist;
- va_start(alist, fmt);
- Common::String str = Common::String::vformat(fmt, alist);
- va_end(alist);
-
- writeString(str);
-}
-
-void GfxSurface::writeString(const Common::Point &pt, const char *fmt, ...) {
- va_list alist;
- va_start(alist, fmt);
- Common::String str = Common::String::vformat(fmt, alist);
- va_end(alist);
-
+void GfxSurface::writeString(const Common::Point &pt, const Common::String &str,
+ Graphics::TextAlign align) {
_textPos = pt;
- writeString(str);
+ writeString(str, align);
}
-void GfxSurface::writeString(const Common::String &str) {
+void GfxSurface::writeString(const Common::String &str, Graphics::TextAlign align) {
+ switch (align) {
+ case Graphics::kTextAlignCenter:
+ _textPos.x -= str.size() / 2;
+ break;
+ case Graphics::kTextAlignRight:
+ _textPos.x -= str.size();
+ break;
+ case Graphics::kTextAlignLeft:
+ default:
+ break;
+ }
+
for (const char *p = str.c_str(); *p; ++p) {
if (*p == '\n') {
+ assert(align == Graphics::kTextAlignLeft);
newLine();
} else {
writeChar(*p);
@@ -88,6 +88,18 @@ void GfxSurface::newLine() {
}
}
+byte GfxSurface::setColor(byte color) {
+ byte oldColor = _textColor;
+ _textColor = color;
+ return oldColor;
+}
+
+byte GfxSurface::setColor(byte r, byte g, byte b) {
+ byte oldColor = _textColor;
+ _textColor = g_engine->_palette.findBestColor(r, g, b);
+ return oldColor;
+}
+
} // namespace Gfx
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.h b/engines/ultima/ultima0/gfx/gfx_surface.h
index 94c87ebeead..94e35457b88 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.h
+++ b/engines/ultima/ultima0/gfx/gfx_surface.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_GFX_SURFACE_H
#define ULTIMA0_GFX_SURFACE_H
+#include "graphics/font.h"
#include "graphics/managed_surface.h"
namespace Ultima {
@@ -34,7 +35,6 @@ private:
byte _textColor;
void init();
- void writeString(const Common::String &str);
void newLine();
public:
@@ -48,10 +48,13 @@ public:
/**
* Write some text to the surface
*/
- void writeString(const char *fmt, ...);
- void writeString(const Common::Point &pt, const char *fmt, ...);
+ void writeString(const Common::Point &pt, const Common::String &str,
+ Graphics::TextAlign align = Graphics::kTextAlignLeft);
+ void writeString(const Common::String &str, Graphics::TextAlign align = Graphics::kTextAlignLeft);
void writeChar(uint32 chr);
+ byte setColor(byte color);
+ byte setColor(byte r, byte g, byte b);
};
} // namespace Gfx
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
new file mode 100644
index 00000000000..d63aa3ecd71
--- /dev/null
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -0,0 +1,139 @@
+/* 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 "ultima/ultima0/metaengine.h"
+#include "ultima/ultima0/ultima0.h"
+#include "common/translation.h"
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/standard-actions.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+struct KeybindingRecord {
+ KeybindingAction _action;
+ const char *_id;
+ const char *_desc;
+ const char *_method;
+ const char *_key;
+ const char *_joy;
+};
+
+static const KeybindingRecord NORMAL_KEYS[] = {
+ { KEYBIND_SELECT, "INTERACT", _s("Interact"), "select", "RETURN", nullptr },
+ { KEYBIND_ESCAPE, "ESCAPE", _s("Abort action"), "", "ESCAPE", nullptr },
+ { KEYBIND_UP, "UP", _s("Up"), "move up", "UP", nullptr },
+ { KEYBIND_DOWN, "DOWN", _s("Down"), "move down", "DOWN", nullptr },
+ { KEYBIND_LEFT, "LEFT", _s("Left"), "move left", "LEFT", nullptr },
+ { KEYBIND_RIGHT, "RIGHT", _s("Right"), "move right", "RIGHT", nullptr },
+
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
+};
+
+struct KeysRecord {
+ const char *_id;
+ const char *_desc;
+ const KeybindingRecord *_keys;
+};
+
+static const KeysRecord NORMAL_RECORDS[] = {
+ { "ultima0", "Akalabeth", NORMAL_KEYS },
+ { nullptr, nullptr, nullptr }
+};
+
+
+static const KeysRecord *MODE_RECORDS[1] = {
+ NORMAL_RECORDS
+};
+
+Common::KeymapArray MetaEngine::initKeymaps(KeybindingMode mode) {
+ Common::KeymapArray keymapArray;
+ Common::Keymap *keyMap;
+ Common::Action *act;
+ const KeysRecord *recPtr = MODE_RECORDS[mode];
+
+ for (int kCtr = 0; recPtr->_id; ++recPtr, ++kCtr) {
+ // Core keymaps
+ keyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame,
+ recPtr->_id, recPtr->_desc);
+ keymapArray.push_back(keyMap);
+
+ if (kCtr == 0) {
+ addMouseClickActions(*keyMap);
+ }
+
+ for (const KeybindingRecord *r = recPtr->_keys; r->_id; ++r) {
+ act = new Common::Action(r->_id, _(r->_desc));
+ act->setCustomEngineActionEvent(r->_action);
+ act->addDefaultInputMapping(r->_key);
+ if (r->_joy)
+ act->addDefaultInputMapping(r->_joy);
+ if (r->_action == KEYBIND_UP || r->_action == KEYBIND_DOWN ||
+ r->_action == KEYBIND_LEFT || r->_action == KEYBIND_RIGHT)
+ // Allow movement actions to be triggered on keyboard repeats
+ act->allowKbdRepeats();
+
+ keyMap->addAction(act);
+ }
+ }
+
+ return keymapArray;
+}
+
+void MetaEngine::addMouseClickActions(Common::Keymap &keyMap) {
+ Common::Action *act;
+
+ act = new Common::Action(Common::kStandardActionLeftClick, _("Left click"));
+ act->setLeftClickEvent();
+ act->addDefaultInputMapping("MOUSE_LEFT");
+ act->addDefaultInputMapping("JOY_A");
+ keyMap.addAction(act);
+
+ act = new Common::Action(Common::kStandardActionRightClick, _("Right click"));
+ act->setRightClickEvent();
+ act->addDefaultInputMapping("MOUSE_RIGHT");
+ act->addDefaultInputMapping("JOY_B");
+ keyMap.addAction(act);
+}
+
+void MetaEngine::setKeybindingMode(KeybindingMode mode) {
+ Common::Keymapper *const mapper = g_engine->getEventManager()->getKeymapper();
+ mapper->cleanupGameKeymaps();
+
+ Common::KeymapArray arr = initKeymaps(mode);
+
+ for (uint idx = 0; idx < arr.size(); ++idx)
+ mapper->addGameKeymap(arr[idx]);
+}
+
+Common::String MetaEngine::getMethod(KeybindingAction keyAction) {
+ for (int kCtr = 0; kCtr < 4; ++kCtr) {
+ for (const KeybindingRecord *r = NORMAL_RECORDS[kCtr]._keys; r->_id; ++r) {
+ if (r->_action == keyAction)
+ return r->_method;
+ }
+ }
+
+ return Common::String();
+}
+
+} // End of namespace Ultima0
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima0/metaengine.h b/engines/ultima/ultima0/metaengine.h
new file mode 100644
index 00000000000..0dac9e7faaf
--- /dev/null
+++ b/engines/ultima/ultima0/metaengine.h
@@ -0,0 +1,67 @@
+/* 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 ULTIMA0_METAENGINE_H
+#define ULTIMA0_METAENGINE_H
+
+#include "backends/keymapper/keymapper.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+enum KeybindingAction {
+ KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
+ KEYBIND_SELECT, KEYBIND_ESCAPE,
+
+ KEYBIND_NONE
+};
+
+enum KeybindingMode {
+ KBMODE_NORMAL ///< Keys available when normal in-game
+};
+
+class MetaEngine {
+private:
+ /**
+ * Get the method to execute
+ */
+ static Common::String getMethod(KeybindingAction keyAction);
+
+ /**
+ * Adds the default actions for the mouse buttons
+ */
+ static void addMouseClickActions(Common::Keymap &keyMap);
+public:
+ /**
+ * Initialize keymaps
+ */
+ static Common::KeymapArray initKeymaps(KeybindingMode mode = KBMODE_NORMAL);
+
+ /**
+ * Sets the current set of actions which are active
+ */
+ static void setKeybindingMode(KeybindingMode mode);
+};
+
+} // End of namespace Ultima0
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 2cd2cfb0c7c..8445fa314ed 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -29,7 +29,7 @@
namespace Ultima {
namespace Ultima0 {
-static const byte PALETTE[8][3] = {
+static const byte PALETTE[][3] = {
{ 0, 0, 0 },
{ 255, 0, 255 },
{ 255, 0, 0 },
@@ -37,6 +37,7 @@ static const byte PALETTE[8][3] = {
{ 0, 0, 255 },
{ 255, 255, 0 },
{ 0, 255, 255 },
+ { 255, 0, 128 },
{ 220, 20, 130 }
};
@@ -44,7 +45,7 @@ Ultima0Engine *g_engine;
Ultima0Engine::Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc) :
Engine(syst), _gameDescription(gameDesc), _randomSource("Ultima0"),
- _palette(&PALETTE[0][0], 8) {
+ _palette(&PALETTE[0][0], sizeof(PALETTE) / 3) {
g_engine = this;
}
@@ -57,15 +58,6 @@ Common::Error Ultima0Engine::run() {
runGame();
-#if 0
- Display = new Graphics::Screen();
- GameSpeed = 120;
-
- // Call the real main program
-// MAINStart();
-
- delete Display;
-#endif
return Common::kNoError;
}
diff --git a/engines/ultima/ultima0/views/startup.cpp b/engines/ultima/ultima0/views/startup.cpp
index b73dddb0fd8..1ef96364297 100644
--- a/engines/ultima/ultima0/views/startup.cpp
+++ b/engines/ultima/ultima0/views/startup.cpp
@@ -33,16 +33,6 @@ void Startup::draw() {
s.writeString(Common::Point(2, 19), "Ready?");
}
-bool Startup::msgKeypress(const KeypressMessage &msg) {
- close();
- return true;
-}
-
-bool Startup::msgMouseDown(const MouseDownMessage &msg) {
- close();
- return true;
-}
-
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/startup.h b/engines/ultima/ultima0/views/startup.h
index f334b302231..466dd4e1244 100644
--- a/engines/ultima/ultima0/views/startup.h
+++ b/engines/ultima/ultima0/views/startup.h
@@ -29,13 +29,28 @@ namespace Ultima0 {
namespace Views {
class Startup : public View {
+private:
+ void showTitle() {
+ replaceView("Title");
+ }
public:
Startup() : View("Startup") {}
~Startup() override {}
- bool msgKeypress(const KeypressMessage &msg) override;
- bool msgMouseDown(const MouseDownMessage &msg) override;
void draw() override;
+
+ bool msgKeypress(const KeypressMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgMouseDown(const MouseDownMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgAction(const ActionMessage &msg) override {
+ showTitle();
+ return true;
+ }
};
} // namespace Views
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
new file mode 100644
index 00000000000..b92129ce0c6
--- /dev/null
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -0,0 +1,67 @@
+/* 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 "graphics/paletteman.h"
+#include "ultima/ultima0/views/title.h"
+#include "ultima/ultima0/metaengine.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+void Title::draw() {
+ auto s = getSurface();
+ s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
+
+ const int selected = getColor(255, 0, 128);
+ const int white = getColor(255, 255, 255);
+
+ s.setColor(_highlightedOption == 0 ? selected : white);
+ s.writeString(Common::Point(20, 16), "Introduction", Graphics::kTextAlignCenter);
+ s.setColor(_highlightedOption == 1 ? selected : white);
+ s.writeString(Common::Point(20, 17), "Create a Character", Graphics::kTextAlignCenter);
+ s.setColor(_highlightedOption == 2 ? selected : white);
+ s.writeString(Common::Point(20, 18), "Acknowledgements", Graphics::kTextAlignCenter);
+ s.setColor(_highlightedOption == 3 ? selected : white);
+ s.writeString(Common::Point(20, 19), "Journey Onwards", Graphics::kTextAlignCenter);
+}
+
+bool Title::msgAction(const ActionMessage &msg) {
+ switch (msg._action) {
+ case KEYBIND_UP:
+ _highlightedOption = _highlightedOption ? _highlightedOption - 1 : 3;
+ redraw();
+ break;
+ case KEYBIND_DOWN:
+ _highlightedOption = (_highlightedOption + 1) % 4;
+ redraw();
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/title.h b/engines/ultima/ultima0/views/title.h
new file mode 100644
index 00000000000..e253d2ffd5d
--- /dev/null
+++ b/engines/ultima/ultima0/views/title.h
@@ -0,0 +1,47 @@
+/* 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 ULTIMA0_VIEWS_TITLE_H
+#define ULTIMA0_VIEWS_TITLE_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Title : public View {
+private:
+ int _highlightedOption = 0;
+
+public:
+ Title() : View("Title") {}
+ ~Title() override {}
+
+ void draw() override;
+ bool msgAction(const ActionMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/view.cpp b/engines/ultima/ultima0/views/view.cpp
index 8ea3789f6d1..082db7db230 100644
--- a/engines/ultima/ultima0/views/view.cpp
+++ b/engines/ultima/ultima0/views/view.cpp
@@ -20,6 +20,7 @@
*/
#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/ultima0.h"
namespace Ultima {
namespace Ultima0 {
@@ -80,6 +81,10 @@ bool View::msgMouseUp(const MouseUpMessage &msg) {
return child ? child->send(msg) : false;
}
+byte View::getColor(byte r, byte g, byte b) {
+ return g_engine->_palette.findBestColor(r, g, b);
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/view.h b/engines/ultima/ultima0/views/view.h
index 7bd607456d2..69e686c1763 100644
--- a/engines/ultima/ultima0/views/view.h
+++ b/engines/ultima/ultima0/views/view.h
@@ -53,6 +53,9 @@ private:
*/
UIElement *getElementAtPos(const Common::Point &pos) const;
+protected:
+ byte getColor(byte r, byte g, byte b);
+
public:
View(const Common::String &name, UIElement *uiParent) :
UIElement(name, uiParent) {
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index ccc675e03b9..a27c33a200d 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -23,6 +23,7 @@
#define ULTIMA0_VIEWS_H
#include "ultima/ultima0/views/startup.h"
+#include "ultima/ultima0/views/title.h"
namespace Ultima {
namespace Ultima0 {
@@ -30,6 +31,7 @@ namespace Views {
struct Views {
Startup _startup;
+ Title _title;
};
} // namespace Views
Commit: f3c3c74c85d20fdf0d168f7f99f48ed0c700150e
https://github.com/scummvm/scummvm/commit/f3c3c74c85d20fdf0d168f7f99f48ed0c700150e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:23+11:00
Commit Message:
ULTIMA: ULTIMA0: Show mouse cursor on mouse move
Changed paths:
engines/ultima/ultima0/events.cpp
engines/ultima/ultima0/ultima0.cpp
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
index cd244282888..685858956b7 100644
--- a/engines/ultima/ultima0/events.cpp
+++ b/engines/ultima/ultima0/events.cpp
@@ -21,6 +21,7 @@
#include "common/system.h"
#include "common/config-manager.h"
+#include "graphics/cursorman.h"
#include "graphics/screen.h"
#include "ultima/ultima0/events.h"
#include "ultima/ultima0/gfx/gfx_surface.h"
@@ -32,6 +33,32 @@ namespace Ultima0 {
Events *g_events;
+constexpr int CURSOR_W = 12;
+constexpr int CURSOR_H = 20;
+
+static const byte ARROW_CURSOR[CURSOR_W * CURSOR_H] = {
+ 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 0, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 0, 1, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 0, 1, 1, 1, 0, 9, 9, 9, 9, 9, 9, 9,
+ 0, 1, 1, 1, 1, 0, 9, 9, 9, 9, 9, 9,
+ 0, 1, 1, 1, 1, 1, 0, 9, 9, 9, 9, 9,
+ 0, 1, 1, 1, 1, 1, 1, 0, 9, 9, 9, 9,
+ 0, 1, 1, 1, 1, 1, 1, 1, 0, 9, 9, 9,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9, 9,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9,
+ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 1, 1, 0, 9, 9, 9, 9,
+ 0, 1, 1, 0, 0, 1, 1, 0, 9, 9, 9, 9,
+ 0, 1, 0, 9, 9, 0, 1, 1, 0, 9, 9, 9,
+ 0, 0, 9, 9, 9, 0, 1, 1, 0, 9, 9, 9,
+ 0, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9, 9,
+ 9, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9,
+ 9, 9, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9
+};
+
Events::Events() : UIElement("Root", nullptr) {
g_events = this;
}
@@ -45,6 +72,8 @@ void Events::runGame() {
_screen = new Graphics::Screen();
Views::Views views; // Loads all views in the structure
+ CursorMan.pushCursor(ARROW_CURSOR, CURSOR_W, CURSOR_H, 0, 0, 9);
+
// Run the game
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot != -1)
@@ -82,23 +111,28 @@ void Events::runGame() {
void Events::processEvent(Common::Event &ev) {
switch (ev.type) {
case Common::EVENT_KEYDOWN:
+ CursorMan.showMouse(false);
if (ev.kbd.keycode < Common::KEYCODE_NUMLOCK)
msgKeypress(KeypressMessage(ev.kbd));
break;
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
+ CursorMan.showMouse(false);
msgAction(ActionMessage(ev.customType));
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_MBUTTONDOWN:
+ CursorMan.showMouse(true);
msgMouseDown(MouseDownMessage(ev.type, ev.mouse));
break;
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_MBUTTONUP:
+ CursorMan.showMouse(true);
msgMouseUp(MouseUpMessage(ev.type, ev.mouse));
break;
case Common::EVENT_MOUSEMOVE:
+ CursorMan.showMouse(true);
msgMouseMove(MouseMoveMessage(ev.type, ev.mouse));
break;
default:
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 8445fa314ed..63edbc54301 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -31,6 +31,7 @@ namespace Ultima0 {
static const byte PALETTE[][3] = {
{ 0, 0, 0 },
+ { 255, 255, 255 },
{ 255, 0, 255 },
{ 255, 0, 0 },
{ 0, 255, 0 },
Commit: cc2262aa12a1295fb5bc1365189f56660eda4c4c
https://github.com/scummvm/scummvm/commit/cc2262aa12a1295fb5bc1365189f56660eda4c4c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:24+11:00
Commit Message:
ULTIMA: ULTIMA0: Add mouse handling to title screen
Changed paths:
engines/ultima/ultima0/gfx/font.h
engines/ultima/ultima0/gfx/gfx_surface.h
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/title.h
diff --git a/engines/ultima/ultima0/gfx/font.h b/engines/ultima/ultima0/gfx/font.h
index 48e48d101c2..233137454e2 100644
--- a/engines/ultima/ultima0/gfx/font.h
+++ b/engines/ultima/ultima0/gfx/font.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_GFX_FONT_H
#define ULTIMA0_GFX_FONT_H
+#include "common/rect.h"
#include "graphics/managed_surface.h"
#include "ultima/ultima0/data/defines.h"
@@ -34,6 +35,14 @@ constexpr int CHAR_WIDTH = 16;
constexpr int TEXT_WIDTH = DEFAULT_SCX / CHAR_WIDTH;
constexpr int TEXT_HEIGHT = DEFAULT_SCY / CHAR_HEIGHT;
+class TextRect : public ::Common::Rect {
+public:
+ TextRect() : ::Common::Rect() {}
+ TextRect(int left, int top, int right, int bottom) :
+ ::Common::Rect(left * CHAR_WIDTH, top * CHAR_HEIGHT,
+ (right + 1) * CHAR_WIDTH, (bottom + 1) * CHAR_HEIGHT) {}
+};
+
class Font {
private:
/**
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.h b/engines/ultima/ultima0/gfx/gfx_surface.h
index 94e35457b88..d765a5cb3c8 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.h
+++ b/engines/ultima/ultima0/gfx/gfx_surface.h
@@ -24,6 +24,7 @@
#include "graphics/font.h"
#include "graphics/managed_surface.h"
+#include "ultima/ultima0/gfx/font.h"
namespace Ultima {
namespace Ultima0 {
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index b92129ce0c6..0a1a6ba49bf 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -28,32 +28,53 @@ namespace Ultima {
namespace Ultima0 {
namespace Views {
-void Title::draw() {
- auto s = getSurface();
- s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
+Title::Title() : View("Title"),
+ _option0(this, 0, "Introduction", 16),
+ _option1(this, 1, "Create a Character", 17),
+ _option2(this, 2, "Acknowledgements", 18),
+ _option3(this, 3, "Journey Onwards", 19) {
+ _options[0] = &_option0;
+ _options[1] = &_option1;
+ _options[2] = &_option2;
+ _options[3] = &_option3;
+}
+bool Title::msgFocus(const FocusMessage &msg) {
+ _highlightedOption = 0;
+ updateSelections();
+ return true;
+}
+
+void Title::updateSelections() {
const int selected = getColor(255, 0, 128);
const int white = getColor(255, 255, 255);
- s.setColor(_highlightedOption == 0 ? selected : white);
- s.writeString(Common::Point(20, 16), "Introduction", Graphics::kTextAlignCenter);
- s.setColor(_highlightedOption == 1 ? selected : white);
- s.writeString(Common::Point(20, 17), "Create a Character", Graphics::kTextAlignCenter);
- s.setColor(_highlightedOption == 2 ? selected : white);
- s.writeString(Common::Point(20, 18), "Acknowledgements", Graphics::kTextAlignCenter);
- s.setColor(_highlightedOption == 3 ? selected : white);
- s.writeString(Common::Point(20, 19), "Journey Onwards", Graphics::kTextAlignCenter);
+ for (int i = 0; i < 4; ++i) {
+ auto &opt = _options[i];
+ opt->_color = opt->_index == _highlightedOption ? selected : white;
+ opt->redraw();
+ }
+}
+
+void Title::draw() {
+ View::draw();
+
+ auto s = getSurface();
+ s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
}
bool Title::msgAction(const ActionMessage &msg) {
switch (msg._action) {
case KEYBIND_UP:
_highlightedOption = _highlightedOption ? _highlightedOption - 1 : 3;
- redraw();
+ updateSelections();
break;
case KEYBIND_DOWN:
_highlightedOption = (_highlightedOption + 1) % 4;
- redraw();
+ updateSelections();
+ break;
+ case KEYBIND_SELECT:
+ selectOption();
break;
default:
break;
@@ -62,6 +83,45 @@ bool Title::msgAction(const ActionMessage &msg) {
return true;
}
+bool Title::msgGame(const GameMessage &msg) {
+ if (msg._name == "SELECTION") {
+ _highlightedOption = msg._value;
+ updateSelections();
+ return true;
+ }
+
+ return false;
+}
+
+bool Title::msgMouseDown(const MouseDownMessage &msg) {
+ selectOption();
+ return true;
+}
+
+void Title::selectOption() {
+ const char *VIEW_NAMES[4] = { "Intro", "CreateCharacter", "Acknowledgements", "Game" };
+ replaceView(VIEW_NAMES[_highlightedOption]);
+}
+
+/*-------------------------------------------------------------------*/
+
+Title::TitleOption::TitleOption(Title *parent, int index, const Common::String &text, int row) :
+ UIElement("TitleOption", parent), _index(index), _text(text) {
+ int xs = 20 - text.size() / 2;
+ setBounds(Gfx::TextRect(xs, row, xs + text.size(), row));
+}
+
+void Title::TitleOption::draw() {
+ auto s = getSurface();
+ s.setColor(_color);
+ s.writeString(_text);
+}
+
+bool Title::TitleOption::msgMouseEnter(const MouseEnterMessage &msg) {
+ _parent->send(GameMessage("SELECTION", _index));
+ return true;
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/title.h b/engines/ultima/ultima0/views/title.h
index e253d2ffd5d..2df1b902851 100644
--- a/engines/ultima/ultima0/views/title.h
+++ b/engines/ultima/ultima0/views/title.h
@@ -29,15 +29,37 @@ namespace Ultima0 {
namespace Views {
class Title : public View {
+ class TitleOption : public UIElement {
+ public:
+ int _index;
+ Common::String _text;
+ byte _color = 0;
+ public:
+ TitleOption(Title *parent, int index, const Common::String &text, int row);
+ void draw() override;
+ bool msgMouseEnter(const MouseEnterMessage &msg) override;
+ };
+
private:
+ TitleOption _option0;
+ TitleOption _option1;
+ TitleOption _option2;
+ TitleOption _option3;
+ TitleOption *_options[4];
int _highlightedOption = 0;
+ void updateSelections();
+ void selectOption();
+
public:
- Title() : View("Title") {}
+ Title();
~Title() override {}
+ bool msgFocus(const FocusMessage &msg) override;
void draw() override;
bool msgAction(const ActionMessage &msg) override;
+ bool msgGame(const GameMessage &msg) override;
+ bool msgMouseDown(const MouseDownMessage &msg);
};
} // namespace Views
Commit: 17de45134d6831c3d2bf5d26c7e8c320bc28542c
https://github.com/scummvm/scummvm/commit/17de45134d6831c3d2bf5d26c7e8c320bc28542c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:24+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Create Character view
Changed paths:
A engines/ultima/ultima0/views/create_character.cpp
A engines/ultima/ultima0/views/create_character.h
engines/ultima/module.mk
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/gfx/gfx_surface.cpp
engines/ultima/ultima0/gfx/gfx_surface.h
engines/ultima/ultima0/globals.cpp
engines/ultima/ultima0/messages.h
engines/ultima/ultima0/player.cpp
engines/ultima/ultima0/views/startup.cpp
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 052378cf4a4..cd152ab2f62 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -35,7 +35,8 @@ MODULE_OBJS += \
ultima0/gfx/gfx_surface.o \
ultima0/views/view.o \
ultima0/views/startup.o \
- ultima0/views/title.o
+ ultima0/views/title.o \
+ ultima0/views/create_character.o
endif
ifdef ENABLE_ULTIMA1
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 5e25ca6838a..be0488f92b9 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -25,17 +25,50 @@
namespace Ultima {
namespace Ultima0 {
+const _OInfStruct _OInfo[] = {
+ { "Food", 1, 0, 'F' },
+ { "Rapier", 8, 10, 'R' },
+ { "Axe", 5, 5, 'A' },
+ { "Shield", 6, 1, 'S' },
+ { "Bow+Arrow", 3, 4, 'B' },
+ { "Amulet", 15, 0, 'M' }
+};
+
+const _MInfStruct _MInfo[] = {
+ { "Skeleton", 1 },
+ { "Thief", 2 },
+ { "Giant Rat", 3 },
+ { "Orc", 4 },
+ { "Viper", 5 },
+ { "Carrion Crawler", 6 },
+ { "Gremlin", 7 },
+ { "Mimic", 8 },
+ { "Daemon", 9 },
+ { "Balrog", 10 }
+};
+
+const char *ATTRIB_NAMES[] = { "HP", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
+
+
void PLAYER::init() {
- LuckyNumber = urand();
-
- if (g_engine->isEnhanced()) {
- // Super Aklabeth : more slots
- Attributes = MAX_ATTR;
- Objects = MAX_OBJ;
- } else {
- // Aklabeth standards
- Attributes = Objects = 6;
- }
+ Common::fill(Name, Name + MAX_NAME + 1, '\0');
+ World.x = World.y = 0;
+ Dungeon.x = Dungeon.y = 0;
+ DungDir.x = DungDir.y = 0;
+ Class = '?';
+ HPGain = 0;
+ LuckyNumber = 0;
+ Level = 0;
+ Skill = 0;
+ Task = 0;
+ TaskCompleted = 0;
+ Common::fill(Attr, Attr + MAX_ATTR, 0);
+ Common::fill(Object, Object + MAX_OBJ, 0);
+}
+
+void PLAYER::rollAttributes() {
+ for (int i = 0; i < MAX_ATTR; ++i)
+ Attr[i] = g_engine->getRandomNumber(21) + 4;
}
} // namespace Ultima0
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index c4ef0dcacfe..65939914efd 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -28,6 +28,19 @@
namespace Ultima {
namespace Ultima0 {
+
+struct _OInfStruct {
+ const char *Name; int Cost; int MaxDamage; char Key;
+};
+struct _MInfStruct {
+ const char *Name; int Level;
+};
+
+extern const _OInfStruct _OInfo[];
+extern const _MInfStruct _MInfo[];
+extern const char *ATTRIB_NAMES[];
+
+
// point/rect types
typedef Common::Point COORD;
typedef Common::Rect RECT;
@@ -75,12 +88,13 @@ struct PLAYER {
int Task = 0; // Task set (-1 = none)
int TaskCompleted = 0; // Task completed
uint32 LuckyNumber = 0; // Value used for seeding
- int Attributes = 0; // Number of attributes
- int Objects = 0; // Number of objects
+ const int Attributes = MAX_ATTR; // Number of attributes
+ const int Objects = MAX_OBJ; // Number of objects
int Attr[MAX_ATTR] = {}; // Attribute values
double Object[MAX_OBJ] = {}; // Object counts
void init();
+ void rollAttributes();
};
} // End of namespace Ultima4
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.cpp b/engines/ultima/ultima0/gfx/gfx_surface.cpp
index bc9fcda45c0..1b27e99e6f4 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.cpp
+++ b/engines/ultima/ultima0/gfx/gfx_surface.cpp
@@ -88,6 +88,10 @@ void GfxSurface::newLine() {
}
}
+void GfxSurface::setTextPos(const Common::Point &pt) {
+ _textPos = pt;
+}
+
byte GfxSurface::setColor(byte color) {
byte oldColor = _textColor;
_textColor = color;
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.h b/engines/ultima/ultima0/gfx/gfx_surface.h
index d765a5cb3c8..98e0a199cac 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.h
+++ b/engines/ultima/ultima0/gfx/gfx_surface.h
@@ -54,6 +54,7 @@ public:
void writeString(const Common::String &str, Graphics::TextAlign align = Graphics::kTextAlignLeft);
void writeChar(uint32 chr);
+ void setTextPos(const Common::Point &pt);
byte setColor(byte color);
byte setColor(byte r, byte g, byte b);
};
diff --git a/engines/ultima/ultima0/globals.cpp b/engines/ultima/ultima0/globals.cpp
index f643e857615..4cf6a1b5bd2 100644
--- a/engines/ultima/ultima0/globals.cpp
+++ b/engines/ultima/ultima0/globals.cpp
@@ -28,41 +28,11 @@
/************************************************************************/
#include "ultima/ultima0/akalabeth.h"
+#include "ultima/ultima0/data/data.h"
namespace Ultima {
namespace Ultima0 {
-struct _OInfStruct {
- const char *Name; int Cost; int MaxDamage; char Key;
-};
-struct _MInfStruct {
- const char *Name; int Level;
-};
-
-static struct _OInfStruct _OInfo[] = {
- { "Food", 1, 0, 'F' },
- { "Rapier", 8, 10, 'R' },
- { "Axe", 5, 5, 'A' },
- { "Shield", 6, 1, 'S' },
- { "Bow+Arrow", 3, 4, 'B' },
- { "Amulet", 15, 0, 'M' }
-};
-
-static struct _MInfStruct _MInfo[] = {
- { "Skeleton", 1 },
- { "Thief", 2 },
- { "Giant Rat", 3 },
- { "Orc", 4 },
- { "Viper", 5 },
- { "Carrion Crawler", 6 },
- { "Gremlin", 7 },
- { "Mimic", 8 },
- { "Daemon", 9 },
- { "Balrog", 10 }
-};
-
-static const char *_AName[] = { "HP", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
-
/************************************************************************/
/* */
/* Return name of object */
@@ -86,7 +56,7 @@ void GLOGetInfo(int n, int *pDamage, int *pCost, int *pKey) {
/************************************************************************/
const char *GLOAttribName(int n) {
- return _AName[n];
+ return ATTRIB_NAMES[n];
}
/************************************************************************/
diff --git a/engines/ultima/ultima0/messages.h b/engines/ultima/ultima0/messages.h
index 58ad20310f2..6f409fed9c8 100644
--- a/engines/ultima/ultima0/messages.h
+++ b/engines/ultima/ultima0/messages.h
@@ -25,6 +25,7 @@
#include "common/array.h"
#include "common/events.h"
#include "common/str.h"
+#include "ultima/ultima0/metaengine.h"
namespace Ultima {
namespace Ultima0 {
diff --git a/engines/ultima/ultima0/player.cpp b/engines/ultima/ultima0/player.cpp
index 5d1b8bb178b..8f97b0ea427 100644
--- a/engines/ultima/ultima0/player.cpp
+++ b/engines/ultima/ultima0/player.cpp
@@ -51,12 +51,7 @@ void PLAYERInit(PLAYER *p) {
p->Task = 0; p->TaskCompleted = 0;
p->HPGain = 0;
p->LuckyNumber = urand(); /* We do the lucky number ! */
- p->Attributes = p->Objects = 6; /* Aklabeth standards */
- if (MAINSuper()) /* Super Aklabeth : more */
- {
- p->Attributes = MAX_ATTR;
- p->Objects = MAX_OBJ;
- }
+
for (i = 0; i < p->Attributes; i++) p->Attr[i] = 0;
for (i = 0; i < p->Objects; i++) p->Object[i] = 0.0;
}
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
new file mode 100644
index 00000000000..cbc27cebad8
--- /dev/null
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -0,0 +1,136 @@
+/* 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 "ultima/ultima0/views/create_character.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+bool CreateCharacter::msgFocus(const FocusMessage &msg) {
+ g_engine->_player.init();
+ _mode = LUCKY_NUMBER;
+ _input = "";
+ return true;
+}
+
+void CreateCharacter::draw() {
+ auto s = getSurface();
+ const auto &player = g_engine->_player;
+ s.clear();
+
+ // Lucky number
+ s.writeString(Common::Point(1, 4), "Type thy Lucky Number.....");
+ if (_mode == LUCKY_NUMBER)
+ s.writeString(_input);
+ else
+ s.writeString(Common::String::format("%d", player.LuckyNumber));
+
+ // Level of play
+ if (_mode >= LEVEL) {
+ s.writeString(Common::Point(1, 6), "Level of play (1-10)......");
+ if (_mode == LEVEL)
+ s.writeString(_input);
+ else
+ s.writeString(Common::String::format("%d", player.Level));
+ }
+
+ // Stats
+ if (_mode >= STATS) {
+ for (int i = 0; i < MAX_ATTR; ++i) {
+ Common::String line = ATTRIB_NAMES[i];
+ while (line.size() < 15)
+ line += ".";
+ line += Common::String::format("%d", player.Attr[i]);
+ s.writeString(Common::Point(1, 9 + i), line);
+ }
+
+ s.writeString(Common::Point(0, 16), "Shallt thou play with these qualities?");
+ }
+
+ // Class selection
+ if (_mode == CLASS) {
+ s.writeString(Common::Point(0, 18), "And shalt thou be a Fighter or a Mage?");
+ }
+}
+
+bool CreateCharacter::msgKeypress(const KeypressMessage &msg) {
+ auto &player = g_engine->_player;
+
+ if (_mode == LUCKY_NUMBER || _mode == LEVEL) {
+ if (Common::isDigit(msg.ascii) && _input.size() < 6) {
+ _input += msg.ascii;
+ redraw();
+ } else if (msg.keycode == Common::KEYCODE_BACKSPACE && _input.size() > 0) {
+ _input.deleteLastChar();
+ redraw();
+ }
+ } else if (msg.keycode == Common::KEYCODE_y) {
+ _mode = CLASS;
+ redraw();
+ } else if (msg.keycode == Common::KEYCODE_n) {
+ player.rollAttributes();
+ redraw();
+ } else if (_mode == CLASS && (msg.keycode == Common::KEYCODE_f ||
+ msg.keycode == Common::KEYCODE_m)) {
+ player.Class = toupper(msg.ascii);
+ characterDone();
+ }
+
+ return true;
+}
+
+bool CreateCharacter::msgAction(const ActionMessage &msg) {
+ auto &player = g_engine->_player;
+
+ if (msg._action == KEYBIND_ESCAPE) {
+ replaceView("Title");
+ return true;
+ }
+
+ if (msg._action == KEYBIND_SELECT && !_input.empty()) {
+ if (_mode == LUCKY_NUMBER) {
+ player.LuckyNumber = atoi(_input.c_str());
+ _input.clear();
+ _mode = LEVEL;
+ redraw();
+ } else if (_mode == LEVEL) {
+ player.Level = atoi(_input.c_str());
+ if (player.Level >= 1 && player.Level <= 10) {
+ _input.clear();
+ _mode = STATS;
+ player.rollAttributes();
+ redraw();
+ }
+ }
+ }
+
+ return true;
+}
+
+void CreateCharacter::characterDone() {
+ replaceView("Store");
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/create_character.h b/engines/ultima/ultima0/views/create_character.h
new file mode 100644
index 00000000000..7639e527d9e
--- /dev/null
+++ b/engines/ultima/ultima0/views/create_character.h
@@ -0,0 +1,53 @@
+/* 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 ULTIMA0_VIEWS_CREATE_CHARACTER_H
+#define ULTIMA0_VIEWS_CREATE_CHARACTER_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class CreateCharacter : public View {
+private:
+ enum Mode { LUCKY_NUMBER, LEVEL, STATS, CLASS };
+ Mode _mode = LUCKY_NUMBER;
+ Common::String _input;
+
+ void characterDone();
+
+public:
+ CreateCharacter() : View("CreateCharacter") {}
+ ~CreateCharacter() override {}
+
+ bool msgFocus(const FocusMessage &msg) override;
+ void draw() override;
+ bool msgKeypress(const KeypressMessage &msg) override;
+ bool msgAction(const ActionMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/startup.cpp b/engines/ultima/ultima0/views/startup.cpp
index 1ef96364297..05bf90d9d17 100644
--- a/engines/ultima/ultima0/views/startup.cpp
+++ b/engines/ultima/ultima0/views/startup.cpp
@@ -29,6 +29,7 @@ namespace Views {
void Startup::draw() {
auto s = getSurface();
+ s.clear();
s.writeString(Common::Point(5, 10), "Ultima 0 - Akalabeth!");
s.writeString(Common::Point(2, 19), "Ready?");
}
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index 0a1a6ba49bf..9b69516a80b 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -19,8 +19,6 @@
*
*/
-#include "common/system.h"
-#include "graphics/paletteman.h"
#include "ultima/ultima0/views/title.h"
#include "ultima/ultima0/metaengine.h"
@@ -57,9 +55,11 @@ void Title::updateSelections() {
}
void Title::draw() {
+ auto s = getSurface();
+ s.clear();
+
View::draw();
- auto s = getSurface();
s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
}
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index a27c33a200d..6f46b6a6e63 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -24,12 +24,14 @@
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
+#include "ultima/ultima0/views/create_character.h"
namespace Ultima {
namespace Ultima0 {
namespace Views {
struct Views {
+ CreateCharacter _createCharacter;
Startup _startup;
Title _title;
};
Commit: bae71ae790a0c7437b811c245afd5c5f086c925b
https://github.com/scummvm/scummvm/commit/bae71ae790a0c7437b811c245afd5c5f086c925b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:24+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Town view
Changed paths:
A engines/ultima/ultima0/views/town.cpp
A engines/ultima/ultima0/views/town.h
engines/ultima/module.mk
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/globals.cpp
engines/ultima/ultima0/player.cpp
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/create_character.cpp
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/title.h
engines/ultima/ultima0/views/views.h
engines/ultima/ultima0/world.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index cd152ab2f62..904934e5678 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -34,9 +34,10 @@ MODULE_OBJS += \
ultima0/gfx/font.o \
ultima0/gfx/gfx_surface.o \
ultima0/views/view.o \
+ ultima0/views/create_character.o \
ultima0/views/startup.o \
ultima0/views/title.o \
- ultima0/views/create_character.o
+ ultima0/views/town.o
endif
ifdef ENABLE_ULTIMA1
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index be0488f92b9..afbdffc9834 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -25,16 +25,16 @@
namespace Ultima {
namespace Ultima0 {
-const _OInfStruct _OInfo[] = {
+const _OInfStruct OBJECT_INFO[] = {
{ "Food", 1, 0, 'F' },
{ "Rapier", 8, 10, 'R' },
{ "Axe", 5, 5, 'A' },
{ "Shield", 6, 1, 'S' },
- { "Bow+Arrow", 3, 4, 'B' },
- { "Amulet", 15, 0, 'M' }
+ { "Bow and Arrow", 3, 4, 'B' },
+ { "Magic Amulet", 15, 0, 'M' }
};
-const _MInfStruct _MInfo[] = {
+const _MInfStruct MONSTER_INFO[] = {
{ "Skeleton", 1 },
{ "Thief", 2 },
{ "Giant Rat", 3 },
@@ -47,7 +47,7 @@ const _MInfStruct _MInfo[] = {
{ "Balrog", 10 }
};
-const char *ATTRIB_NAMES[] = { "HP", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
+const char *ATTRIB_NAMES[] = { "Hit Points", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
void PLAYER::init() {
@@ -71,5 +71,46 @@ void PLAYER::rollAttributes() {
Attr[i] = g_engine->getRandomNumber(21) + 4;
}
+/*-------------------------------------------------------------------*/
+
+void WORLDMAP::init(PLAYER &p) {
+ int c, x, y, Size;
+
+ g_engine->setRandomSeed(p.LuckyNumber);
+ Size = MapSize; // Get hard-coded map size
+
+ // Set the boundaries
+ for (x = 0; x <= Size; x++) {
+ Map[Size][x] = WT_MOUNTAIN;
+ Map[0][x] = WT_MOUNTAIN;
+ Map[x][Size] = WT_MOUNTAIN;
+ Map[x][0] = WT_MOUNTAIN;
+ }
+
+ // Set up the map contents
+ for (x = 1; x < Size; x++) {
+ for (y = 1; y < Size; y++) {
+ c = (int)(pow(RND(), 5.0) * 4.5); // Calculate what's there
+ if (c == WT_TOWN && RND() > .5) // Remove half the towns
+ c = WT_SPACE;
+ Map[x][y] = c;
+ }
+ }
+
+ // Calculate player start
+ x = g_engine->getRandomNumber(1, Size - 1);
+ y = g_engine->getRandomNumber(1, Size - 1);
+ p.World.x = x; p.World.y = y; // Save it
+ Map[x][y] = WT_TOWN; // Make it a town
+
+ // Find place for castle
+ do {
+ x = g_engine->getRandomNumber(1, Size - 1);
+ y = g_engine->getRandomNumber(1, Size - 1);
+ } while (Map[x][y] != WT_SPACE);
+
+ Map[x][y] = WT_BRITISH; // Put LBs castle there
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 65939914efd..c5d9cfd35ff 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -30,14 +30,17 @@ namespace Ultima0 {
struct _OInfStruct {
- const char *Name; int Cost; int MaxDamage; char Key;
+ const char *Name;
+ int Cost;
+ int MaxDamage;
+ char Key;
};
struct _MInfStruct {
const char *Name; int Level;
};
-extern const _OInfStruct _OInfo[];
-extern const _MInfStruct _MInfo[];
+extern const _OInfStruct OBJECT_INFO[];
+extern const _MInfStruct MONSTER_INFO[];
extern const char *ATTRIB_NAMES[];
@@ -45,14 +48,6 @@ extern const char *ATTRIB_NAMES[];
typedef Common::Point COORD;
typedef Common::Rect RECT;
-/**
- * World Map structure
- */
-struct WORLDMAP {
- int MapSize = 0; // Size of map
- byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE]; // Map information
-};
-
/**
* Monster structure
*/
@@ -97,6 +92,16 @@ struct PLAYER {
void rollAttributes();
};
+/**
+ * World Map structure
+ */
+struct WORLDMAP {
+ const int MapSize = WORLD_MAP_SIZE - 1; // Size of map
+ byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
+
+ void init(PLAYER &p);
+};
+
} // End of namespace Ultima4
} // End of namespace Ultima
diff --git a/engines/ultima/ultima0/globals.cpp b/engines/ultima/ultima0/globals.cpp
index 4cf6a1b5bd2..8cd977f0343 100644
--- a/engines/ultima/ultima0/globals.cpp
+++ b/engines/ultima/ultima0/globals.cpp
@@ -40,13 +40,13 @@ namespace Ultima0 {
/************************************************************************/
const char *GLOObjName(int n) {
- return _OInfo[n].Name;
+ return OBJECT_INFO[n].Name;
}
void GLOGetInfo(int n, int *pDamage, int *pCost, int *pKey) {
- if (pDamage != nullptr) *pDamage = _OInfo[n].MaxDamage;
- if (pCost != nullptr) *pCost = _OInfo[n].Cost;
- if (pKey != nullptr) *pKey = _OInfo[n].Key;
+ if (pDamage != nullptr) *pDamage = OBJECT_INFO[n].MaxDamage;
+ if (pCost != nullptr) *pCost = OBJECT_INFO[n].Cost;
+ if (pKey != nullptr) *pKey = OBJECT_INFO[n].Key;
}
/************************************************************************/
@@ -70,11 +70,11 @@ const char *GLOClassName(char c) {
}
const char *GLOMonsterName(int n) {
- return _MInfo[n - 1].Name;
+ return MONSTER_INFO[n - 1].Name;
}
int GLOMonsterLevel(int n) {
- return _MInfo[n - 1].Level;
+ return MONSTER_INFO[n - 1].Level;
}
} // namespace Ultima0
diff --git a/engines/ultima/ultima0/player.cpp b/engines/ultima/ultima0/player.cpp
index 8f97b0ea427..d0edd79cca5 100644
--- a/engines/ultima/ultima0/player.cpp
+++ b/engines/ultima/ultima0/player.cpp
@@ -40,20 +40,7 @@ namespace Ultima0 {
/************************************************************************/
void PLAYERInit(PLAYER *p) {
- int i;
- memset(p, 0xFF, sizeof(PLAYER)); /* Fill with character $FF */
- p->Name[0] = '\0';
- p->World.x = p->World.y = 0;
- p->Dungeon.x = p->Dungeon.y = 0;
- p->DungDir.x = p->DungDir.y = 0;
- p->Class = '?';
- p->Level = 0; p->Skill = 0;
- p->Task = 0; p->TaskCompleted = 0;
- p->HPGain = 0;
- p->LuckyNumber = urand(); /* We do the lucky number ! */
-
- for (i = 0; i < p->Attributes; i++) p->Attr[i] = 0;
- for (i = 0; i < p->Objects; i++) p->Object[i] = 0.0;
+ p->init();
}
/************************************************************************/
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 63edbc54301..3bf677c0011 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -38,8 +38,9 @@ static const byte PALETTE[][3] = {
{ 0, 0, 255 },
{ 255, 255, 0 },
{ 0, 255, 255 },
- { 255, 0, 128 },
- { 220, 20, 130 }
+ { 255, 0, 128 }, // Rose
+ { 80, 80, 255 }, // Purple
+ { 220, 20, 130 } // Transparent. Needed?
};
Ultima0Engine *g_engine;
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 1bebcecc4c9..08059e55355 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -45,6 +45,7 @@ protected:
public:
Graphics::Palette _palette;
PLAYER _player;
+ WORLDMAP _worldMap;
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
@@ -74,6 +75,9 @@ public:
* Get a random number
*/
uint getRandomNumber(uint maxVal = RND_MAX) { return _randomSource.getRandomNumber(maxVal); }
+ uint getRandomNumber(uint minVal, uint maxVal) {
+ return _randomSource.getRandomNumber(maxVal - minVal) + minVal;
+ }
/**
* Returns true if enhancements are turned on
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
index cbc27cebad8..d4b405c6f5a 100644
--- a/engines/ultima/ultima0/views/create_character.cpp
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -128,7 +128,11 @@ bool CreateCharacter::msgAction(const ActionMessage &msg) {
}
void CreateCharacter::characterDone() {
- replaceView("Store");
+ // Generate the world map
+ g_engine->_worldMap.init(g_engine->_player);
+
+ // Enter the town
+ replaceView("Town");
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index 9b69516a80b..4bfc6169208 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -26,15 +26,7 @@ namespace Ultima {
namespace Ultima0 {
namespace Views {
-Title::Title() : View("Title"),
- _option0(this, 0, "Introduction", 16),
- _option1(this, 1, "Create a Character", 17),
- _option2(this, 2, "Acknowledgements", 18),
- _option3(this, 3, "Journey Onwards", 19) {
- _options[0] = &_option0;
- _options[1] = &_option1;
- _options[2] = &_option2;
- _options[3] = &_option3;
+Title::Title() : View("Title") {
}
bool Title::msgFocus(const FocusMessage &msg) {
@@ -49,8 +41,8 @@ void Title::updateSelections() {
for (int i = 0; i < 4; ++i) {
auto &opt = _options[i];
- opt->_color = opt->_index == _highlightedOption ? selected : white;
- opt->redraw();
+ opt._color = opt._index == _highlightedOption ? selected : white;
+ opt.redraw();
}
}
diff --git a/engines/ultima/ultima0/views/title.h b/engines/ultima/ultima0/views/title.h
index 2df1b902851..0764c51f568 100644
--- a/engines/ultima/ultima0/views/title.h
+++ b/engines/ultima/ultima0/views/title.h
@@ -41,11 +41,12 @@ class Title : public View {
};
private:
- TitleOption _option0;
- TitleOption _option1;
- TitleOption _option2;
- TitleOption _option3;
- TitleOption *_options[4];
+ TitleOption _options[4] = {
+ TitleOption(this, 0, "Introduction", 16),
+ TitleOption(this, 1, "Create a Character", 17),
+ TitleOption(this, 2, "Acknowledgements", 18),
+ TitleOption(this, 3, "Journey Onwards", 19)
+ };
int _highlightedOption = 0;
void updateSelections();
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
new file mode 100644
index 00000000000..b0d9e8a8c7e
--- /dev/null
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -0,0 +1,193 @@
+/* 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 "ultima/ultima0/views/town.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+static const char *WELCOME = "Welcome to the Adventure Shop";
+static const char *THANK_YOU = "Thank you m'lord";
+static const char *DONT_HAVE_THAT = "I'm Sorry We Don't have that.";
+static const char *NOT_ENOUGH = "M'Lord thou can not afford that item.";
+static const char *MAGES_CANT_USE = "I'm sorry, Mages can't use that.";
+static const char *BYE = "Bye";
+
+Town::Town() : View("Town") {
+}
+
+bool Town::msgFocus(const FocusMessage &msg) {
+ _message = WELCOME;
+ return true;
+}
+
+void Town::draw() {
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+ int i;
+
+ s.clear();
+ View::draw();
+
+ // Stats
+ for (i = 0; i < MAX_ATTR; ++i) {
+ Common::String line = ATTRIB_NAMES[i];
+ while (line.size() < 15)
+ line += '.';
+ s.writeString(Common::Point(0, 4 + i), line);
+ }
+
+ // General message
+ s.writeString(Common::Point(1, 12), _message.empty() ? THANK_YOU : _message);
+ s.writeString(Common::Point(1, 13), "Which item shallt thou buy");
+ _message.clear();
+
+ // Price/Damage/Item
+ for (i = 0; i < MAX_OBJ; ++i) {
+ s.writeString(Common::Point(5, 18 + i),
+ Common::String::format("%d", OBJECT_INFO[i].Cost));
+
+ if (i == 0) {
+ s.writeString(" For 10");
+ s.writeString(Common::Point(15, 18 + i), "N/A");
+ } else if (i == 5) {
+ s.writeString(Common::Point(15, 18 + i), "?????");
+ } else {
+ s.writeString(Common::Point(15, 18 + i),
+ Common::String::format("1-%d", OBJECT_INFO[i].MaxDamage));
+ }
+
+ s.writeString(Common::Point(25, 18 + i), OBJECT_INFO[i].Name);
+ }
+
+ // Headers
+ s.setColor(255, 0, 128);
+ s.writeString(Common::Point(6, 2), "Stat's");
+ s.writeString(Common::Point(21, 2), "Weapons");
+ s.writeString(Common::Point(5, 16), "Price Damage Item");
+
+ // Amounts
+ s.setColor(80, 80, 255);
+ for (i = 0; i < MAX_ATTR; ++i)
+ s.writeString(Common::Point(15, 4 + i),
+ Common::String::format("%d", player.Attr[i]));
+ for (i = 0; i < MAX_OBJ; ++i)
+ s.writeString(Common::Point(22, 4 + i),
+ Common::String::format("%3d-", (int)player.Object[i]));
+ s.writeString(Common::Point(18, 10), "Q-Quit");
+}
+
+bool Town::msgKeypress(const KeypressMessage &msg) {
+ if (isDelayActive())
+ return false;
+
+ for (int i = 0; i < MAX_OBJ; ++i) {
+ if (toupper(msg.ascii) == OBJECT_INFO[i].Key ||
+ (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i].Cost)) {
+ selectObject(i);
+ return true;
+ }
+ }
+
+ if (msg.keycode == Common::KEYCODE_q) {
+ _message = BYE;
+ delaySeconds(1);
+ redraw();
+ }
+
+ return true;
+}
+
+bool Town::msgAction(const ActionMessage &msg) {
+ if (isDelayActive())
+ return false;
+
+ if (msg._action == KEYBIND_ESCAPE) {
+ _message = BYE;
+ delaySeconds(1);
+ redraw();
+ return true;
+ }
+
+ return false;
+}
+
+bool Town::msgGame(const GameMessage &msg) {
+ if (msg._name == "SELECTION") {
+ selectObject(msg._value);
+ return true;
+ }
+
+ return false;
+}
+
+void Town::selectObject(int item) {
+ auto &player = g_engine->_player;
+ const auto &obj = OBJECT_INFO[item];
+
+ // Some things mages can't use
+ if (player.Class == 'M') {
+ if (item == OB_BOW || item == OB_RAPIER) {
+ _message = MAGES_CANT_USE;
+ redraw();
+ return;
+ }
+ }
+
+ if (obj.Cost > player.Attr[AT_GOLD]) {
+ _message = NOT_ENOUGH;
+
+ } else {
+ player.Attr[AT_GOLD] -= obj.Cost; // Lose the money
+ player.Object[item] = MIN<int>(player.Object[item] + (item == OB_FOOD ? 10 : 1), 999);
+ _message = THANK_YOU;
+ }
+
+ redraw();
+}
+
+void Town::timeout() {
+ replaceView("WorldMap");
+}
+
+/*-------------------------------------------------------------------*/
+
+Town::TitleOption::TitleOption(Town *parent, const Common::Point &pt, int id,
+ const Common::String &text) :
+ UIElement("TitleOption", parent), _id(id), _text(text) {
+ setBounds(Gfx::TextRect(pt.x, pt.y, pt.x + text.size(), pt.y));
+}
+
+void Town::TitleOption::draw() {
+ auto s = getSurface();
+ s.writeString(_text);
+}
+
+bool Town::TitleOption::msgMouseDown(const MouseDownMessage &msg) {
+ _parent->send(GameMessage("SELECTION", _id));
+ return true;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/town.h b/engines/ultima/ultima0/views/town.h
new file mode 100644
index 00000000000..445f91c84bf
--- /dev/null
+++ b/engines/ultima/ultima0/views/town.h
@@ -0,0 +1,73 @@
+/* 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 ULTIMA0_VIEWS_TOWN_H
+#define ULTIMA0_VIEWS_TOWN_H
+
+#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/data/data.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Town : public View {
+ class TitleOption : public UIElement {
+ public:
+ Common::String _text;
+ int _id;
+ public:
+ TitleOption(Town *parent, const Common::Point &pt, int id, const Common::String &text);
+ void draw() override;
+ bool msgMouseDown(const MouseDownMessage &msg) override;
+ };
+
+private:
+ TitleOption _options[6] = {
+ TitleOption(this, Common::Point(26, 4), 0, OBJECT_INFO[0].Name),
+ TitleOption(this, Common::Point(26, 5), 1, OBJECT_INFO[1].Name),
+ TitleOption(this, Common::Point(26, 6), 2, OBJECT_INFO[2].Name),
+ TitleOption(this, Common::Point(26, 7), 3, OBJECT_INFO[3].Name),
+ TitleOption(this, Common::Point(26, 8), 4, OBJECT_INFO[4].Name),
+ TitleOption(this, Common::Point(26, 9), 5, OBJECT_INFO[5].Name)
+ };
+ Common::String _message;
+
+ void selectObject(int item);
+
+public:
+ Town();
+ ~Town() override {}
+
+ bool msgFocus(const FocusMessage &msg) override;
+ void draw() override;
+ bool msgKeypress(const KeypressMessage &msg) override;
+ bool msgAction(const ActionMessage &msg) override;
+ bool msgGame(const GameMessage &msg) override;
+ void timeout() override;
+
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 6f46b6a6e63..8339e73c649 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -25,6 +25,7 @@
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
#include "ultima/ultima0/views/create_character.h"
+#include "ultima/ultima0/views/town.h"
namespace Ultima {
namespace Ultima0 {
@@ -34,6 +35,7 @@ struct Views {
CreateCharacter _createCharacter;
Startup _startup;
Title _title;
+ Town _town;
};
} // namespace Views
diff --git a/engines/ultima/ultima0/world.cpp b/engines/ultima/ultima0/world.cpp
index a29a173c82c..611601b33db 100644
--- a/engines/ultima/ultima0/world.cpp
+++ b/engines/ultima/ultima0/world.cpp
@@ -40,40 +40,7 @@ namespace Ultima0 {
/************************************************************************/
void WORLDCreate(PLAYER *p, WORLDMAP *w) {
- int c, x, y, Size;
-
- g_engine->setRandomSeed(p->LuckyNumber); /* Seed the random number */
- Size = MAINSuper() ? WORLD_MAP_SIZE - 1 : 20; /* Calculate map size */
- w->MapSize = Size; /* Save the map size */
-
- // Draw the boundaries
- for (x = 0; x <= Size; x++) {
- w->Map[Size][x] = WT_MOUNTAIN;
- w->Map[0][x] = WT_MOUNTAIN;
- w->Map[x][Size] = WT_MOUNTAIN;
- w->Map[x][0] = WT_MOUNTAIN;
- }
-
- /* Draw the rest of it */
- for (x = 1; x < Size; x++)
- for (y = 1; y < Size; y++) {
- c = (int)(pow(RND(), 5.0) * 4.5); /* Calculate what's there */
- if (c == WT_TOWN && RND() > .5) /* Remove half the towns */
- c = WT_SPACE;
- w->Map[x][y] = c; /* Save in map */
- }
- x = urand() % (Size - 1) + 1; /* Calculate player start */
- y = urand() % (Size - 1) + 1;
- p->World.x = x; p->World.y = y; /* Save it */
- w->Map[x][y] = WT_TOWN; /* Make it a town */
-
- /* Find place for castle */
- do {
- x = urand() % Size + 1;
- y = urand() % Size + 1;
- } while (w->Map[x][y] != WT_SPACE);
-
- w->Map[x][y] = WT_BRITISH; /* Put LBs castle there */
+ w->init(*p);
}
/************************************************************************/
Commit: 6a8d468d24d50b52b359e4b0b2d7060d1813d087
https://github.com/scummvm/scummvm/commit/6a8d468d24d50b52b359e4b0b2d7060d1813d087
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Beginnings of world map rendering
Changed paths:
A engines/ultima/ultima0/gfx/map.cpp
A engines/ultima/ultima0/gfx/map.h
A engines/ultima/ultima0/views/world_map.cpp
A engines/ultima/ultima0/views/world_map.h
engines/ultima/module.mk
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/data/defines.h
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/town.cpp
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 904934e5678..fbf7a0c8eef 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -33,11 +33,13 @@ MODULE_OBJS += \
ultima0/data/data.o \
ultima0/gfx/font.o \
ultima0/gfx/gfx_surface.o \
+ ultima0/gfx/map.o \
ultima0/views/view.o \
ultima0/views/create_character.o \
ultima0/views/startup.o \
ultima0/views/title.o \
- ultima0/views/town.o
+ ultima0/views/town.o \
+ ultima0/views/world_map.o
endif
ifdef ENABLE_ULTIMA1
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index afbdffc9834..c1258d11971 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -112,5 +112,13 @@ void WORLDMAP::init(PLAYER &p) {
Map[x][y] = WT_BRITISH; // Put LBs castle there
}
+int WORLDMAP::read(int x, int y) const {
+ if (x < 0 || y < 0)
+ return WT_MOUNTAIN;
+ if (x >= WORLD_MAP_SIZE || y >= WORLD_MAP_SIZE)
+ return WT_MOUNTAIN;
+ return Map[x][y];
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index c5d9cfd35ff..d965d5c337a 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -100,6 +100,8 @@ struct WORLDMAP {
byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
void init(PLAYER &p);
+
+ int read(int x, int y) const;
};
} // End of namespace Ultima4
diff --git a/engines/ultima/ultima0/data/defines.h b/engines/ultima/ultima0/data/defines.h
index 69741de0e88..96f991cc3a9 100644
--- a/engines/ultima/ultima0/data/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -54,6 +54,7 @@ constexpr int DEFAULT_SCY = 400;
#define C_YELLOW RGB(1,1,0)
#define C_WHITE RGB(1,1,1)
#define C_CYAN RGB(0,1,1)
+#define C_PURPLE RGB(1,0,1)
#define WT_SPACE (0) /* World Tiles */
#define WT_MOUNTAIN (1)
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
new file mode 100644
index 00000000000..4ae173bbafa
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -0,0 +1,142 @@
+/* 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 "ultima/ultima0/gfx/map.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
+ const auto &player = g_engine->_player;
+ const auto &map = g_engine->_worldMap;
+
+ s->clear();
+
+ int x, y, x1, y1, w, h, Grid;
+ Common::Rect r;
+ Grid = showAsMap ? map.MapSize + 1 : (g_engine->isEnhanced() ? 7 : 3);
+ w = s->w / Grid; h = s->h / Grid; // Get grid sizes
+
+ for (x = 0; x < Grid; x++) {
+ for (y = 0; y < Grid; y++) {
+ r = Common::Rect(x * w, y * h, x * w + w - 1, y * h + h - 1);
+
+ if (showAsMap) {
+ // If map, not centred around us
+ x1 = x, y1 = Grid - 1 - y;
+ } else {
+ // Which cell ?
+ x1 = player.World.x - Grid / 2 + x;
+ y1 = player.World.y + Grid / 2 - y;
+ }
+
+ DRAWTile(s, r, map.read(x1, y1));
+
+ // Draw us if we're there
+ if (x1 == player.World.x && y1 == player.World.y)
+ DRAWTile(s, r, WT_PLAYER);
+ }
+ }
+}
+
+#define HWColour(IDX) color = IDX
+#define X(n) (x1 + w * (n)/10)
+#define Y(n) (y1 + h * (n)/10)
+#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
+#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
+
+void Map::DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int Obj) {
+ int x1 = r.left;
+ int y1 = r.top;
+ int w = r.width();
+ int h = r.height();
+ byte color = 0;
+
+ // Decide on the object
+ switch (Obj) {
+ case WT_SPACE:
+ // Space does nothing at all
+ break;
+
+ case WT_MOUNTAIN:
+ // Mountain the cracked effect
+ HWColour(COL_MOUNTAIN);
+ HWLine(X(2), Y(6), X(2), Y(10));
+ HWLine(X(0), Y(8), X(2), Y(8));
+ HWLine(X(2), Y(6), X(4), Y(6));
+ HWLine(X(4), Y(6), X(4), Y(4));
+ HWLine(X(2), Y(2), X(4), Y(4));
+ HWLine(X(2), Y(2), X(2), Y(0));
+ HWLine(X(2), Y(2), X(0), Y(2));
+ HWLine(X(8), Y(4), X(4), Y(4));
+ HWLine(X(8), Y(4), X(8), Y(0));
+ HWLine(X(8), Y(2), X(10), Y(2));
+ HWLine(X(6), Y(4), X(6), Y(8));
+ HWLine(X(10), Y(8), X(6), Y(8));
+ HWLine(X(8), Y(8), X(8), Y(10));
+ break;
+
+ case WT_TREE:
+ // Tree is just a box
+ HWColour(COL_TREE);
+ BOX(3, 3, 7, 7);
+ break;
+
+ case WT_TOWN:
+ // Town is 5 boxes
+ HWColour(COL_TOWN);
+ BOX(2, 2, 4, 4); BOX(4, 4, 6, 6); BOX(6, 6, 8, 8);
+ BOX(6, 2, 8, 4); BOX(2, 6, 4, 8);
+ break;
+
+ case WT_DUNGEON:
+ // Dungeon is a cross
+ HWColour(COL_DUNGEON);
+ HWLine(X(3), Y(3), X(7), Y(7));
+ HWLine(X(7), Y(3), X(3), Y(7));
+ break;
+
+ case WT_BRITISH:
+ // British castle
+ HWColour(COL_BRITISH);
+ HWLine(X(2), Y(2), X(8), Y(8));
+ HWLine(X(8), Y(2), X(2), Y(8));
+ BOX(0, 0, 10, 10);
+ BOX(2, 2, 8, 8);
+ break;
+
+ case WT_PLAYER:
+ // Player
+ HWColour(COL_PLAYER);
+ HWLine(X(4), Y(5), X(6), Y(5));
+ HWLine(X(5), Y(4), X(5), Y(6));
+ break;
+
+ default:
+ break;
+ }
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/map.h b/engines/ultima/ultima0/gfx/map.h
new file mode 100644
index 00000000000..92c570b4a0c
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/map.h
@@ -0,0 +1,43 @@
+/* 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 ULTIMA0_GFX_MAP_H
+#define ULTIMA0_GFX_MAP_H
+
+#include "graphics/managed_surface.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+class Map {
+private:
+ static void DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int Obj);
+
+public:
+ static void draw(Graphics::ManagedSurface *s, bool showAsMap = false);
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 3bf677c0011..f06f1855289 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -30,19 +30,20 @@ namespace Ultima {
namespace Ultima0 {
static const byte PALETTE[][3] = {
- { 0, 0, 0 },
- { 255, 255, 255 },
- { 255, 0, 255 },
- { 255, 0, 0 },
- { 0, 255, 0 },
- { 0, 0, 255 },
- { 255, 255, 0 },
- { 0, 255, 255 },
+ { 0, 0, 0 }, // Black
+ { 0, 0, 255 }, // Blue
+ { 0, 255, 0 }, // Green,
+ { 0, 255, 255 }, // Cyan
+ { 255, 0, 0 }, // Red
+ { 255, 0, 255 }, // Purple
+ { 255, 255, 0 }, // Yellow
+ { 255, 255, 255 }, // White
+
{ 255, 0, 128 }, // Rose
- { 80, 80, 255 }, // Purple
{ 220, 20, 130 } // Transparent. Needed?
};
+
Ultima0Engine *g_engine;
Ultima0Engine::Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc) :
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 08059e55355..b1013d278b0 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -46,6 +46,7 @@ public:
Graphics::Palette _palette;
PLAYER _player;
WORLDMAP _worldMap;
+ DUNGEONMAP _dungeon;
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
index b0d9e8a8c7e..38039d8e88b 100644
--- a/engines/ultima/ultima0/views/town.cpp
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -87,7 +87,7 @@ void Town::draw() {
s.writeString(Common::Point(5, 16), "Price Damage Item");
// Amounts
- s.setColor(80, 80, 255);
+ s.setColor(C_PURPLE);
for (i = 0; i < MAX_ATTR; ++i)
s.writeString(Common::Point(15, 4 + i),
Common::String::format("%d", player.Attr[i]));
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 8339e73c649..4c5c318829e 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -22,10 +22,11 @@
#ifndef ULTIMA0_VIEWS_H
#define ULTIMA0_VIEWS_H
+#include "ultima/ultima0/views/create_character.h"
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
-#include "ultima/ultima0/views/create_character.h"
#include "ultima/ultima0/views/town.h"
+#include "ultima/ultima0/views/world_map.h"
namespace Ultima {
namespace Ultima0 {
@@ -36,6 +37,7 @@ struct Views {
Startup _startup;
Title _title;
Town _town;
+ WorldMap _worldMap;
};
} // namespace Views
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
new file mode 100644
index 00000000000..28661bfcd94
--- /dev/null
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -0,0 +1,48 @@
+/* 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 "ultima/ultima0/views/world_map.h"
+#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/gfx/map.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+WorldMap::WorldMap() : View("WorldMap") {
+}
+
+bool WorldMap::msgFocus(const FocusMessage &msg) {
+ return true;
+}
+
+void WorldMap::draw() {
+ auto s = getSurface();
+ Gfx::Map::draw(&s);
+}
+
+bool WorldMap::msgAction(const ActionMessage &msg) {
+ return true;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
new file mode 100644
index 00000000000..d38621fe772
--- /dev/null
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -0,0 +1,48 @@
+/* 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 ULTIMA0_VIEWS_WORLD_MAP_H
+#define ULTIMA0_VIEWS_WORLD_MAP_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class WorldMap : public View {
+private:
+ void DRAWTile(Gfx::GfxSurface &s, const Common::Rect &r, int Obj);
+
+public:
+ WorldMap();
+ ~WorldMap() override {}
+
+ bool msgFocus(const FocusMessage &msg) override;
+ void draw() override;
+ bool msgAction(const ActionMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
Commit: e439b5c05fd1d1549e435a7022d2763383e77a78
https://github.com/scummvm/scummvm/commit/e439b5c05fd1d1549e435a7022d2763383e77a78
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Added map status display
Changed paths:
A engines/ultima/ultima0/views/status.cpp
A engines/ultima/ultima0/views/status.h
engines/ultima/module.mk
engines/ultima/ultima0/data/defines.h
engines/ultima/ultima0/events.cpp
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/town.cpp
engines/ultima/ultima0/views/world_map.cpp
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index fbf7a0c8eef..cb1557ba862 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -37,6 +37,7 @@ MODULE_OBJS += \
ultima0/views/view.o \
ultima0/views/create_character.o \
ultima0/views/startup.o \
+ ultima0/views/status.o \
ultima0/views/title.o \
ultima0/views/town.o \
ultima0/views/world_map.o
diff --git a/engines/ultima/ultima0/data/defines.h b/engines/ultima/ultima0/data/defines.h
index 96f991cc3a9..ceb9c9b8560 100644
--- a/engines/ultima/ultima0/data/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -55,6 +55,8 @@ constexpr int DEFAULT_SCY = 400;
#define C_WHITE RGB(1,1,1)
#define C_CYAN RGB(0,1,1)
#define C_PURPLE RGB(1,0,1)
+#define C_ROSE 8
+#define C_VIOLET 9
#define WT_SPACE (0) /* World Tiles */
#define WT_MOUNTAIN (1)
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
index 685858956b7..562905f8cf9 100644
--- a/engines/ultima/ultima0/events.cpp
+++ b/engines/ultima/ultima0/events.cpp
@@ -38,24 +38,24 @@ constexpr int CURSOR_H = 20;
static const byte ARROW_CURSOR[CURSOR_W * CURSOR_H] = {
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 0, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 0, 1, 1, 0, 9, 9, 9, 9, 9, 9, 9, 9,
- 0, 1, 1, 1, 0, 9, 9, 9, 9, 9, 9, 9,
- 0, 1, 1, 1, 1, 0, 9, 9, 9, 9, 9, 9,
- 0, 1, 1, 1, 1, 1, 0, 9, 9, 9, 9, 9,
- 0, 1, 1, 1, 1, 1, 1, 0, 9, 9, 9, 9,
- 0, 1, 1, 1, 1, 1, 1, 1, 0, 9, 9, 9,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9, 9,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9,
- 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 0, 1, 1, 0, 9, 9, 9, 9,
- 0, 1, 1, 0, 0, 1, 1, 0, 9, 9, 9, 9,
- 0, 1, 0, 9, 9, 0, 1, 1, 0, 9, 9, 9,
- 0, 0, 9, 9, 9, 0, 1, 1, 0, 9, 9, 9,
- 0, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9, 9,
- 9, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9,
- 9, 9, 9, 9, 9, 9, 9, 0, 1, 1, 0, 9,
+ 0, 7, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 0, 7, 7, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 0, 7, 7, 7, 0, 9, 9, 9, 9, 9, 9, 9,
+ 0, 7, 7, 7, 7, 0, 9, 9, 9, 9, 9, 9,
+ 0, 7, 7, 7, 7, 7, 0, 9, 9, 9, 9, 9,
+ 0, 7, 7, 7, 7, 7, 7, 0, 9, 9, 9, 9,
+ 0, 7, 7, 7, 7, 7, 7, 7, 0, 9, 9, 9,
+ 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 9, 9,
+ 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 9,
+ 0, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0,
+ 0, 7, 7, 7, 0, 7, 7, 0, 9, 9, 9, 9,
+ 0, 7, 7, 0, 0, 7, 7, 0, 9, 9, 9, 9,
+ 0, 7, 0, 9, 9, 0, 7, 7, 0, 9, 9, 9,
+ 0, 0, 9, 9, 9, 0, 7, 7, 0, 9, 9, 9,
+ 0, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9, 9,
+ 9, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9,
+ 9, 9, 9, 9, 9, 9, 9, 0, 7, 7, 0, 9,
9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 9, 9
};
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index f06f1855289..dcac596dcd5 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -38,8 +38,8 @@ static const byte PALETTE[][3] = {
{ 255, 0, 255 }, // Purple
{ 255, 255, 0 }, // Yellow
{ 255, 255, 255 }, // White
-
{ 255, 0, 128 }, // Rose
+ { 80, 80, 255 }, // Violet
{ 220, 20, 130 } // Transparent. Needed?
};
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
new file mode 100644
index 00000000000..07ebaa96c2a
--- /dev/null
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -0,0 +1,54 @@
+/* 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 "ultima/ultima0/views/status.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+Status::Status(const Common::String &name, UIElement *parent) : View(name, parent) {
+ setBounds(Common::Rect(0, DEFAULT_SCY - 4 * Gfx::CHAR_HEIGHT, DEFAULT_SCX, DEFAULT_SCY));
+}
+
+void Status::draw() {
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+ s.clear();
+
+ if (!_message.empty())
+ s.writeString(Common::Point(1, 0), _message);
+ if (!_direction.empty())
+ s.writeString(Common::Point(15, 0), _direction);
+
+ s.writeString(Common::Point(28, 1), "Food=");
+ s.writeString(Common::Point(28, 2), "H.P.=");
+ s.writeString(Common::Point(28, 3), "Gold=");
+ s.setColor(C_VIOLET);
+ s.writeString(Common::Point(33, 1), Common::String::format("%d", (int)player.Object[OB_FOOD]));
+ s.writeString(Common::Point(33, 2), Common::String::format("%d", player.Attr[AT_HP]));
+ s.writeString(Common::Point(33, 3), Common::String::format("%d", player.Attr[AT_GOLD]));
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/status.h b/engines/ultima/ultima0/views/status.h
new file mode 100644
index 00000000000..6076b03564b
--- /dev/null
+++ b/engines/ultima/ultima0/views/status.h
@@ -0,0 +1,47 @@
+/* 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 ULTIMA0_VIEWS_STATUS_H
+#define ULTIMA0_VIEWS_STATUS_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Status : public View {
+private:
+ Common::String _message;
+ Common::String _direction;
+
+public:
+ Status(const Common::String &name, UIElement *parent);
+ ~Status() override {}
+
+ void draw() override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index 4bfc6169208..25df0d6a7f5 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -20,7 +20,7 @@
*/
#include "ultima/ultima0/views/title.h"
-#include "ultima/ultima0/metaengine.h"
+#include "ultima/ultima0/ultima0.h"
namespace Ultima {
namespace Ultima0 {
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
index 38039d8e88b..adf3f1348b9 100644
--- a/engines/ultima/ultima0/views/town.cpp
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -87,7 +87,7 @@ void Town::draw() {
s.writeString(Common::Point(5, 16), "Price Damage Item");
// Amounts
- s.setColor(C_PURPLE);
+ s.setColor(C_VIOLET);
for (i = 0; i < MAX_ATTR; ++i)
s.writeString(Common::Point(15, 4 + i),
Common::String::format("%d", player.Attr[i]));
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 28661bfcd94..0e367964e24 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -21,6 +21,7 @@
#include "ultima/ultima0/views/world_map.h"
#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/gfx/font.h"
#include "ultima/ultima0/gfx/map.h"
namespace Ultima {
@@ -36,7 +37,13 @@ bool WorldMap::msgFocus(const FocusMessage &msg) {
void WorldMap::draw() {
auto s = getSurface();
- Gfx::Map::draw(&s);
+
+ // Draw the map
+ Graphics::ManagedSurface mapArea(s, Common::Rect(0, 0, s.w, s.h - Gfx::CHAR_HEIGHT * 4));
+ Gfx::Map::draw(&mapArea);
+
+ // Allow the status area to draw
+ View::draw();
}
bool WorldMap::msgAction(const ActionMessage &msg) {
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index d38621fe772..75113f8d0d7 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -23,6 +23,7 @@
#define ULTIMA0_VIEWS_WORLD_MAP_H
#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/views/status.h"
namespace Ultima {
namespace Ultima0 {
@@ -30,8 +31,10 @@ namespace Views {
class WorldMap : public View {
private:
- void DRAWTile(Gfx::GfxSurface &s, const Common::Rect &r, int Obj);
+ Status _status = Status("MapStatus", this);
+ void DRAWTile(Gfx::GfxSurface &s, const Common::Rect &r, int Obj);
+
public:
WorldMap();
~WorldMap() override {}
Commit: 3154e69b96003b13d5a4dfa327d17806bbfeb149
https://github.com/scummvm/scummvm/commit/3154e69b96003b13d5a4dfa327d17806bbfeb149
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Adding savegame code
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/events.h
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index c1258d11971..fbb9fe6a72b 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -71,6 +71,28 @@ void PLAYER::rollAttributes() {
Attr[i] = g_engine->getRandomNumber(21) + 4;
}
+void PLAYER::synchronize(Common::Serializer &s) {
+ s.syncBytes((byte *)Name, MAX_NAME + 1);
+ s.syncAsSint16LE(World.x);
+ s.syncAsSint16LE(World.y);
+ s.syncAsSint16LE(Dungeon.x);
+ s.syncAsSint16LE(Dungeon.y);
+ s.syncAsSint16LE(DungDir.x);
+ s.syncAsSint16LE(DungDir.y);
+ s.syncAsByte(Class);
+ s.syncAsSint32LE(HPGain);
+ s.syncAsSint32LE(Level);
+ s.syncAsSint32LE(Skill);
+ s.syncAsSint32LE(Task);
+ s.syncAsSint32LE(TaskCompleted);
+ s.syncAsUint32LE(LuckyNumber);
+
+ for (int i = 0; i < MAX_ATTR; ++i)
+ s.syncAsUint32LE(Attr[i]);
+ for (int i = 0; i < MAX_OBJ; ++i)
+ s.syncAsUint32LE(Object[i]);
+}
+
/*-------------------------------------------------------------------*/
void WORLDMAP::init(PLAYER &p) {
@@ -120,5 +142,10 @@ int WORLDMAP::read(int x, int y) const {
return Map[x][y];
}
+void WORLDMAP::synchronize(Common::Serializer &s) {
+ for (int i = 0; i < WORLD_MAP_SIZE; ++i)
+ s.syncBytes(&Map[i][0], WORLD_MAP_SIZE);
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index d965d5c337a..7fcc7b83ff6 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -23,6 +23,7 @@
#define ULTIMA0_DATA_H
#include "common/rect.h"
+#include "common/serializer.h"
#include "ultima/ultima0/data/defines.h"
namespace Ultima {
@@ -86,10 +87,11 @@ struct PLAYER {
const int Attributes = MAX_ATTR; // Number of attributes
const int Objects = MAX_OBJ; // Number of objects
int Attr[MAX_ATTR] = {}; // Attribute values
- double Object[MAX_OBJ] = {}; // Object counts
+ int Object[MAX_OBJ] = {}; // Object counts
void init();
void rollAttributes();
+ void synchronize(Common::Serializer &s);
};
/**
@@ -100,8 +102,8 @@ struct WORLDMAP {
byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
void init(PLAYER &p);
-
int read(int x, int y) const;
+ void synchronize(Common::Serializer &s);
};
} // End of namespace Ultima4
diff --git a/engines/ultima/ultima0/events.h b/engines/ultima/ultima0/events.h
index ec020f8377d..22ee172ff7c 100644
--- a/engines/ultima/ultima0/events.h
+++ b/engines/ultima/ultima0/events.h
@@ -158,6 +158,13 @@ public:
*/
bool isFocused() const;
+ /**
+ * Returns the view name
+ */
+ Common::String getName() const {
+ return _name;
+ }
+
/**
* Sets the focus to a new view
*/
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index dcac596dcd5..f0da892b380 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -64,5 +64,30 @@ Common::Error Ultima0Engine::run() {
return Common::kNoError;
}
+bool Ultima0Engine::canSaveGameStateCurrently(Common::U32String *msg) {
+ Common::String name = focusedView()->getName();
+ return name == "WorldMap" || name == "Dungeon";
+}
+
+Common::Error Ultima0Engine::loadGameStream(Common::SeekableReadStream *stream) {
+ Common::Serializer s(stream, nullptr);
+ syncSavegame(s);
+
+ replaceView(_player.Level == 0 ? "WorldMap" : "Dungeon");
+
+ return Common::kNoError;
+}
+
+Common::Error Ultima0Engine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
+ Common::Serializer s(nullptr, stream);
+ syncSavegame(s);
+ return Common::kNoError;
+}
+
+void Ultima0Engine::syncSavegame(Common::Serializer &s) {
+ _player.synchronize(s);
+ _worldMap.synchronize(s);
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index b1013d278b0..0a07c9d0301 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -23,6 +23,7 @@
#define ULTIMA0_H
#include "common/random.h"
+#include "common/serializer.h"
#include "graphics/palette.h"
#include "engines/engine.h"
#include "ultima/detection.h"
@@ -35,9 +36,10 @@ namespace Ultima0 {
class Ultima0Engine : public Engine, public Events {
private:
Common::RandomSource _randomSource;
-
const UltimaGameDescription *_gameDescription;
+ void syncSavegame(Common::Serializer &s);
+
protected:
// Engine APIs
Common::Error run() override;
@@ -86,6 +88,33 @@ public:
bool isEnhanced() const {
return true;
}
+
+ /**
+ * Returns true if a savegame can be loaded
+ */
+ bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
+ return true;
+ }
+
+ /**
+ * Returns true if the game can be saved
+ */
+ bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
+
+ /**
+ * Load a game state.
+ * @param stream the stream to load the savestate from
+ * @return returns kNoError on success, else an error code.
+ */
+ Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
+
+ /**
+ * Save a game state.
+ * @param stream The write stream to save the savegame data to
+ * @param isAutosave Expected to be true if an autosave is being created
+ * @return returns kNoError on success, else an error code.
+ */
+ Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
};
extern Ultima0Engine *g_engine;
Commit: eb6b0dc7e9d4403c8b3fc109830f7036bd5eaecb
https://github.com/scummvm/scummvm/commit/eb6b0dc7e9d4403c8b3fc109830f7036bd5eaecb
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Don't set Level field of PLAYER structure
It's Level field is used to determine whether the player is
on the overworld map or on a given dungeon level. As far as
the sources I'm using is concerned, the level you enter when
creating a character doesn't seem to be used.
Changed paths:
engines/ultima/ultima0/views/create_character.cpp
engines/ultima/ultima0/views/create_character.h
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
index d4b405c6f5a..8d5b754912b 100644
--- a/engines/ultima/ultima0/views/create_character.cpp
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -51,7 +51,7 @@ void CreateCharacter::draw() {
if (_mode == LEVEL)
s.writeString(_input);
else
- s.writeString(Common::String::format("%d", player.Level));
+ s.writeString(Common::String::format("%d", _level));
}
// Stats
@@ -114,8 +114,8 @@ bool CreateCharacter::msgAction(const ActionMessage &msg) {
_mode = LEVEL;
redraw();
} else if (_mode == LEVEL) {
- player.Level = atoi(_input.c_str());
- if (player.Level >= 1 && player.Level <= 10) {
+ _level = atoi(_input.c_str());
+ if (_level >= 1 && _level <= 10) {
_input.clear();
_mode = STATS;
player.rollAttributes();
diff --git a/engines/ultima/ultima0/views/create_character.h b/engines/ultima/ultima0/views/create_character.h
index 7639e527d9e..cb45054cf0a 100644
--- a/engines/ultima/ultima0/views/create_character.h
+++ b/engines/ultima/ultima0/views/create_character.h
@@ -33,6 +33,7 @@ private:
enum Mode { LUCKY_NUMBER, LEVEL, STATS, CLASS };
Mode _mode = LUCKY_NUMBER;
Common::String _input;
+ int _level = 0;
void characterDone();
Commit: 04b4a943368ad1c8c04c3901d8f547cf1310656f
https://github.com/scummvm/scummvm/commit/04b4a943368ad1c8c04c3901d8f547cf1310656f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Further savegame code
Changed paths:
engines/ultima/ultima0/events.cpp
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
diff --git a/engines/ultima/ultima0/events.cpp b/engines/ultima/ultima0/events.cpp
index 562905f8cf9..39829d78453 100644
--- a/engines/ultima/ultima0/events.cpp
+++ b/engines/ultima/ultima0/events.cpp
@@ -76,10 +76,9 @@ void Events::runGame() {
// Run the game
int saveSlot = ConfMan.getInt("save_slot");
- if (saveSlot != -1)
- g_engine->loadGameState(saveSlot);
-
- addView("Title");
+ if (saveSlot == -1 || g_engine->loadGameState(saveSlot).getCode() != Common::kNoError)
+ // Except when loading a savegame from the launcher, default to first screen
+ addView("Startup");
Common::Event e;
while (!_views.empty() && !shouldQuit()) {
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index f0da892b380..742c6eea2be 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -64,7 +64,18 @@ Common::Error Ultima0Engine::run() {
return Common::kNoError;
}
+bool Ultima0Engine::hasFeature(EngineFeature f) const {
+ return (f == kSupportsReturnToLauncher) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+
+}
+
bool Ultima0Engine::canSaveGameStateCurrently(Common::U32String *msg) {
+ auto *view = focusedView();
+ if (!view)
+ return false;
+
Common::String name = focusedView()->getName();
return name == "WorldMap" || name == "Dungeon";
}
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 0a07c9d0301..198d9bc9f0f 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -63,9 +63,7 @@ public:
/**
* Returns supported engine features
*/
- bool hasFeature(EngineFeature f) const override {
- return (f == kSupportsReturnToLauncher);
- }
+ bool hasFeature(EngineFeature f) const override;
/**
* Sets the random number seed
Commit: db6bb3ef1ed2a43aa1197f18dd532ecc6edbf196
https://github.com/scummvm/scummvm/commit/db6bb3ef1ed2a43aa1197f18dd532ecc6edbf196
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Starting on world map commands
Changed paths:
engines/ultima/ultima0/views/world_map.cpp
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 0e367964e24..f873d22831b 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/system.h"
#include "ultima/ultima0/views/world_map.h"
#include "ultima/ultima0/ultima0.h"
#include "ultima/ultima0/gfx/font.h"
@@ -50,6 +51,15 @@ bool WorldMap::msgAction(const ActionMessage &msg) {
return true;
}
+bool WorldMap::msgKeypress(const KeypressMessage &msg) {
+ switch (msg.keycode) {
+ case Common::KEYCODE_q:
+ // "Quit" in the original which merely saves the game. For ScummVM,
+ // we open the GMM, allowing the user to either save or quit
+ break;
+ }
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index 75113f8d0d7..d3a24522252 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -42,6 +42,7 @@ public:
bool msgFocus(const FocusMessage &msg) override;
void draw() override;
bool msgAction(const ActionMessage &msg) override;
+ bool msgKeypress(const KeypressMessage &msg) override;
};
} // namespace Views
Commit: 3445ec9302187b67212346d08a2d3675b6bea96a
https://github.com/scummvm/scummvm/commit/3445ec9302187b67212346d08a2d3675b6bea96a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:25+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Info screen
Changed paths:
A engines/ultima/ultima0/views/info.cpp
A engines/ultima/ultima0/views/info.h
engines/ultima/module.mk
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/metaengine.h
engines/ultima/ultima0/views/town.cpp
engines/ultima/ultima0/views/town.h
engines/ultima/ultima0/views/views.h
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index cb1557ba862..270926fc87b 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -36,6 +36,7 @@ MODULE_OBJS += \
ultima0/gfx/map.o \
ultima0/views/view.o \
ultima0/views/create_character.o \
+ ultima0/views/info.o \
ultima0/views/startup.o \
ultima0/views/status.o \
ultima0/views/title.o \
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index d63aa3ecd71..50dd671f860 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -32,20 +32,20 @@ struct KeybindingRecord {
KeybindingAction _action;
const char *_id;
const char *_desc;
- const char *_method;
const char *_key;
const char *_joy;
};
static const KeybindingRecord NORMAL_KEYS[] = {
- { KEYBIND_SELECT, "INTERACT", _s("Interact"), "select", "RETURN", nullptr },
- { KEYBIND_ESCAPE, "ESCAPE", _s("Abort action"), "", "ESCAPE", nullptr },
- { KEYBIND_UP, "UP", _s("Up"), "move up", "UP", nullptr },
- { KEYBIND_DOWN, "DOWN", _s("Down"), "move down", "DOWN", nullptr },
- { KEYBIND_LEFT, "LEFT", _s("Left"), "move left", "LEFT", nullptr },
- { KEYBIND_RIGHT, "RIGHT", _s("Right"), "move right", "RIGHT", nullptr },
-
- { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr }
+ { KEYBIND_SELECT, "INTERACT", _s("Interact"), "RETURN", "JOY_A" },
+ { KEYBIND_ESCAPE, "ESCAPE", _s("Escape"), "ESCAPE", "JOY_B" },
+ { KEYBIND_UP, "UP", _s("Up/Forward"), "UP", "JOY_UP" },
+ { KEYBIND_DOWN, "DOWN", _s("Down/Backwards"), "DOWN", "JOY_DOWN" },
+ { KEYBIND_LEFT, "LEFT", _s("Left"), "LEFT", "JOY_LEFT" },
+ { KEYBIND_RIGHT, "RIGHT", _s("Right"), "RIGHT", "JOY_RIGHT" },
+ { KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_Y" },
+
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
struct KeysRecord {
@@ -124,16 +124,5 @@ void MetaEngine::setKeybindingMode(KeybindingMode mode) {
mapper->addGameKeymap(arr[idx]);
}
-Common::String MetaEngine::getMethod(KeybindingAction keyAction) {
- for (int kCtr = 0; kCtr < 4; ++kCtr) {
- for (const KeybindingRecord *r = NORMAL_RECORDS[kCtr]._keys; r->_id; ++r) {
- if (r->_action == keyAction)
- return r->_method;
- }
- }
-
- return Common::String();
-}
-
} // End of namespace Ultima0
} // End of namespace Ultima
diff --git a/engines/ultima/ultima0/metaengine.h b/engines/ultima/ultima0/metaengine.h
index 0dac9e7faaf..699c769cc7e 100644
--- a/engines/ultima/ultima0/metaengine.h
+++ b/engines/ultima/ultima0/metaengine.h
@@ -29,7 +29,7 @@ namespace Ultima0 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
- KEYBIND_SELECT, KEYBIND_ESCAPE,
+ KEYBIND_SELECT, KEYBIND_ESCAPE, KEYBIND_INFO,
KEYBIND_NONE
};
@@ -40,11 +40,6 @@ enum KeybindingMode {
class MetaEngine {
private:
- /**
- * Get the method to execute
- */
- static Common::String getMethod(KeybindingAction keyAction);
-
/**
* Adds the default actions for the mouse buttons
*/
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
new file mode 100644
index 00000000000..5a0ef223215
--- /dev/null
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -0,0 +1,148 @@
+/* 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 "ultima/ultima0/views/info.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+Info::Info(const char *viewName) : View(viewName) {
+}
+
+void Info::draw() {
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+ int i;
+
+ s.clear();
+ View::draw();
+
+ // Stats
+ for (i = 0; i < MAX_ATTR; ++i) {
+ Common::String line = ATTRIB_NAMES[i];
+ while (line.size() < 15)
+ line += '.';
+ s.writeString(Common::Point(0, 4 + i), line);
+ }
+
+ // Price/Damage/Item
+ for (i = 0; i < MAX_OBJ; ++i) {
+ s.writeString(Common::Point(5, 18 + i),
+ Common::String::format("%d", OBJECT_INFO[i].Cost));
+
+ if (i == 0) {
+ s.writeString(" For 10");
+ s.writeString(Common::Point(15, 18 + i), "N/A");
+ } else if (i == 5) {
+ s.writeString(Common::Point(15, 18 + i), "?????");
+ } else {
+ s.writeString(Common::Point(15, 18 + i),
+ Common::String::format("1-%d", OBJECT_INFO[i].MaxDamage));
+ }
+
+ s.writeString(Common::Point(25, 18 + i), OBJECT_INFO[i].Name);
+ }
+
+ // Headers
+ s.setColor(255, 0, 128);
+ s.writeString(Common::Point(6, 2), "Stat's");
+ s.writeString(Common::Point(21, 2), "Weapons");
+ s.writeString(Common::Point(5, 16), "Price Damage Item");
+
+ // Amounts
+ s.setColor(C_VIOLET);
+ for (i = 0; i < MAX_ATTR; ++i)
+ s.writeString(Common::Point(15, 4 + i),
+ Common::String::format("%d", player.Attr[i]));
+ for (i = 0; i < MAX_OBJ; ++i)
+ s.writeString(Common::Point(22, 4 + i),
+ Common::String::format("%3d-", (int)player.Object[i]));
+ s.writeString(Common::Point(18, 10), "Q-Quit");
+}
+
+bool Info::msgKeypress(const KeypressMessage &msg) {
+ if (isDelayActive())
+ return false;
+
+ for (int i = 0; i < MAX_OBJ; ++i) {
+ if (toupper(msg.ascii) == OBJECT_INFO[i].Key ||
+ (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i].Cost)) {
+ selectObject(i);
+ return true;
+ }
+ }
+
+ if (msg.keycode == Common::KEYCODE_q) {
+ leave();
+ return true;
+ }
+
+ return false;
+}
+
+void Info::leave() {
+ replaceView("WorldMap");
+}
+
+bool Info::msgAction(const ActionMessage &msg) {
+ if (isDelayActive())
+ return false;
+
+ if (msg._action == KEYBIND_ESCAPE) {
+ leave();
+ return true;
+ }
+
+ return false;
+}
+
+bool Info::msgGame(const GameMessage &msg) {
+ if (msg._name == "SELECTION") {
+ selectObject(msg._value);
+ return true;
+ }
+
+ return false;
+}
+
+/*-------------------------------------------------------------------*/
+
+Info::InfoObject::InfoObject(Info *parent, const Common::Point &pt, int id,
+ const Common::String &text) :
+ UIElement("InfoObject", parent), _id(id), _text(text) {
+ setBounds(Gfx::TextRect(pt.x, pt.y, pt.x + text.size(), pt.y));
+}
+
+void Info::InfoObject::draw() {
+ auto s = getSurface();
+ s.writeString(_text);
+}
+
+bool Info::InfoObject::msgMouseDown(const MouseDownMessage &msg) {
+ _parent->send(GameMessage("SELECTION", _id));
+ return true;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/info.h b/engines/ultima/ultima0/views/info.h
new file mode 100644
index 00000000000..72b7411c89a
--- /dev/null
+++ b/engines/ultima/ultima0/views/info.h
@@ -0,0 +1,72 @@
+/* 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 ULTIMA0_VIEWS_INFO_H
+#define ULTIMA0_VIEWS_INFO_H
+
+#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/data/data.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Info : public View {
+ class InfoObject : public UIElement {
+ public:
+ Common::String _text;
+ int _id;
+ public:
+ InfoObject(Info *parent, const Common::Point &pt, int id, const Common::String &text);
+ void draw() override;
+ bool msgMouseDown(const MouseDownMessage &msg) override;
+ };
+
+private:
+ InfoObject _options[6] = {
+ InfoObject(this, Common::Point(26, 4), 0, OBJECT_INFO[0].Name),
+ InfoObject(this, Common::Point(26, 5), 1, OBJECT_INFO[1].Name),
+ InfoObject(this, Common::Point(26, 6), 2, OBJECT_INFO[2].Name),
+ InfoObject(this, Common::Point(26, 7), 3, OBJECT_INFO[3].Name),
+ InfoObject(this, Common::Point(26, 8), 4, OBJECT_INFO[4].Name),
+ InfoObject(this, Common::Point(26, 9), 5, OBJECT_INFO[5].Name)
+ };
+
+protected:
+ virtual void selectObject(int item) {
+ }
+ virtual void leave();
+
+public:
+ Info(const char *viewName = "Info");
+ ~Info() override {}
+
+ void draw() override;
+ bool msgKeypress(const KeypressMessage &msg) override;
+ bool msgAction(const ActionMessage &msg) override;
+ bool msgGame(const GameMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
index adf3f1348b9..2aa54c189d1 100644
--- a/engines/ultima/ultima0/views/town.cpp
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -33,7 +33,7 @@ static const char *NOT_ENOUGH = "M'Lord thou can not afford that item.";
static const char *MAGES_CANT_USE = "I'm sorry, Mages can't use that.";
static const char *BYE = "Bye";
-Town::Town() : View("Town") {
+Town::Town() : Info("Town") {
}
bool Town::msgFocus(const FocusMessage &msg) {
@@ -42,103 +42,13 @@ bool Town::msgFocus(const FocusMessage &msg) {
}
void Town::draw() {
- const auto &player = g_engine->_player;
- auto s = getSurface();
- int i;
-
- s.clear();
- View::draw();
-
- // Stats
- for (i = 0; i < MAX_ATTR; ++i) {
- Common::String line = ATTRIB_NAMES[i];
- while (line.size() < 15)
- line += '.';
- s.writeString(Common::Point(0, 4 + i), line);
- }
+ Info::draw();
// General message
+ auto s = getSurface();
s.writeString(Common::Point(1, 12), _message.empty() ? THANK_YOU : _message);
s.writeString(Common::Point(1, 13), "Which item shallt thou buy");
_message.clear();
-
- // Price/Damage/Item
- for (i = 0; i < MAX_OBJ; ++i) {
- s.writeString(Common::Point(5, 18 + i),
- Common::String::format("%d", OBJECT_INFO[i].Cost));
-
- if (i == 0) {
- s.writeString(" For 10");
- s.writeString(Common::Point(15, 18 + i), "N/A");
- } else if (i == 5) {
- s.writeString(Common::Point(15, 18 + i), "?????");
- } else {
- s.writeString(Common::Point(15, 18 + i),
- Common::String::format("1-%d", OBJECT_INFO[i].MaxDamage));
- }
-
- s.writeString(Common::Point(25, 18 + i), OBJECT_INFO[i].Name);
- }
-
- // Headers
- s.setColor(255, 0, 128);
- s.writeString(Common::Point(6, 2), "Stat's");
- s.writeString(Common::Point(21, 2), "Weapons");
- s.writeString(Common::Point(5, 16), "Price Damage Item");
-
- // Amounts
- s.setColor(C_VIOLET);
- for (i = 0; i < MAX_ATTR; ++i)
- s.writeString(Common::Point(15, 4 + i),
- Common::String::format("%d", player.Attr[i]));
- for (i = 0; i < MAX_OBJ; ++i)
- s.writeString(Common::Point(22, 4 + i),
- Common::String::format("%3d-", (int)player.Object[i]));
- s.writeString(Common::Point(18, 10), "Q-Quit");
-}
-
-bool Town::msgKeypress(const KeypressMessage &msg) {
- if (isDelayActive())
- return false;
-
- for (int i = 0; i < MAX_OBJ; ++i) {
- if (toupper(msg.ascii) == OBJECT_INFO[i].Key ||
- (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i].Cost)) {
- selectObject(i);
- return true;
- }
- }
-
- if (msg.keycode == Common::KEYCODE_q) {
- _message = BYE;
- delaySeconds(1);
- redraw();
- }
-
- return true;
-}
-
-bool Town::msgAction(const ActionMessage &msg) {
- if (isDelayActive())
- return false;
-
- if (msg._action == KEYBIND_ESCAPE) {
- _message = BYE;
- delaySeconds(1);
- redraw();
- return true;
- }
-
- return false;
-}
-
-bool Town::msgGame(const GameMessage &msg) {
- if (msg._name == "SELECTION") {
- selectObject(msg._value);
- return true;
- }
-
- return false;
}
void Town::selectObject(int item) {
@@ -166,26 +76,14 @@ void Town::selectObject(int item) {
redraw();
}
-void Town::timeout() {
- replaceView("WorldMap");
-}
-
-/*-------------------------------------------------------------------*/
-
-Town::TitleOption::TitleOption(Town *parent, const Common::Point &pt, int id,
- const Common::String &text) :
- UIElement("TitleOption", parent), _id(id), _text(text) {
- setBounds(Gfx::TextRect(pt.x, pt.y, pt.x + text.size(), pt.y));
-}
-
-void Town::TitleOption::draw() {
- auto s = getSurface();
- s.writeString(_text);
+void Town::leave() {
+ _message = BYE;
+ delaySeconds(1);
+ redraw();
}
-bool Town::TitleOption::msgMouseDown(const MouseDownMessage &msg) {
- _parent->send(GameMessage("SELECTION", _id));
- return true;
+void Town::timeout() {
+ replaceView("WorldMap");
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/town.h b/engines/ultima/ultima0/views/town.h
index 445f91c84bf..f263bf0fa22 100644
--- a/engines/ultima/ultima0/views/town.h
+++ b/engines/ultima/ultima0/views/town.h
@@ -22,36 +22,20 @@
#ifndef ULTIMA0_VIEWS_TOWN_H
#define ULTIMA0_VIEWS_TOWN_H
-#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/views/info.h"
#include "ultima/ultima0/data/data.h"
namespace Ultima {
namespace Ultima0 {
namespace Views {
-class Town : public View {
- class TitleOption : public UIElement {
- public:
- Common::String _text;
- int _id;
- public:
- TitleOption(Town *parent, const Common::Point &pt, int id, const Common::String &text);
- void draw() override;
- bool msgMouseDown(const MouseDownMessage &msg) override;
- };
-
+class Town : public Info {
private:
- TitleOption _options[6] = {
- TitleOption(this, Common::Point(26, 4), 0, OBJECT_INFO[0].Name),
- TitleOption(this, Common::Point(26, 5), 1, OBJECT_INFO[1].Name),
- TitleOption(this, Common::Point(26, 6), 2, OBJECT_INFO[2].Name),
- TitleOption(this, Common::Point(26, 7), 3, OBJECT_INFO[3].Name),
- TitleOption(this, Common::Point(26, 8), 4, OBJECT_INFO[4].Name),
- TitleOption(this, Common::Point(26, 9), 5, OBJECT_INFO[5].Name)
- };
Common::String _message;
- void selectObject(int item);
+protected:
+ void selectObject(int item) override;
+ void leave() override;
public:
Town();
@@ -59,11 +43,7 @@ public:
bool msgFocus(const FocusMessage &msg) override;
void draw() override;
- bool msgKeypress(const KeypressMessage &msg) override;
- bool msgAction(const ActionMessage &msg) override;
- bool msgGame(const GameMessage &msg) override;
void timeout() override;
-
};
} // namespace Views
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 4c5c318829e..cb83372ebb7 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -23,6 +23,7 @@
#define ULTIMA0_VIEWS_H
#include "ultima/ultima0/views/create_character.h"
+#include "ultima/ultima0/views/info.h"
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
#include "ultima/ultima0/views/town.h"
@@ -34,6 +35,7 @@ namespace Views {
struct Views {
CreateCharacter _createCharacter;
+ Info _info;
Startup _startup;
Title _title;
Town _town;
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index f873d22831b..ba1dfdbd8d3 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -19,7 +19,6 @@
*
*/
-#include "common/system.h"
#include "ultima/ultima0/views/world_map.h"
#include "ultima/ultima0/ultima0.h"
#include "ultima/ultima0/gfx/font.h"
@@ -48,6 +47,13 @@ void WorldMap::draw() {
}
bool WorldMap::msgAction(const ActionMessage &msg) {
+ switch (msg._action) {
+ case KEYBIND_INFO:
+ // Show character info screen
+ replaceView("Info");
+ break;
+ }
+
return true;
}
@@ -56,8 +62,14 @@ bool WorldMap::msgKeypress(const KeypressMessage &msg) {
case Common::KEYCODE_q:
// "Quit" in the original which merely saves the game. For ScummVM,
// we open the GMM, allowing the user to either save or quit
+ g_engine->openMainMenuDialog();
+ break;
+
+ default:
break;
}
+
+ return true;
}
} // namespace Views
Commit: b65aac6c3074ff0115f1ce29664bfe27b600a384
https://github.com/scummvm/scummvm/commit/b65aac6c3074ff0115f1ce29664bfe27b600a384
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:26+11:00
Commit Message:
ULTIMA: ULTIMA0: More keybindings setup
Changed paths:
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/metaengine.h
engines/ultima/ultima0/views/world_map.cpp
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index 50dd671f860..857d71c1e24 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -37,13 +37,14 @@ struct KeybindingRecord {
};
static const KeybindingRecord NORMAL_KEYS[] = {
- { KEYBIND_SELECT, "INTERACT", _s("Interact"), "RETURN", "JOY_A" },
- { KEYBIND_ESCAPE, "ESCAPE", _s("Escape"), "ESCAPE", "JOY_B" },
{ KEYBIND_UP, "UP", _s("Up/Forward"), "UP", "JOY_UP" },
{ KEYBIND_DOWN, "DOWN", _s("Down/Backwards"), "DOWN", "JOY_DOWN" },
{ KEYBIND_LEFT, "LEFT", _s("Left"), "LEFT", "JOY_LEFT" },
{ KEYBIND_RIGHT, "RIGHT", _s("Right"), "RIGHT", "JOY_RIGHT" },
- { KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_Y" },
+ { KEYBIND_SELECT, "INTERACT", _s("Interact"), "RETURN", "JOY_A" },
+ { KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
+ { KEYBIND_ESCAPE, "ESCAPE", _s("Escape"), "ESCAPE", "JOY_Y" },
+ { KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
@@ -86,6 +87,9 @@ Common::KeymapArray MetaEngine::initKeymaps(KeybindingMode mode) {
act->addDefaultInputMapping(r->_key);
if (r->_joy)
act->addDefaultInputMapping(r->_joy);
+ if (r->_action == KEYBIND_ENTER)
+ act->addDefaultInputMapping("x");
+
if (r->_action == KEYBIND_UP || r->_action == KEYBIND_DOWN ||
r->_action == KEYBIND_LEFT || r->_action == KEYBIND_RIGHT)
// Allow movement actions to be triggered on keyboard repeats
diff --git a/engines/ultima/ultima0/metaengine.h b/engines/ultima/ultima0/metaengine.h
index 699c769cc7e..9291745ac21 100644
--- a/engines/ultima/ultima0/metaengine.h
+++ b/engines/ultima/ultima0/metaengine.h
@@ -29,7 +29,7 @@ namespace Ultima0 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
- KEYBIND_SELECT, KEYBIND_ESCAPE, KEYBIND_INFO,
+ KEYBIND_SELECT, KEYBIND_ESCAPE, KEYBIND_ENTER, KEYBIND_INFO,
KEYBIND_NONE
};
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index ba1dfdbd8d3..1957524498b 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -72,6 +72,10 @@ bool WorldMap::msgKeypress(const KeypressMessage &msg) {
return true;
}
+void WorldMap::endOfTurn() {
+ // TODO
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index d3a24522252..496d4d63be2 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -33,8 +33,8 @@ class WorldMap : public View {
private:
Status _status = Status("MapStatus", this);
- void DRAWTile(Gfx::GfxSurface &s, const Common::Rect &r, int Obj);
-
+ void endOfTurn();
+
public:
WorldMap();
~WorldMap() override {}
Commit: 7dd069ed7d8357995e711dbb326cf23a680f0ca7
https://github.com/scummvm/scummvm/commit/7dd069ed7d8357995e711dbb326cf23a680f0ca7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:26+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Dead view
Changed paths:
A engines/ultima/ultima0/console.cpp
A engines/ultima/ultima0/console.h
A engines/ultima/ultima0/views/dead.cpp
A engines/ultima/ultima0/views/dead.h
engines/ultima/module.mk
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/startup.cpp
engines/ultima/ultima0/views/views.h
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 270926fc87b..868f8443ebe 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -9,6 +9,7 @@ MODULE_OBJS := \
ifdef ENABLE_AKALABETH
MODULE_OBJS += \
ultima0/ultima0.o \
+ ultima0/console.o \
ultima0/events.o \
ultima0/messages.o \
ultima0/metaengine.o \
diff --git a/engines/ultima/ultima0/console.cpp b/engines/ultima/ultima0/console.cpp
new file mode 100644
index 00000000000..d9a838f4513
--- /dev/null
+++ b/engines/ultima/ultima0/console.cpp
@@ -0,0 +1,46 @@
+/* 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 "ultima/ultima0/console.h"
+#include "ultima/ultima0/events.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+Console::Console() : GUI::Debugger() {
+ registerCmd("view", WRAP_METHOD(Console, cmdView));
+}
+
+Console::~Console() {
+}
+
+bool Console::cmdView(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("view <view name>\n");
+ return true;
+ } else {
+ g_events->replaceView(argv[1]);
+ return false;
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/console.h b/engines/ultima/ultima0/console.h
new file mode 100644
index 00000000000..9fba8bf0af6
--- /dev/null
+++ b/engines/ultima/ultima0/console.h
@@ -0,0 +1,42 @@
+
+/* 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 ULTIMA_ULTIMA0_CONSOLE_H
+#define ULTIMA_ULTIMA0_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+class Console : public GUI::Debugger {
+private:
+ bool cmdView(int argc, const char **argv);
+public:
+ Console();
+ ~Console() override;
+};
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 742c6eea2be..5cc7aee1ec9 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -23,6 +23,7 @@
#include "graphics/paletteman.h"
#include "ultima/ultima0/sdw.h"
#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/console.h"
#include "ultima/ultima0/akalabeth.h"
#include "ultima/ultima0/sdw.h"
@@ -56,9 +57,14 @@ Ultima0Engine::~Ultima0Engine() {
}
Common::Error Ultima0Engine::run() {
+ // Initialize the graphics
initGraphics(DEFAULT_SCX, DEFAULT_SCY);
g_system->getPaletteManager()->setPalette(_palette);
+ // Set the debugger console
+ setDebugger(new Console());
+
+ // Play the game
runGame();
return Common::kNoError;
diff --git a/engines/ultima/ultima0/views/dead.cpp b/engines/ultima/ultima0/views/dead.cpp
new file mode 100644
index 00000000000..181167dfaea
--- /dev/null
+++ b/engines/ultima/ultima0/views/dead.cpp
@@ -0,0 +1,51 @@
+/* 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 "ultima/ultima0/views/dead.h"
+#include "ultima/ultima0/gfx/font.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+Dead::Dead() : View("Dead") {
+ setBounds(Common::Rect(0, DEFAULT_SCY - 4 * Gfx::CHAR_HEIGHT, DEFAULT_SCX, DEFAULT_SCY));
+}
+
+void Dead::draw() {
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+ s.clear();
+
+ const char *name = player.Name;
+ if (*name == '\0')
+ name = "the peasant";
+
+ s.writeString(Common::Point(20, 0), "We mourn the passing of", Graphics::kTextAlignCenter);
+ s.writeString(Common::Point(20, 1), Common::String::format("%s and his Computer", name), Graphics::kTextAlignCenter);
+ s.writeString(Common::Point(20, 2), "To invoke a miracle of resurrection", Graphics::kTextAlignCenter);
+ s.writeString(Common::Point(20, 3), "Press a Key", Graphics::kTextAlignCenter);
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/dead.h b/engines/ultima/ultima0/views/dead.h
new file mode 100644
index 00000000000..fc896335998
--- /dev/null
+++ b/engines/ultima/ultima0/views/dead.h
@@ -0,0 +1,60 @@
+/* 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 ULTIMA0_VIEWS_DEAD_H
+#define ULTIMA0_VIEWS_DEAD_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Dead : public View {
+private:
+ void showTitle() {
+ replaceView("Title");
+ }
+public:
+ Dead();
+ ~Dead() override {}
+
+ void draw() override;
+
+ bool msgKeypress(const KeypressMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgMouseDown(const MouseDownMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgAction(const ActionMessage &msg) override {
+ showTitle();
+ return true;
+ }
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/startup.cpp b/engines/ultima/ultima0/views/startup.cpp
index 05bf90d9d17..8879a92ac8f 100644
--- a/engines/ultima/ultima0/views/startup.cpp
+++ b/engines/ultima/ultima0/views/startup.cpp
@@ -19,8 +19,6 @@
*
*/
-#include "common/system.h"
-#include "graphics/paletteman.h"
#include "ultima/ultima0/views/startup.h"
namespace Ultima {
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index cb83372ebb7..268a0662011 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -23,6 +23,7 @@
#define ULTIMA0_VIEWS_H
#include "ultima/ultima0/views/create_character.h"
+#include "ultima/ultima0/views/dead.h"
#include "ultima/ultima0/views/info.h"
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
@@ -35,6 +36,7 @@ namespace Views {
struct Views {
CreateCharacter _createCharacter;
+ Dead _dead;
Info _info;
Startup _startup;
Title _title;
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 1957524498b..b8674011da6 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -73,7 +73,10 @@ bool WorldMap::msgKeypress(const KeypressMessage &msg) {
}
void WorldMap::endOfTurn() {
- // TODO
+ auto &player = g_engine->_player;
+
+ if (player.Attr[AT_HP] <= 0)
+ replaceView("Dead");
}
} // namespace Views
Commit: 49b282d50c639bdadde6c3ae66396847365c53e0
https://github.com/scummvm/scummvm/commit/49b282d50c639bdadde6c3ae66396847365c53e0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:26+11:00
Commit Message:
ULTIMA: ULTIMA0: Adding overworld movement
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/gfx/map.cpp
engines/ultima/ultima0/views/status.cpp
engines/ultima/ultima0/views/status.h
engines/ultima/ultima0/views/world_map.cpp
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index fbb9fe6a72b..86e04b08f78 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -89,8 +89,12 @@ void PLAYER::synchronize(Common::Serializer &s) {
for (int i = 0; i < MAX_ATTR; ++i)
s.syncAsUint32LE(Attr[i]);
- for (int i = 0; i < MAX_OBJ; ++i)
- s.syncAsUint32LE(Object[i]);
+ for (int i = 0; i < MAX_OBJ; ++i) {
+ uint32 val = (uint32)Object[i];
+ s.syncAsUint32LE(val);
+ if (s.isLoading())
+ Object[i] = (double)val;
+ }
}
/*-------------------------------------------------------------------*/
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 7fcc7b83ff6..9095680c59a 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -87,7 +87,7 @@ struct PLAYER {
const int Attributes = MAX_ATTR; // Number of attributes
const int Objects = MAX_OBJ; // Number of objects
int Attr[MAX_ATTR] = {}; // Attribute values
- int Object[MAX_OBJ] = {}; // Object counts
+ double Object[MAX_OBJ] = {}; // Object counts
void init();
void rollAttributes();
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
index 4ae173bbafa..b06333e9d92 100644
--- a/engines/ultima/ultima0/gfx/map.cpp
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -42,12 +42,12 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
r = Common::Rect(x * w, y * h, x * w + w - 1, y * h + h - 1);
if (showAsMap) {
- // If map, not centred around us
+ // If map, not centered around us
x1 = x, y1 = Grid - 1 - y;
} else {
// Which cell ?
x1 = player.World.x - Grid / 2 + x;
- y1 = player.World.y + Grid / 2 - y;
+ y1 = player.World.y - Grid / 2 + y;
}
DRAWTile(s, r, map.read(x1, y1));
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index 07ebaa96c2a..fedcac49964 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -49,6 +49,16 @@ void Status::draw() {
s.writeString(Common::Point(33, 3), Common::String::format("%d", player.Attr[AT_GOLD]));
}
+bool Status::msgGame(const GameMessage &msg) {
+ if (msg._name == "MSG") {
+ _message = msg._stringValue;
+ redraw();
+ return true;
+ }
+
+ return false;
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/status.h b/engines/ultima/ultima0/views/status.h
index 6076b03564b..fbce224d4d6 100644
--- a/engines/ultima/ultima0/views/status.h
+++ b/engines/ultima/ultima0/views/status.h
@@ -38,6 +38,7 @@ public:
~Status() override {}
void draw() override;
+ bool msgGame(const GameMessage &msg) override;
};
} // namespace Views
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index b8674011da6..235a7038df0 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -47,28 +47,57 @@ void WorldMap::draw() {
}
bool WorldMap::msgAction(const ActionMessage &msg) {
+ if (isDelayActive())
+ return false;
+
switch (msg._action) {
+ case KEYBIND_UP:
+ showMessage("North");
+ move(0, -1);
+ break;
+ case KEYBIND_DOWN:
+ showMessage("South");
+ move(0, 1);
+ break;
+ case KEYBIND_LEFT:
+ showMessage("West");
+ move(-1, 0);
+ break;
+ case KEYBIND_RIGHT:
+ showMessage("East");
+ move(1, 0);
+ break;
case KEYBIND_INFO:
// Show character info screen
+ showMessage("");
replaceView("Info");
break;
+
+ default:
+ showMessage("");
+ break;
}
+ endOfTurn();
return true;
}
bool WorldMap::msgKeypress(const KeypressMessage &msg) {
+ if (isDelayActive())
+ return false;
+
switch (msg.keycode) {
case Common::KEYCODE_q:
// "Quit" in the original which merely saves the game. For ScummVM,
// we open the GMM, allowing the user to either save or quit
g_engine->openMainMenuDialog();
- break;
+ return true;
default:
break;
}
+ endOfTurn();
return true;
}
@@ -77,6 +106,35 @@ void WorldMap::endOfTurn() {
if (player.Attr[AT_HP] <= 0)
replaceView("Dead");
+
+ player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
+ if (player.Object[OB_FOOD] == 0) {
+ showMessage("You have starved...");
+ delaySeconds(2);
+ }
+}
+
+void WorldMap::timeout() {
+ // Currently the only delay is for having starved
+ replaceView("Dead");
+}
+
+void WorldMap::move(int xi, int yi) {
+ auto &player = g_engine->_player;
+ auto &map = g_engine->_worldMap;
+
+ // Calculate new position
+ int x1 = player.World.x + xi;
+ int y1 = player.World.y + yi;
+
+ if (map.read(x1, y1) == WT_MOUNTAIN) {
+ showMessage("You can't pass the mountains.");
+ } else {
+ // Move
+ player.World.x = x1;
+ player.World.y = y1;
+ redraw();
+ }
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index 496d4d63be2..96c9395a317 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -33,7 +33,11 @@ class WorldMap : public View {
private:
Status _status = Status("MapStatus", this);
+ void move(int xi, int yi);
void endOfTurn();
+ void showMessage(const Common::String &msg) {
+ _status.send(GameMessage("MSG", msg));
+ }
public:
WorldMap();
@@ -43,6 +47,7 @@ public:
void draw() override;
bool msgAction(const ActionMessage &msg) override;
bool msgKeypress(const KeypressMessage &msg) override;
+ void timeout() override;
};
} // namespace Views
Commit: 857632dacf5127202755631a0d1f1d82b99fee30
https://github.com/scummvm/scummvm/commit/857632dacf5127202755631a0d1f1d82b99fee30
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:26+11:00
Commit Message:
ULTIMA: ULTIMA0: Dungeon creation logic
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/dungeon.cpp
engines/ultima/ultima0/views/world_map.cpp
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 86e04b08f78..a6d44768f42 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -35,6 +35,7 @@ const _OInfStruct OBJECT_INFO[] = {
};
const _MInfStruct MONSTER_INFO[] = {
+ { nullptr, 0 },
{ "Skeleton", 1 },
{ "Thief", 2 },
{ "Giant Rat", 3 },
@@ -49,6 +50,7 @@ const _MInfStruct MONSTER_INFO[] = {
const char *ATTRIB_NAMES[] = { "Hit Points", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
+/*-------------------------------------------------------------------*/
void PLAYER::init() {
Common::fill(Name, Name + MAX_NAME + 1, '\0');
@@ -151,5 +153,105 @@ void WORLDMAP::synchronize(Common::Serializer &s) {
s.syncBytes(&Map[i][0], WORLD_MAP_SIZE);
}
+/*-------------------------------------------------------------------*/
+
+void DUNGEONMAP::create(const PLAYER &player) {
+ int i, x, y;
+ const int Size = DUNGEON_MAP_SIZE - 1;
+
+ // Seed the random number
+ g_engine->setRandomSeed(player.LuckyNumber - player.World.x * 40 -
+ player.World.y * 1000 - player.Level);
+
+ // Clear the dungeon
+ Common::fill((byte *)Map, (byte *)Map + DUNGEON_MAP_SIZE * DUNGEON_MAP_SIZE, DT_SPACE);
+
+ // Draw the boundaries
+ for (x = 0; x <= Size; x++) {
+ Map[Size][x] = DT_SOLID;
+ Map[0][x] = DT_SOLID;
+ Map[x][Size] = DT_SOLID;
+ Map[x][0] = DT_SOLID;
+ }
+
+ // Fill with checkerboard
+ for (x = 2; x < Size; x = x + 2) {
+ for (y = 1; y < Size; y++) {
+ Map[x][y] = DT_SOLID;
+ Map[y][x] = DT_SOLID;
+ }
+ }
+
+ // Fill with stuff
+ for (x = 2; x < Size; x = x + 2) {
+ for (y = 1; y < Size; y = y + 2) {
+ Map[x][y] = generateContent(Map[x][y]);
+ Map[y][x] = generateContent(Map[y][x]);
+ }
+ }
+
+ // Put stairs in
+ Map[2][1] = DT_SPACE;
+
+ // Different ends each level
+ if (player.Level % 2 == 0) {
+ Map[Size - 3][3] = DT_LADDERDN;
+ Map[3][Size - 3] = DT_LADDERUP;
+ } else {
+ Map[Size - 3][3] = DT_LADDERUP;
+ Map[3][Size - 3] = DT_LADDERDN;
+ }
+
+ // On first floor
+ if (player.Level == 1) {
+ Map[1][1] = DT_LADDERUP; // Ladder at top left
+ Map[Size - 3][3] = DT_SPACE; // No other ladder up
+ }
+
+ // Add monsters
+ MonstCount = 0;
+ for (i = 1; i <= MAX_MONSTERS; ++i)
+ addMonster(player, i);
+}
+
+int DUNGEONMAP::generateContent(int c) {
+ if (RND() > .95) c = DT_TRAP;
+ if (RND() > .6) c = DT_HIDDENDOOR;
+ if (RND() > .6) c = DT_DOOR;
+ if (RND() > .97) c = DT_PIT;
+ if (RND() > .94) c = DT_GOLD;
+ return c;
+}
+
+void DUNGEONMAP::addMonster(const PLAYER &player, int Type) {
+ int x, y;
+ int level = MONSTER_INFO[Type].Level;
+
+ // Limit monsters to levels
+ if (level - 2 > player.Level)
+ return;
+ // Not always there anyway
+ if (RND() > 0.4)
+ return;
+
+ // Get monster record
+ MONSTER &m = Monster[MonstCount++];
+
+ // Fill in details */
+ m.Type = Type;
+ m.Strength = level + 3 + player.Level;
+ m.Alive = 1;
+
+ // Find a place for it. Must be empty, not player
+ do {
+ x = urand() % DUNGEON_MAP_SIZE;
+ y = urand() % DUNGEON_MAP_SIZE;
+ } while (Map[x][y] != DT_SPACE ||
+ (x == player.Dungeon.x && y == player.Dungeon.y));
+
+ // Record position
+ m.Loc.x = x; m.Loc.y = y;
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 9095680c59a..157c2af1ca2 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -29,6 +29,7 @@
namespace Ultima {
namespace Ultima0 {
+struct PLAYER;
struct _OInfStruct {
const char *Name;
@@ -63,10 +64,17 @@ struct MONSTER {
* Dungeon Map Structure
*/
struct DUNGEONMAP {
- int MapSize = 0; // Size of Map
+private:
+ void addMonster(const PLAYER &player, int Type);
+ int generateContent(int c);
+
+public:
+ const int MapSize = DUNGEON_MAP_SIZE - 1; // Size of Map
byte Map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
int MonstCount = 0; // Number of Monsters
MONSTER Monster[MAX_MONSTERS]; // Monster records
+
+ void create(const PLAYER &player);
};
/**
diff --git a/engines/ultima/ultima0/dungeon.cpp b/engines/ultima/ultima0/dungeon.cpp
index eb5c031c94a..db425d6710a 100644
--- a/engines/ultima/ultima0/dungeon.cpp
+++ b/engines/ultima/ultima0/dungeon.cpp
@@ -33,9 +33,6 @@
namespace Ultima {
namespace Ultima0 {
-static int _DUNGEONContents(int);
-static void _DUNGEONAddMonster(DUNGEONMAP *, PLAYER *, int);
-
/************************************************************************/
/* */
/* Create Dungeon Level */
@@ -43,104 +40,9 @@ static void _DUNGEONAddMonster(DUNGEONMAP *, PLAYER *, int);
/************************************************************************/
void DUNGEONCreate(PLAYER *p, DUNGEONMAP *d) {
- int i, n, x, y, Size;
-
- g_engine->setRandomSeed(p->LuckyNumber - p->World.x * 40 - /* Seed the random number */
- p->World.y * 1000 - p->Level);
- Size = MAINSuper() ? DUNGEON_MAP_SIZE - 1 : 10; /* Calculate map size */
- d->MapSize = Size; /* Save the map size */
-
- for (x = 0; x < Size; x++) /* Clear the dungeon */
- for (y = 0; y < Size; y++)
- d->Map[x][y] = DT_SPACE;
-
- for (x = 0; x <= Size; x++) /* Draw the boundaries */
- {
- d->Map[Size][x] = DT_SOLID;
- d->Map[0][x] = DT_SOLID;
- d->Map[x][Size] = DT_SOLID;
- d->Map[x][0] = DT_SOLID;
- }
- for (x = 2; x < Size; x = x + 2) /* Fill with checkerboard */
- for (y = 1; y < Size; y++)
- {
- d->Map[x][y] = DT_SOLID;
- d->Map[y][x] = DT_SOLID;
- }
- for (x = 2; x < Size; x = x + 2) /* Fill with stuff */
- for (y = 1; y < Size; y = y + 2)
- {
- d->Map[x][y] = _DUNGEONContents(d->Map[x][y]);
- d->Map[y][x] = _DUNGEONContents(d->Map[y][x]);
- }
-
- d->Map[2][1] = DT_SPACE; /* Put stairs in */
- if (p->Level % 2 == 0) /* Different ends each level */
- {
- d->Map[Size - 3][3] = DT_LADDERDN;
- d->Map[3][Size - 3] = DT_LADDERUP;
- } else
- {
- d->Map[Size - 3][3] = DT_LADDERUP;
- d->Map[3][Size - 3] = DT_LADDERDN;
- }
-
- if (p->Level == 1) /* On first floor */
- {
- d->Map[1][1] = DT_LADDERUP; /* Ladder at top left */
- d->Map[Size - 3][3] = DT_SPACE; /* No other ladder up */
- }
-
- d->MonstCount = 0; /* No monsters */
- n = MAINSuper() ? MAX_MONSTERS : 10; /* How many might there be ? */
- for (i = 1; i <= n; i++) /* Go through the monsters */
- _DUNGEONAddMonster(d, p, i); /* Maybe adding them as you go */
+ d->create(*p);
}
-/************************************************************************/
-/* */
-/* Generate some contents */
-/* */
-/************************************************************************/
-
-static int _DUNGEONContents(int c) {
- if (RND() > .95) c = DT_TRAP;
- if (RND() > .6) c = DT_HIDDENDOOR;
- if (RND() > .6) c = DT_DOOR;
- if (RND() > .97) c = DT_PIT;
- if (RND() > .94) c = DT_GOLD;
- return c;
-}
-
-/************************************************************************/
-/* */
-/* Maybe add a monster of the given type */
-/* */
-/************************************************************************/
-
-static void _DUNGEONAddMonster(DUNGEONMAP *d, PLAYER *p, int Type) {
- MONSTER *m;
- int x, y;
- int Level = GLOMonsterLevel(Type); /* Read the level */
-
- if (Level - 2 > p->Level) return; /* Limit monsters to levels */
- if (RND() > 0.4) return; /* Not always there anyway */
-
- m = &(d->Monster[(d->MonstCount)++]); /* Get monster record */
-
- m->Type = Type; /* Fill in details */
- m->Strength = Level + 3 + p->Level;
- m->Alive = 1;
-
- do /* Find a place for it */
- {
- x = urand() % d->MapSize;
- y = urand() % d->MapSize;
- } while (d->Map[x][y] != DT_SPACE || /* Must be empty, not player */
- (x == p->Dungeon.x && y == p->Dungeon.y));
-
- m->Loc.x = x; m->Loc.y = y; /* Record position */
-}
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 235a7038df0..f1949f7e285 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -72,7 +72,10 @@ bool WorldMap::msgAction(const ActionMessage &msg) {
showMessage("");
replaceView("Info");
break;
-
+ case KEYBIND_ENTER:
+ case KEYBIND_SELECT:
+ enter();
+ break;
default:
showMessage("");
break;
@@ -115,8 +118,35 @@ void WorldMap::endOfTurn() {
}
void WorldMap::timeout() {
- // Currently the only delay is for having starved
- replaceView("Dead");
+ auto &player = g_engine->_player;
+ const auto &map = g_engine->_worldMap;
+
+ if (player.Attr[AT_HP] <= 0 || player.Object[OB_FOOD] <= 0) {
+ // Timeout from displaying player was killed
+ replaceView("Dead");
+ } else {
+ // Otherwise a timeout from entering a location
+ int t = map.read(player.World.x, player.World.y);
+ switch (t) {
+ case WT_TOWN:
+ replaceView("Town");
+ break;
+ case WT_DUNGEON:
+ player.Level = 1; // Go to level 1
+ player.Dungeon.x = 1; // Set initial position
+ player.Dungeon.y = 1;
+ player.DungDir.x = 1; // And direction
+ player.DungDir.y = 0;
+
+ replaceView("Dungeon");
+ break;
+ case WT_BRITISH:
+ replaceView("Castle");
+ break;
+ default:
+ break;
+ }
+ }
}
void WorldMap::move(int xi, int yi) {
@@ -137,6 +167,31 @@ void WorldMap::move(int xi, int yi) {
}
}
+void WorldMap::enter() {
+ const auto &player = g_engine->_player;
+ const auto &map = g_engine->_worldMap;
+
+ int t = map.read(player.World.x, player.World.y);
+ switch (t) {
+ case WT_TOWN:
+ showMessage("Enter Town.");
+ delaySeconds(2);
+ break;
+ case WT_DUNGEON:
+ showMessage("Enter Dungeon.");
+ delaySeconds(2);
+ break;
+ case WT_BRITISH:
+ showMessage("Enter Castle.");
+ delaySeconds(2);
+ break;
+ default:
+ // Nope....
+ showMessage("Huh???");
+ break;
+ }
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index 96c9395a317..d989f54ea0d 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -34,6 +34,7 @@ private:
Status _status = Status("MapStatus", this);
void move(int xi, int yi);
+ void enter();
void endOfTurn();
void showMessage(const Common::String &msg) {
_status.send(GameMessage("MSG", msg));
Commit: c4416b982f0abb4278c511f19427271f93760c7b
https://github.com/scummvm/scummvm/commit/c4416b982f0abb4278c511f19427271f93760c7b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Castle view
Changed paths:
A engines/ultima/ultima0/views/castle.cpp
A engines/ultima/ultima0/views/castle.h
engines/ultima/module.mk
engines/ultima/ultima0/data/defines.h
engines/ultima/ultima0/gfx/gfx_surface.cpp
engines/ultima/ultima0/gfx/gfx_surface.h
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/create_character.cpp
engines/ultima/ultima0/views/create_character.h
engines/ultima/ultima0/views/views.h
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 868f8443ebe..19a90df575e 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -36,6 +36,7 @@ MODULE_OBJS += \
ultima0/gfx/gfx_surface.o \
ultima0/gfx/map.o \
ultima0/views/view.o \
+ ultima0/views/castle.o \
ultima0/views/create_character.o \
ultima0/views/info.o \
ultima0/views/startup.o \
diff --git a/engines/ultima/ultima0/data/defines.h b/engines/ultima/ultima0/data/defines.h
index ceb9c9b8560..0b15e9c402c 100644
--- a/engines/ultima/ultima0/data/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -57,6 +57,9 @@ constexpr int DEFAULT_SCY = 400;
#define C_PURPLE RGB(1,0,1)
#define C_ROSE 8
#define C_VIOLET 9
+#define C_GREY 10
+
+#define C_TEXT_DEFAULT C_CYAN
#define WT_SPACE (0) /* World Tiles */
#define WT_MOUNTAIN (1)
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.cpp b/engines/ultima/ultima0/gfx/gfx_surface.cpp
index 1b27e99e6f4..50dcc475852 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.cpp
+++ b/engines/ultima/ultima0/gfx/gfx_surface.cpp
@@ -27,12 +27,6 @@ namespace Ultima {
namespace Ultima0 {
namespace Gfx {
-
-void GfxSurface::init() {
- // Default text to Cyan
- _textColor = g_engine->_palette.findBestColor(0, 255, 255);
-}
-
void GfxSurface::writeString(const Common::Point &pt, const Common::String &str,
Graphics::TextAlign align) {
_textPos = pt;
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.h b/engines/ultima/ultima0/gfx/gfx_surface.h
index 98e0a199cac..65d7dfbb42f 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.h
+++ b/engines/ultima/ultima0/gfx/gfx_surface.h
@@ -33,18 +33,13 @@ namespace Gfx {
class GfxSurface : public Graphics::ManagedSurface {
private:
Common::Point _textPos;
- byte _textColor;
+ byte _textColor = C_TEXT_DEFAULT;
- void init();
void newLine();
public:
- GfxSurface() : Graphics::ManagedSurface() {
- init();
- }
- GfxSurface(Graphics::ManagedSurface &surf, const Common::Rect &bounds) : Graphics::ManagedSurface(surf, bounds) {
- init();
- }
+ GfxSurface() : Graphics::ManagedSurface() {}
+ GfxSurface(Graphics::ManagedSurface &surf, const Common::Rect &bounds) : Graphics::ManagedSurface(surf, bounds) {}
/**
* Write some text to the surface
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index 857d71c1e24..f986ef507c2 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -41,7 +41,7 @@ static const KeybindingRecord NORMAL_KEYS[] = {
{ KEYBIND_DOWN, "DOWN", _s("Down/Backwards"), "DOWN", "JOY_DOWN" },
{ KEYBIND_LEFT, "LEFT", _s("Left"), "LEFT", "JOY_LEFT" },
{ KEYBIND_RIGHT, "RIGHT", _s("Right"), "RIGHT", "JOY_RIGHT" },
- { KEYBIND_SELECT, "INTERACT", _s("Interact"), "RETURN", "JOY_A" },
+ { KEYBIND_SELECT, "INTERACT", _s("Interact"), "SPACE", "JOY_A" },
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
{ KEYBIND_ESCAPE, "ESCAPE", _s("Escape"), "ESCAPE", "JOY_Y" },
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 5cc7aee1ec9..6d31cf44bf0 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -41,6 +41,7 @@ static const byte PALETTE[][3] = {
{ 255, 255, 255 }, // White
{ 255, 0, 128 }, // Rose
{ 80, 80, 255 }, // Violet
+ { 180, 180, 180 }, // Grey
{ 220, 20, 130 } // Transparent. Needed?
};
diff --git a/engines/ultima/ultima0/views/castle.cpp b/engines/ultima/ultima0/views/castle.cpp
new file mode 100644
index 00000000000..9afe36791af
--- /dev/null
+++ b/engines/ultima/ultima0/views/castle.cpp
@@ -0,0 +1,210 @@
+/* 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 "ultima/ultima0/views/castle.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+static const char *GO_FORTH = " Go now upon this quest, and may\n"
+ "Lady Luck be fair unto you.....\n"
+ ".....Also I, British, have increased\n"
+ "each of thy attributes by one.!";
+
+bool Castle::msgFocus(const FocusMessage &msg) {
+ const auto &player = g_engine->_player;
+
+ if (Common::String(player.Name).empty())
+ _mode = NAMING;
+ else if (player.TaskCompleted) {
+ _mode = TASK_COMPLETE;
+ } else {
+ _mode = TASK_INCOMPLETE;
+ }
+
+ return true;
+}
+
+void Castle::draw() {
+ auto s = getSurface();
+ s.clear();
+
+ if (_mode <= FIRST_TASK) {
+ firstTime();
+ } else if (_mode == TASK_COMPLETE) {
+ taskCompleted();
+ } else if (_mode == TASK_INCOMPLETE) {
+ taskIncomplete();
+ }
+}
+
+void Castle::firstTime() {
+ auto s = getSurface();
+
+ if (_mode >= NAMING && _mode <= FIRST_TASK) {
+ s.writeString(Common::Point(5, 2), "Welcome Peasant into the halls of\n"
+ "the mighty Lord British. Herein thou\n"
+ "may choose to dare battle with the\n"
+ "evil creatures of the depths, for\n"
+ "great reward!\n\n"
+ "What is thy name peasant? ");
+ s.setColor(C_GREY);
+ s.writeString(_playerName);
+ s.setColor(C_TEXT_DEFAULT);
+ }
+
+ if (_mode >= GRAND_ADVENTURE && _mode <= FIRST_TASK)
+ s.writeString(Common::Point(0, 10), "Doest thou wish for great adventure ?\n\n");
+
+ if (_mode == BEGONE) {
+ s.writeString("Then leave and begone!");
+ } else if (_mode == FIRST_TASK) {
+ s.writeString("Good! Thou shalt try to become a\nKnight!!!\n\n"
+ "Thy first task is to go into the\n"
+ "dungeons and to return only after\n"
+ "killing ");
+ s.setColor(C_VIOLET);
+ s.writeString(getTaskName(1));
+
+ pressAnyKey();
+ }
+}
+
+void Castle::taskCompleted() {
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+
+ s.writeString(Common::Point(0, 3), "Aaaahhhh.... ");
+ s.writeString(player.Name);
+ s.writeString("\n\nThou has accomplished\nthy quest.\n\n");
+
+ if (player.Task == MAX_MONSTERS) {
+ s.writeString("Thou hast proved thyself worthy of\n"
+ "Knighthood, continue if thou doth wish\n"
+ "but thou hast accomplished the\n"
+ "main objective of the game.\n\n"
+ "Now, maybe thou art foolhardy enough to\n"
+ "try difficulty level ");
+ s.writeString(Common::String::format("%s.", player.Skill + 1));
+ } else {
+ nextTask();
+
+ s.writeString("Unfortunately, this is not enough to\n"
+ "become a knight.\n\n");
+ s.writeString("Thou must now kill ");
+ s.setColor(C_VIOLET);
+ s.writeString(getTaskName(1));
+
+ s.setColor(C_TEXT_DEFAULT);
+ s.writeString("\n\n");
+ s.writeString(GO_FORTH);
+
+ pressAnyKey();
+ }
+}
+
+void Castle::taskIncomplete() {
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+
+ s.writeString(Common::Point(0, 3),
+ "Why hast thou returned ?\n"
+ "Thou must kill ");
+ s.setColor(C_VIOLET);
+ s.writeString(getTaskName(player.Task));
+
+ s.setColor(C_TEXT_DEFAULT);
+ s.writeString("\n\nGo now and complete thy quest");
+}
+
+void Castle::pressAnyKey() {
+ auto s = getSurface();
+ s.writeString(Common::Point(20, 23), "Press any Key to Continue",
+ Graphics::kTextAlignCenter);
+}
+
+bool Castle::msgKeypress(const KeypressMessage &msg) {
+ auto &player = g_engine->_player;
+
+ switch (_mode) {
+ case NAMING:
+ if (msg.keycode == Common::KEYCODE_BACKSPACE && !_playerName.empty()) {
+ _playerName.deleteLastChar();
+ } else if (msg.keycode == Common::KEYCODE_RETURN && !_playerName.empty()) {
+ Common::strcpy_s(player.Name, _playerName.c_str());
+ _mode = GRAND_ADVENTURE;
+ } else if (Common::isAlpha(msg.ascii) && _playerName.size() < MAX_NAME) {
+ _playerName += msg.ascii;
+ }
+ redraw();
+ break;
+
+ case GRAND_ADVENTURE:
+ if (msg.keycode == Common::KEYCODE_y) {
+ nextTask();
+ _mode = FIRST_TASK;
+ } else if (msg.keycode == Common::KEYCODE_n) {
+ _mode = BEGONE;
+ }
+ redraw();
+ break;
+
+ default:
+ // All other modes exit the castle
+ replaceView("WorldMap");
+ break;
+ }
+
+ return true;
+}
+
+bool Castle::msgAction(const ActionMessage &msg) {
+ if (_mode >= FIRST_TASK) {
+ replaceView("WorldMap");
+ }
+
+ return true;
+}
+
+void Castle::nextTask() {
+ auto &player = g_engine->_player;
+
+ player.Task++;
+ player.TaskCompleted = 0;
+
+ // LB gives you extra attributes
+ for (int i = 0; i < MAX_ATTR; i++)
+ player.Attr[i]++;
+}
+
+Common::String Castle::getTaskName(int taskNum) const {
+ Common::String mons = MONSTER_INFO[taskNum].Name;
+
+ return Common::String::format("%s %s",
+ strchr("aeiou", tolower(mons.firstChar())) != nullptr ? "an" : "a",
+ mons.c_str());
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/castle.h b/engines/ultima/ultima0/views/castle.h
new file mode 100644
index 00000000000..55261c49b55
--- /dev/null
+++ b/engines/ultima/ultima0/views/castle.h
@@ -0,0 +1,60 @@
+/* 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 ULTIMA0_VIEWS_CASTLE_H
+#define ULTIMA0_VIEWS_CASTLE_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Castle : public View {
+private:
+ enum Mode {
+ NAMING, GRAND_ADVENTURE, BEGONE, FIRST_TASK, TASK_COMPLETE, TASK_INCOMPLETE
+ };
+ Mode _mode = NAMING;
+ Common::String _playerName;
+
+ void firstTime();
+ void taskCompleted();
+ void taskIncomplete();
+ void nextTask();
+ void pressAnyKey();
+ Common::String getTaskName(int taskNum) const;
+
+public:
+ Castle() : View("Castle") {}
+ ~Castle() override {}
+
+ bool msgFocus(const FocusMessage &msg) override;
+ void draw() override;
+ bool msgKeypress(const KeypressMessage &msg) override;
+ bool msgAction(const ActionMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
index 8d5b754912b..5ec3d35e5e2 100644
--- a/engines/ultima/ultima0/views/create_character.cpp
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -51,7 +51,7 @@ void CreateCharacter::draw() {
if (_mode == LEVEL)
s.writeString(_input);
else
- s.writeString(Common::String::format("%d", _level));
+ s.writeString(Common::String::format("%d", player.Skill));
}
// Stats
@@ -114,8 +114,8 @@ bool CreateCharacter::msgAction(const ActionMessage &msg) {
_mode = LEVEL;
redraw();
} else if (_mode == LEVEL) {
- _level = atoi(_input.c_str());
- if (_level >= 1 && _level <= 10) {
+ player.Skill = atoi(_input.c_str());
+ if (player.Skill >= 1 && player.Skill <= 10) {
_input.clear();
_mode = STATS;
player.rollAttributes();
diff --git a/engines/ultima/ultima0/views/create_character.h b/engines/ultima/ultima0/views/create_character.h
index cb45054cf0a..7639e527d9e 100644
--- a/engines/ultima/ultima0/views/create_character.h
+++ b/engines/ultima/ultima0/views/create_character.h
@@ -33,7 +33,6 @@ private:
enum Mode { LUCKY_NUMBER, LEVEL, STATS, CLASS };
Mode _mode = LUCKY_NUMBER;
Common::String _input;
- int _level = 0;
void characterDone();
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 268a0662011..006c0a823a8 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_VIEWS_H
#define ULTIMA0_VIEWS_H
+#include "ultima/ultima0/views/castle.h"
#include "ultima/ultima0/views/create_character.h"
#include "ultima/ultima0/views/dead.h"
#include "ultima/ultima0/views/info.h"
@@ -35,6 +36,7 @@ namespace Ultima0 {
namespace Views {
struct Views {
+ Castle _castle;
CreateCharacter _createCharacter;
Dead _dead;
Info _info;
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index f1949f7e285..48fadaeef2b 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -113,7 +113,7 @@ void WorldMap::endOfTurn() {
player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
if (player.Object[OB_FOOD] == 0) {
showMessage("You have starved...");
- delaySeconds(2);
+ delaySeconds(1);
}
}
@@ -175,15 +175,15 @@ void WorldMap::enter() {
switch (t) {
case WT_TOWN:
showMessage("Enter Town.");
- delaySeconds(2);
+ delaySeconds(1);
break;
case WT_DUNGEON:
showMessage("Enter Dungeon.");
- delaySeconds(2);
+ delaySeconds(1);
break;
case WT_BRITISH:
showMessage("Enter Castle.");
- delaySeconds(2);
+ delaySeconds(1);
break;
default:
// Nope....
Commit: df502806e13c7322707cc06d2a375797cee99ffe
https://github.com/scummvm/scummvm/commit/df502806e13c7322707cc06d2a375797cee99ffe
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Savegame fixes, keybinding fix
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/gfx/map.cpp
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/create_character.cpp
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/title.h
engines/ultima/ultima0/world.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index a6d44768f42..f395a08f126 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -105,7 +105,7 @@ void WORLDMAP::init(PLAYER &p) {
int c, x, y, Size;
g_engine->setRandomSeed(p.LuckyNumber);
- Size = MapSize; // Get hard-coded map size
+ Size = WORLD_MAP_SIZE - 1;
// Set the boundaries
for (x = 0; x <= Size; x++) {
@@ -149,8 +149,9 @@ int WORLDMAP::read(int x, int y) const {
}
void WORLDMAP::synchronize(Common::Serializer &s) {
- for (int i = 0; i < WORLD_MAP_SIZE; ++i)
- s.syncBytes(&Map[i][0], WORLD_MAP_SIZE);
+ for (int y = 0; y < WORLD_MAP_SIZE; ++y)
+ for (int x = 0; x < WORLD_MAP_SIZE; ++x)
+ s.syncAsByte(Map[x][y]);
}
/*-------------------------------------------------------------------*/
@@ -253,5 +254,11 @@ void DUNGEONMAP::addMonster(const PLAYER &player, int Type) {
m.Loc.x = x; m.Loc.y = y;
}
+void DUNGEONMAP::synchronize(Common::Serializer &s) {
+ for (int y = 0; y < DUNGEON_MAP_SIZE; ++y)
+ for (int x = 0; x < DUNGEON_MAP_SIZE; ++x)
+ s.syncAsByte(Map[x][y]);
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 157c2af1ca2..53f677acf22 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -75,6 +75,7 @@ public:
MONSTER Monster[MAX_MONSTERS]; // Monster records
void create(const PLAYER &player);
+ void synchronize(Common::Serializer &s);
};
/**
@@ -106,7 +107,6 @@ struct PLAYER {
* World Map structure
*/
struct WORLDMAP {
- const int MapSize = WORLD_MAP_SIZE - 1; // Size of map
byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
void init(PLAYER &p);
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
index b06333e9d92..48bb75896c4 100644
--- a/engines/ultima/ultima0/gfx/map.cpp
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -34,7 +34,7 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
int x, y, x1, y1, w, h, Grid;
Common::Rect r;
- Grid = showAsMap ? map.MapSize + 1 : (g_engine->isEnhanced() ? 7 : 3);
+ Grid = showAsMap ? WORLD_MAP_SIZE : (g_engine->isEnhanced() ? 7 : 3);
w = s->w / Grid; h = s->h / Grid; // Get grid sizes
for (x = 0; x < Grid; x++) {
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 6d31cf44bf0..b3855a4fcfc 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -105,6 +105,7 @@ Common::Error Ultima0Engine::saveGameStream(Common::WriteStream *stream, bool is
void Ultima0Engine::syncSavegame(Common::Serializer &s) {
_player.synchronize(s);
_worldMap.synchronize(s);
+ _dungeon.synchronize(s);
}
} // namespace Ultima0
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
index 5ec3d35e5e2..91a0e0c775f 100644
--- a/engines/ultima/ultima0/views/create_character.cpp
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -83,6 +83,21 @@ bool CreateCharacter::msgKeypress(const KeypressMessage &msg) {
} else if (msg.keycode == Common::KEYCODE_BACKSPACE && _input.size() > 0) {
_input.deleteLastChar();
redraw();
+ } else if (msg.keycode == Common::KEYCODE_RETURN && !_input.empty()) {
+ if (_mode == LUCKY_NUMBER) {
+ player.LuckyNumber = atoi(_input.c_str());
+ _input.clear();
+ _mode = LEVEL;
+ redraw();
+ } else {
+ player.Skill = atoi(_input.c_str());
+ if (player.Skill >= 1 && player.Skill <= 10) {
+ _input.clear();
+ _mode = STATS;
+ player.rollAttributes();
+ redraw();
+ }
+ }
}
} else if (msg.keycode == Common::KEYCODE_y) {
_mode = CLASS;
@@ -107,23 +122,6 @@ bool CreateCharacter::msgAction(const ActionMessage &msg) {
return true;
}
- if (msg._action == KEYBIND_SELECT && !_input.empty()) {
- if (_mode == LUCKY_NUMBER) {
- player.LuckyNumber = atoi(_input.c_str());
- _input.clear();
- _mode = LEVEL;
- redraw();
- } else if (_mode == LEVEL) {
- player.Skill = atoi(_input.c_str());
- if (player.Skill >= 1 && player.Skill <= 10) {
- _input.clear();
- _mode = STATS;
- player.rollAttributes();
- redraw();
- }
- }
- }
-
return true;
}
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index 25df0d6a7f5..235d466672c 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -55,6 +55,15 @@ void Title::draw() {
s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
}
+bool Title::msgKeypress(const KeypressMessage &msg) {
+ if (msg.keycode == Common::KEYCODE_RETURN) {
+ selectOption();
+ return true;
+ }
+
+ return false;
+}
+
bool Title::msgAction(const ActionMessage &msg) {
switch (msg._action) {
case KEYBIND_UP:
diff --git a/engines/ultima/ultima0/views/title.h b/engines/ultima/ultima0/views/title.h
index 0764c51f568..e2b8e91582a 100644
--- a/engines/ultima/ultima0/views/title.h
+++ b/engines/ultima/ultima0/views/title.h
@@ -58,6 +58,7 @@ public:
bool msgFocus(const FocusMessage &msg) override;
void draw() override;
+ bool msgKeypress(const KeypressMessage &msg) override;
bool msgAction(const ActionMessage &msg) override;
bool msgGame(const GameMessage &msg) override;
bool msgMouseDown(const MouseDownMessage &msg);
diff --git a/engines/ultima/ultima0/world.cpp b/engines/ultima/ultima0/world.cpp
index 611601b33db..05da892efff 100644
--- a/engines/ultima/ultima0/world.cpp
+++ b/engines/ultima/ultima0/world.cpp
@@ -51,8 +51,8 @@ void WORLDCreate(PLAYER *p, WORLDMAP *w) {
int WORLDRead(WORLDMAP *w, int x, int y) {
if (x < 0 || y < 0) return WT_MOUNTAIN;
- if (x > w->MapSize) return WT_MOUNTAIN;
- if (y > w->MapSize) return WT_MOUNTAIN;
+ if (x >= WORLD_MAP_SIZE) return WT_MOUNTAIN;
+ if (y >= WORLD_MAP_SIZE) return WT_MOUNTAIN;
return w->Map[x][y];
}
@@ -67,7 +67,7 @@ void WORLDDraw(PLAYER *p, WORLDMAP *m, int ShowAsMap) {
RECT r;
Grid = 7; /* Number of cells in grid */
if (MAINSuper() == 0) Grid = 3; /* Standard Aklabeth */
- if (ShowAsMap) Grid = m->MapSize + 1; /* Displaying as a map ? */
+ if (ShowAsMap) Grid = DUNGEON_MAP_SIZE; /* Displaying as a map ? */
w = 1280 / Grid; h = 1024 / Grid; /* Get grid sizes */
for (x = 0; x < Grid; x++) /* For all grid cells */
for (y = 0; y < Grid; y++)
Commit: 45901d344651b3a29af2ec62cb522467d2fb6e02
https://github.com/scummvm/scummvm/commit/45901d344651b3a29af2ec62cb522467d2fb6e02
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Extra console commands
Changed paths:
engines/ultima/ultima0/akalabeth.h
engines/ultima/ultima0/console.cpp
engines/ultima/ultima0/console.h
engines/ultima/ultima0/main.cpp
engines/ultima/ultima0/player.cpp
engines/ultima/ultima0/views/info.cpp
diff --git a/engines/ultima/ultima0/akalabeth.h b/engines/ultima/ultima0/akalabeth.h
index 1414a2628ae..23f58e967f6 100644
--- a/engines/ultima/ultima0/akalabeth.h
+++ b/engines/ultima/ultima0/akalabeth.h
@@ -50,8 +50,6 @@ void MAINSetup(void);
void MAINStart(void);
void PLAYERInit(PLAYER *); /* PLAYER.C prototyping */
-void PLAYERDebug(PLAYER *);
-void PLAYERDemo(PLAYER *);
void PLAYERCharacter(PLAYER *);
void PLAYERInv(PLAYER *);
diff --git a/engines/ultima/ultima0/console.cpp b/engines/ultima/ultima0/console.cpp
index d9a838f4513..a74ace877d7 100644
--- a/engines/ultima/ultima0/console.cpp
+++ b/engines/ultima/ultima0/console.cpp
@@ -20,13 +20,18 @@
*/
#include "ultima/ultima0/console.h"
-#include "ultima/ultima0/events.h"
+#include "ultima/ultima0/ultima0.h"
namespace Ultima {
namespace Ultima0 {
Console::Console() : GUI::Debugger() {
registerCmd("view", WRAP_METHOD(Console, cmdView));
+ registerCmd("food", WRAP_METHOD(Console, cmdFood));
+ registerCmd("hp", WRAP_METHOD(Console, cmdHP));
+ registerCmd("gold", WRAP_METHOD(Console, cmdGold));
+ registerCmd("demo", WRAP_METHOD(Console, cmdDemo));
+ registerCmd("debug", WRAP_METHOD(Console, cmdDebug));
}
Console::~Console() {
@@ -42,5 +47,86 @@ bool Console::cmdView(int argc, const char **argv) {
}
}
+bool Console::cmdFood(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("food <amount>\n");
+ return true;
+ } else {
+ g_engine->_player.Object[OB_FOOD] = atoi(argv[1]);
+ g_engine->focusedView()->redraw();
+ return false;
+ }
+}
+
+bool Console::cmdGold(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("gold <amount>\n");
+ return true;
+ } else {
+ g_engine->_player.Attr[AT_GOLD] = atoi(argv[1]);
+ g_engine->focusedView()->redraw();
+ return false;
+ }
+}
+
+bool Console::cmdHP(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("hp <amount>\n");
+ return true;
+ } else {
+ g_engine->_player.Attr[AT_HP] = atoi(argv[1]);
+ g_engine->focusedView()->redraw();
+ return false;
+ }
+}
+
+bool Console::cmdDemo(int argc, const char **argv) {
+ auto &p = g_engine->_player;
+ auto &map = g_engine->_worldMap;
+
+ Common::strcpy_s(p.Name, "Demo"); // Characters Name
+ p.Class = 'F'; // Fighter
+ p.LuckyNumber = 42; // Always the same.....
+ p.Skill = 1; // Skill level 1
+
+ // Nice high attributes
+ Common::fill(p.Attr, p.Attr + MAX_ATTR, 15);
+ p.Attr[AT_HP] = 18;
+ p.Attr[AT_GOLD] = 99;
+
+ for (int i = 0; i < p.Objects; i++) // Lots of nice objects
+ p.Object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
+
+ p.Level = 0;
+ map.init(p);
+ g_engine->replaceView("WorldMap");
+
+ return false;
+}
+
+
+bool Console::cmdDebug(int argc, const char **argv) {
+ auto &p = g_engine->_player;
+ auto &map = g_engine->_worldMap;
+ int i;
+
+ Common::strcpy_s(p.Name, "Debuggo"); // Characters Name
+ p.Class = 'F'; // Fighter
+ p.LuckyNumber = 42; // Always the same.....
+ p.Skill = 1; // Skill level 1
+ for (i = 0; i < MAX_ATTR; i++) // Nice high attributes
+ p.Attr[i] = 99;
+ p.Attr[AT_HP] = 999;
+ p.Attr[AT_GOLD] = 9999;
+ for (i = 0; i < p.Objects; i++) // Lots of nice objects
+ p.Object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
+
+ p.Level = 0;
+ map.init(p);
+ g_engine->replaceView("WorldMap");
+
+ return false;
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/console.h b/engines/ultima/ultima0/console.h
index 9fba8bf0af6..cab8cde6e55 100644
--- a/engines/ultima/ultima0/console.h
+++ b/engines/ultima/ultima0/console.h
@@ -31,6 +31,12 @@ namespace Ultima0 {
class Console : public GUI::Debugger {
private:
bool cmdView(int argc, const char **argv);
+ bool cmdFood(int argc, const char **argv);
+ bool cmdGold(int argc, const char **argv);
+ bool cmdHP(int argc, const char **argv);
+ bool cmdDemo(int argc, const char **argv);
+ bool cmdDebug(int argc, const char **argv);
+
public:
Console();
~Console() override;
diff --git a/engines/ultima/ultima0/main.cpp b/engines/ultima/ultima0/main.cpp
index ad2053ac68c..39af768cde9 100644
--- a/engines/ultima/ultima0/main.cpp
+++ b/engines/ultima/ultima0/main.cpp
@@ -86,7 +86,6 @@ void MAINStart(void) {
void MAINSetup(void) {
PLAYERInit(&Player); /* Initialise the player */
PLAYERCharacter(&Player); /* Character information */
- // PLAYERDebug(&Player);
WORLDCreate(&Player, &World); /* Create the over world */
WORLDDraw(&Player, &World, 0); /* Draw the player map */
TOWNEnter(&World, &Player); /* Visit the shops */
diff --git a/engines/ultima/ultima0/player.cpp b/engines/ultima/ultima0/player.cpp
index d0edd79cca5..947e9fc6b83 100644
--- a/engines/ultima/ultima0/player.cpp
+++ b/engines/ultima/ultima0/player.cpp
@@ -43,40 +43,6 @@ void PLAYERInit(PLAYER *p) {
p->init();
}
-/************************************************************************/
-/* */
-/* Manage Player Structures */
-/* */
-/************************************************************************/
-
-void PLAYERDebug(PLAYER *p) {
- int i;
- Common::strcpy_s(p->Name, "Debuggo"); /* Characters Name */
- p->Class = 'F'; /* Fighter */
- p->LuckyNumber = 42; /* Always the same..... */
- p->Skill = 1; /* Skill level 1 */
- for (i = 0; i < p->Attributes; i++) /* Nice high attributes */
- p->Attr[i] = 99;
- p->Attr[AT_HP] = 999;
- p->Attr[AT_GOLD] = 9999;
- for (i = 0; i < p->Objects; i++) /* Lots of nice objects */
- p->Object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
-}
-
-void PLAYERDemo(PLAYER *p) {
- int i;
- Common::strcpy_s(p->Name, "Demo"); /* Characters Name */
- p->Class = 'F'; /* Fighter */
- p->LuckyNumber = 42; /* Always the same..... */
- p->Skill = 1; /* Skill level 1 */
- for (i = 0; i < p->Attributes; i++) /* Nice high attributes */
- p->Attr[i] = 15;
- p->Attr[AT_HP] = 18;
- p->Attr[AT_GOLD] = 99;
- for (i = 0; i < p->Objects; i++) /* Lots of nice objects */
- p->Object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
-}
-
/************************************************************************/
/* */
/* Player Inventory */
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
index 5a0ef223215..788fca81ca9 100644
--- a/engines/ultima/ultima0/views/info.cpp
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -75,8 +75,8 @@ void Info::draw() {
s.writeString(Common::Point(15, 4 + i),
Common::String::format("%d", player.Attr[i]));
for (i = 0; i < MAX_OBJ; ++i)
- s.writeString(Common::Point(22, 4 + i),
- Common::String::format("%3d-", (int)player.Object[i]));
+ s.writeString(Common::Point(21, 4 + i),
+ Common::String::format("%4d-", (int)player.Object[i]));
s.writeString(Common::Point(18, 10), "Q-Quit");
}
Commit: 20ead6582a1db3814bc7755d7087c05a3ee101a3
https://github.com/scummvm/scummvm/commit/20ead6582a1db3814bc7755d7087c05a3ee101a3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: In progress dungeon drawing
Changed paths:
A engines/ultima/ultima0/gfx/dungeon.cpp
A engines/ultima/ultima0/gfx/dungeon.h
A engines/ultima/ultima0/gfx/monster.cpp
A engines/ultima/ultima0/gfx/monster.h
A engines/ultima/ultima0/views/dungeon.cpp
A engines/ultima/ultima0/views/dungeon.h
engines/ultima/module.mk
engines/ultima/ultima0/gfx/map.h
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 19a90df575e..2f160043f50 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -32,12 +32,15 @@ MODULE_OBJS += \
ultima0/town.o \
ultima0/world.o \
ultima0/data/data.o \
+ ultima0/gfx/dungeon.o \
ultima0/gfx/font.o \
ultima0/gfx/gfx_surface.o \
ultima0/gfx/map.o \
+ ultima0/gfx/monster.o \
ultima0/views/view.o \
ultima0/views/castle.o \
ultima0/views/create_character.o \
+ ultima0/views/dungeon.o \
ultima0/views/info.o \
ultima0/views/startup.o \
ultima0/views/status.o \
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
new file mode 100644
index 00000000000..5b7181eb2b3
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -0,0 +1,278 @@
+/* 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 "ultima/ultima0/gfx/dungeon.h"
+#include "ultima/ultima0/gfx/monster.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+int Dungeon::xLeft;
+int Dungeon::xRight;
+int Dungeon::yBottom;
+int Dungeon::yDiffLeft;
+int Dungeon::yDiffRight;
+
+#define HWColour(IDX) color = IDX
+#define X(n) (x1 + w * (n)/10)
+#define Y(n) (y1 + h * (n)/10)
+#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
+#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
+
+void Dungeon::draw(Graphics::ManagedSurface *s) {
+ const auto &player = g_engine->_player;
+ const auto &dungeon = g_engine->_dungeon;
+
+ s->clear();
+
+ double Level = 0;
+ Common::Rect rOut(0, 1023 / 2, 1260 / 2, 10);
+ Common::Rect rIn;
+ COORD Dir, Pos, Next;
+ int Monster, Front, Left, Right;
+ _DDRAWCalcRect(&rOut, 0);
+ Pos = player.Dungeon; // Get position
+
+ do {
+ Level++; // Next level
+ _DDRAWCalcRect(&rIn, Level);
+ Next.x = Pos.x + player.DungDir.x; // Next position
+ Next.y = Pos.y + player.DungDir.y;
+
+ Dir = player.DungDir; MOVERotLeft(&Dir); // To the left
+ Left = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
+ MOVERotLeft(&Dir); MOVERotLeft(&Dir);// To the right
+ Right = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
+ Front = dungeon.Map[Next.x][Next.y]; // What's in front ?
+
+ Monster = DDRAWFindMonster(&Pos); // Find ID of monster here
+ if (Monster >= 0) // Find Type if Found
+ {
+ Monster = dungeon.Monster[Monster].Type;
+ }
+ DRAWDungeon(s, &rOut, &rIn, // Draw the dungeon
+ Left, Front, Right,
+ dungeon.Map[Pos.x][Pos.y], Monster);
+
+ Pos = Next; // Next position down
+ rOut = rIn; // Last in is new out
+ } while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(Front));
+}
+
+void Dungeon::_DDRAWCalcRect(Common::Rect *r, double Level) {
+ int xWidth, yWidth;
+ xWidth = (int) // Calculate frame size
+ (atan(1.0 / (Level + 1)) / atan(1.0) * 1279 + 0.5);
+ xWidth = 1279 / (Level + 1);
+ yWidth = xWidth * 10 / 13;
+ r->left = 640 - xWidth / 2; // Calculate drawing rectangle
+ r->right = 640 + xWidth / 2;
+ r->top = 512 + yWidth / 2;
+ r->bottom = 512 - yWidth / 2;
+}
+
+void Dungeon::MOVERotLeft(COORD *Dir) {
+ int t;
+ if (Dir->y == 0) Dir->x = -Dir->x;
+ t = Dir->x;
+ Dir->x = Dir->y;
+ Dir->y = t;
+}
+
+int Dungeon::DDRAWFindMonster(COORD *c) {
+ const auto &dungeon = g_engine->_dungeon;
+ int i, n = -1;
+ for (i = 0; i < dungeon.MonstCount; i++)
+ if (c->x == dungeon.Monster[i].Loc.x &&
+ c->y == dungeon.Monster[i].Loc.y &&
+ dungeon.Monster[i].Alive != 0) n = i;
+ return n;
+}
+
+void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
+ Common::Rect *rIn, int Left, int Centre, int Right, int Room, int Monster) {
+ int x1, y1, x, y, y2;
+ Common::Rect r;
+ double Scale;
+ int color;
+
+ HWColour(COL_WALL); /* Start on the walls */
+
+ if (ISDRAWOPEN(Left)) /* Do we draw the left edge */
+ {
+ HWLine(rOut->left, rIn->top, rIn->left, rIn->top);
+ HWLine(rOut->left, rIn->bottom, rIn->left, rIn->bottom);
+ HWLine(rOut->left, rOut->top, rOut->left, rOut->bottom);
+ } else /* If closed, draw left diags */
+ {
+ HWLine(rOut->left, rOut->top, rIn->left, rIn->top);
+ HWLine(rOut->left, rOut->bottom, rIn->left, rIn->bottom);
+ }
+
+ if (ISDRAWOPEN(Right)) /* Do we draw the right edge */
+ {
+ HWLine(rOut->right, rIn->top, rIn->right, rIn->top);
+ HWLine(rOut->right, rIn->bottom, rIn->right, rIn->bottom);
+ HWLine(rOut->right, rOut->top, rOut->right, rOut->bottom);
+ } else /* If closed draw right diags */
+ {
+ HWLine(rOut->right, rOut->top, rIn->right, rIn->top);
+ HWLine(rOut->right, rOut->bottom, rIn->right, rIn->bottom);
+ }
+
+ if (!ISDRAWOPEN(Centre)) /* Back wall ? */
+ {
+ HWLine(rIn->left, rIn->top, rIn->right, rIn->top);
+ HWLine(rIn->left, rIn->bottom, rIn->right, rIn->bottom);
+ if (!ISDRAWOPEN(Left)) /* Corner if left,right closed */
+ HWLine(rIn->left, rIn->top, rIn->left, rIn->bottom);
+ if (!ISDRAWOPEN(Right))
+ HWLine(rIn->right, rIn->top, rIn->right, rIn->bottom);
+ }
+
+ _DRAWSetRange(rOut->left, rIn->left, /* Set up for left side */
+ rOut->bottom,
+ rOut->bottom - rOut->top,
+ rIn->bottom - rIn->top);
+ _DRAWWall(s, Left);
+ _DRAWSetRange(rIn->right, rOut->right, /* Set up for right side */
+ rIn->bottom,
+ rIn->bottom - rIn->top,
+ rOut->bottom - rOut->top);
+ _DRAWWall(s, Right); /* Set up for centre */
+ _DRAWSetRange(rIn->left, rIn->right,
+ rIn->bottom,
+ rIn->bottom - rIn->top,
+ rIn->bottom - rIn->top);
+ _DRAWWall(s, Centre);
+
+ if (Room == DT_LADDERUP) {
+ r = Common::Rect(rOut->left, rOut->top, rOut->right, rIn->top);
+ _DRAWPit(s, &r, 1);
+ }
+ if (Room == DT_LADDERDN || Room == DT_PIT) {
+ r = Common::Rect(rOut->left, rIn->bottom, rOut->right, rOut->bottom);
+ _DRAWPit(s, &r, -1);
+ }
+
+ // Get the object area
+ r = Common::Rect(
+ (rIn->left + rOut->left) / 2,
+ (rIn->top + rOut->top) / 2,
+ (rIn->right + rOut->right) / 2,
+ (rIn->bottom + rOut->bottom) / 2);
+
+ // Ladder here ?
+ if (Room == DT_LADDERUP || Room == DT_LADDERDN) {
+ HWColour(COL_LADDER);
+ y1 = r.top; y2 = r.bottom;
+ x = (r.right - r.left) * 3 / 10;
+ HWLine(r.left + x, y1, r.left + x, y2);
+ HWLine(r.right - x, y1, r.right - x, y2);
+ x1 = (y1 - y2) / 5;
+ y = y2 + x1 / 2;
+ while (y < y1)
+ {
+ HWLine(r.left + x, y, r.right - x, y);
+ y = y + x1;
+ }
+ }
+
+ // Scale (trial and error this :))
+ Scale = 0.1;
+ Scale = Scale / (r.right - r.left) * 1059.0;
+
+ // Monster here ?
+ if (Monster > 0) {
+ HWColour(COL_MONSTER);
+ Monster::draw(s, (r.left + r.right) / 2, r.bottom, Monster, Scale);
+ }
+
+ // Draw the gold (as a mimic)
+ if (Room == DT_GOLD) {
+ HWColour(COL_MONSTER);
+ Monster::draw(s, (r.left + r.right) / 2, r.bottom, MN_MIMIC, Scale);
+ }
+}
+
+void Dungeon::_DRAWSetRange(int x1, int x2, int y, int yd1, int yd2) {
+ xLeft = x1; xRight = x2; /* Set x ranges */
+ yBottom = y; /* Set lower left y value */
+ yDiffLeft = yd1; yDiffRight = yd2; /* Set difference for either end */
+}
+
+void Dungeon::_DRAWWall(Graphics::ManagedSurface *s, int n) {
+ int x1, y1, x2, y2;
+ int color = 0;
+
+ if (n == DT_DOOR) {
+ HWColour(COL_DOOR);
+ x1 = 35; y1 = 0; x2 = 35; y2 = 60;
+ _DRAWConvert(&x1, &y1);
+ _DRAWConvert(&x2, &y2);
+ HWLine(x1, y1, x2, y2);
+ x1 = 65; y1 = 60; _DRAWConvert(&x1, &y1);
+ HWLine(x1, y1, x2, y2);
+ x2 = 65; y2 = 0; _DRAWConvert(&x2, &y2);
+ HWLine(x1, y1, x2, y2);
+ }
+}
+
+void Dungeon::_DRAWConvert(int *px, int *py) {
+ long x, y, yd; /* Longs for overflow in 16 bit */
+ x = (xRight - xLeft); /* Calculate width */
+ x = x * (*px) / 100 + xLeft; /* Work out horiz value */
+ yd = (yDiffRight - yDiffLeft); /* Work out height of vert for x */
+ yd = yd * (*px) / 100;
+ y = yBottom + /* Half of the distance */
+ yd / 2 - /* + Scaled total size */
+ (yd + yDiffLeft) * (*py) / 100;
+
+ *px = (int)x; /* Write back, casting to int */
+ *py = (int)y;
+}
+
+void Dungeon::_DRAWPit(Graphics::ManagedSurface *s, Common::Rect *r, int Dir) {
+ int x1, x2, y1;
+ int color;
+
+ HWColour(COL_HOLE);
+ y1 = (r->top - r->bottom) / 5;
+ r->bottom += y1; r->top -= y1;
+ x1 = (r->right - r->left) / 5;
+ r->left += x1; r->right -= x1;
+ x2 = 0; x1 = x1 / 2;
+ if (Dir > 0)
+ {
+ y1 = x1; x1 = x2; x2 = y1;
+ }
+ HWLine(r->left + x1, r->top, r->right - x1, r->top);
+ HWLine(r->left + x1, r->top, r->left + x2, r->bottom);
+ HWLine(r->left + x2, r->bottom, r->right - x2, r->bottom);
+ HWLine(r->right - x1, r->top, r->right - x2, r->bottom);
+
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
new file mode 100644
index 00000000000..51ac20c7290
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -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 ULTIMA0_GFX_MAP_H
+#define ULTIMA0_GFX_MAP_H
+
+#include "graphics/managed_surface.h"
+#include "ultima/ultima0/data/data.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+class Dungeon {
+private:
+ // Slanted drawing constants
+ static int xLeft, xRight, yBottom, yDiffLeft, yDiffRight;
+
+ /**
+ * Calculate display rectangle
+ */
+ static void _DDRAWCalcRect(Common::Rect *r, double Level);
+
+ /**
+ * Rotate a direction left
+ */
+ static void MOVERotLeft(COORD *Dir);
+
+ /**
+ * Find Monster ID at given location
+ */
+ static int DDRAWFindMonster(COORD *c);
+
+ /**
+ * Draw part of dungeon
+ */
+ static void DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
+ Common::Rect *rIn, int Left, int Centre, int Right, int Room, int Monster);
+
+ /**
+ * Set the oblique drawing routine
+ */
+ static void _DRAWSetRange(int x1, int x2, int y, int yd1, int yd2);
+
+ /**
+ * Draw wall object using current setting
+ */
+ static void _DRAWWall(Graphics::ManagedSurface *s, int n);
+
+ /**
+ * Convert coordinates from oblique to logical
+ */
+ static void _DRAWConvert(int *px, int *py);
+
+ /**
+ * Draw the pits/ladder hole
+ */
+ static void _DRAWPit(Graphics::ManagedSurface *s, Common::Rect *r, int Dir);
+
+public:
+ static void draw(Graphics::ManagedSurface *s);
+};
+
+} // namespace Gfx
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/gfx/map.h b/engines/ultima/ultima0/gfx/map.h
index 92c570b4a0c..89b77981835 100644
--- a/engines/ultima/ultima0/gfx/map.h
+++ b/engines/ultima/ultima0/gfx/map.h
@@ -36,7 +36,7 @@ public:
static void draw(Graphics::ManagedSurface *s, bool showAsMap = false);
};
-} // namespace Views
+} // namespace Gfx
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
new file mode 100644
index 00000000000..7658010c0a0
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -0,0 +1,201 @@
+/* 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 "ultima/ultima0/gfx/monster.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+Monster::DrawFn Monster::DRAW_FUNCTIONS[] = {
+ nullptr, _DRAWSkeleton, _DRAWThief, _DRAWRat, _DRAWOrc, _DRAWViper,
+ _DRAWCarrion, _DRAWGremlin, _DRAWMimic, _DRAWDaemon, _DRAWBalrog
+};
+int Monster::xPos = 640;
+int Monster::yPos = 512;
+
+#define END (-9999.99) /* End marker */
+
+#define HWColour(IDX) color = IDX
+#define X(n) (x1 + w * (n)/10)
+#define Y(n) (y1 + h * (n)/10)
+#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
+#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
+
+void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
+ int Monster, double Scale) {
+ const auto &player = g_engine->_player;
+ const auto &dungeon = g_engine->_dungeon;
+
+ xPos = x; yPos = y; // Save drawing pos
+ if (Monster == MN_MIMIC)
+ // Fix for Mimic/Chest
+ xPos = xPos - 90;
+
+ // Call appropriate function
+ assert(Monster <= MN_BALROG);
+ (*DRAW_FUNCTIONS)(s, 0, 0, Scale);
+}
+
+void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
+ va_list alist;
+ double y1, x1;
+ int color;
+
+ // Start reading values
+ va_start(alist, y);
+
+ do {
+ x1 = va_arg(alist, double); // Get the next two
+ y1 = va_arg(alist, double);
+ if (x1 != END && y1 != END) // If legit, draw the line
+ HWLine(xPos + x, yPos - y, xPos + x1, yPos - y1);
+ x = x1; y = y1;
+ } while (x1 != END && y1 != END);
+
+ va_end(alist);
+}
+
+void Monster::_DRAWSkeleton(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y - 23 / d, x, y - 15 / d, x, y - 15 / d, x - 15 / d, y - 8 / d, x - 30 / d, y + 8 / d, x - 30 / d, y + 15 / d, x - 15 / d, y + 15 / d, x, y + 23 / d, x, END, END);
+ _HPlot(s, y, x - 26 / d, y, x - 65 / d, END, END);
+ _HPlot(s, y - 2 / d + .5, x - 38 / d, y + 2 / d + .5, x - 38 / d, END, END);
+ _HPlot(s, y - 3 / d + .5, x - 45 / d, y + 3 / d + .5, x - 45 / d, END, END);
+ _HPlot(s, y - 5 / d + .5, x - 53 / d, y + 5 / d + .5, x - 53 / d, END, END);
+ _HPlot(s, y - 23 / d, x - 56 / d, y - 30 / d, x - 53 / d, y - 23 / d, x - 45 / d, y - 23 / d, x - 53 / d, y - 8 / d, x - 38 / d, END, END);
+ _HPlot(s, y - 15 / d, x - 45 / d, y - 8 / d, x - 60 / d, y + 8 / d, x - 60 / d, y + 15 / d, x - 45 / d, END, END);
+ _HPlot(s, y + 15 / d, x - 42 / d, y + 15 / d, x - 57 / d, END, END);
+ _HPlot(s, y + 12 / d, x - 45 / d, y + 20 / d, x - 45 / d, END, END);
+ _HPlot(s, y, x - 75 / d, y - 5 / d + .5, x - 80 / d, y - 8 / d, x - 75 / d, y - 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 65 / d, END, END);
+ _HPlot(s, y + 5 / d + .5, x - 65 / d, y + 8 / d, x - 75 / d, y + 5 / d + .5, x - 80 / d, y - 5 / d + .5, x - 80 / d, END, END);
+ _HPlot(s, y - 5 / d + .5, x - 72 / d, END, END);
+ _HPlot(s, y + 5 / d + .5, x - 72 / d, END, END);
+}
+
+void Monster::_DRAWThief(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y, x - 56 / d, y, x - 8 / d, y + 10 / d, x, y + 30 / d, x, y + 30 / d, x - 45 / d, y + 10 / d, x - 64 / d, y, x - 56 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 64 / d, y - 30 / d, x - 45 / d, y - 30 / d, x, y - 10 / d, x, y, x - 8 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 64 / d, y - 10 / d, x - 75 / d, y, x - 83 / d, y + 10 / d, x - 75 / d, y, x - 79 / d, y - 10 / d, x - 75 / d, y, x - 60 / d, y + 10 / d, x - 75 / d, y + 10 / d, x - 64 / d, END, END);
+}
+
+void Monster::_DRAWRat(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y + 5 / d, x - 30 / d, y, x - 25 / d, y - 5 / d, x - 30 / d, y - 15 / d, x - 5 / d, y - 10 / d, x, y + 10 / d, x, y + 15 / d, x - 5 / d, END, END);
+ _HPlot(s, y + 20 / d, x - 5 / d, y + 10 / d, x, y + 15 / d, x - 5 / d, y + 5 / d, x - 30 / d, y + 10 / d, x - 40 / d, y + 3 / d + .5, x - 35 / d, y - 3 / d + .5, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 30 / d, END, END);
+ _HPlot(s, y - 5 / d, x - 33 / d, y - 3 / d + .5, x - 30 / d, END, END);
+ _HPlot(s, y + 5 / d, x - 33 / d, y + 3 / d + .5, x - 30 / d, END, END);
+ _HPlot(s, y - 5 / d, x - 20 / d, y - 5 / d, x - 15 / d, END, END);
+ _HPlot(s, y + 5 / d, x - 20 / d, y + 5 / d, x - 15 / d, END, END);
+ _HPlot(s, y - 7 / d, x - 20 / d, y - 7 / d, x - 15 / d, END, END);
+ _HPlot(s, y + 7 / d, x - 20 / d, y + 7 / d, x - 15 / d, END, END);
+}
+
+void Monster::_DRAWOrc(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y, x, y - 15 / d, x, y - 8 / d, x - 8 / d, y - 8 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 23 / d, END, END);
+ _HPlot(s, y - 23 / d, x - 45 / d, y - 15 / d, x - 53 / d, y - 8 / d, x - 53 / d, y - 15 / d, x - 68 / d, y - 8 / d, x - 75 / d, y, x - 75 / d, END, END);
+ _HPlot(s, y, x, y + 15 / d, x, y + 8 / d, x - 8 / d, y + 8 / d, x - 15 / d, y + 15 / d, x - 23 / d, y + 15 / d, x - 15 / d, y + 23 / d, x - 23 / d, END, END);
+ _HPlot(s, y + 23 / d, x - 45 / d, y + 15 / d, x - 53 / d, y + 8 / d, x - 53 / d, y + 15 / d, x - 68 / d, y + 8 / d, x - 75 / d, y, x - 75 / d, END, END);
+ _HPlot(s, y - 15 / d, x - 68 / d, y + 15 / d, x - 68 / d, END, END);
+ _HPlot(s, y - 8 / d, x - 53 / d, y + 8 / d, x - 53 / d, END, END);
+ _HPlot(s, y - 23 / d, x - 15 / d, y + 8 / d, x - 45 / d, END, END);
+ _HPlot(s, y - 8 / d, x - 68 / d, y, x - 60 / d, y + 8 / d, x - 68 / d, y + 8 / d, x - 60 / d, y - 8 / d, x - 60 / d, y - 8 / d, x - 68 / d, END, END);
+ _HPlot(s, y, x - 38 / d, y - 8 / d, x - 38 / d, y + 8 / d, x - 53 / d, y + 8 / d, x - 45 / d, y + 15 / d, x - 45 / d, y, x - 30 / d, y, x - 38 / d, END, END);
+}
+
+void Monster::_DRAWViper(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y - 10 / d, x - 15 / d, y - 10 / d, x - 30 / d, y - 15 / d, x - 20 / d, y - 15 / d, x - 15 / d, y - 15 / d, x, y + 15 / d, x, y + 15 / d, x - 15 / d, y - 15 / d, x - 15 / d, END, END);
+ _HPlot(s, y - 15 / d, x - 10 / d, y + 15 / d, x - 10 / d, END, END);
+ _HPlot(s, y - 15 / d, x - 5 / d, y + 15 / d, x - 5 / d, END, END);
+ _HPlot(s, y, x - 15 / d, y - 5 / d, x - 20 / d, y - 5 / d, x - 35 / d, y + 5 / d, x - 35 / d, y + 5 / d, x - 20 / d, y + 10 / d, x - 15 / d, END, END);
+ _HPlot(s, y - 5 / d, x - 20 / d, y + 5 / d, x - 20 / d, END, END);
+ _HPlot(s, y - 5 / d, x - 25 / d, y + 5 / d, x - 25 / d, END, END);
+ _HPlot(s, y - 5 / d, x - 30 / d, y + 5 / d, x - 30 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 45 / d, y + 5 / d, x - 45 / d, y + 10 / d, x - 40 / d, y + 10 / d, x - 35 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 40 / d, y, x - 45 / d, y + 10 / d, x - 40 / d, END, END);
+ _HPlot(s, y - 5 / d, x - 40 / d, y + 5 / d, x - 40 / d, y + 15 / d, x - 30 / d, y, x - 40 / d, y - 15 / d, x - 30 / d, y - 5 / d + .5, x - 40 / d, END, END);
+}
+
+void Monster::_DRAWCarrion(Graphics::ManagedSurface *s, double x, double y, double d) {
+ /* 79-dst.recty(d) line here */
+ _HPlot(s, y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
+ _HPlot(s, y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
+ _HPlot(s, y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
+ _HPlot(s, y - 15 / d, x - 86 / d, y - 20 / d, x - 83 / d, y - 20 / d, x - 78 / d, y - 30 / d, x - 73 / d, y - 30 / d, x - 68 / d, y - 20 / d, x - 63 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 83 / d, y - 10 / d, x - 58 / d, y, x - 50 / d, END, END);
+ _HPlot(s, y + 10 / d, x - 83 / d, y + 10 / d, x - 78 / d, y + 20 / d, x - 73 / d, y + 20 / d, x - 40 / d, END, END);
+ _HPlot(s, y + 15 / d, x - 85 / d, y + 20 / d, x - 78 / d, y + 30 / d, x - 76 / d, y + 30 / d, x - 60 / d, END, END);
+ _HPlot(s, y, x - 83 / d, y, x - 73 / d, y + 10 / d, x - 68 / d, y + 10 / d, x - 63 / d, y, x - 58 / d, END, END);
+}
+
+void Monster::_DRAWGremlin(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y + 5 / d + .5, x - 10 / d, y - 5 / d + .5, x - 10 / d, y, x - 15 / d, y + 10 / d, x - 20 / d, y + 5 / d + .5, x - 15 / d, y + 5 / d + .5, x - 10 / d, END, END);
+ _HPlot(s, y + 7 / d + .5, x - 6 / d, y + 5 / d + .5, x - 3 / d, y - 5 / d + .5, x - 3 / d, y - 7 / d + .5, x - 6 / d, y - 5 / d + .5, x - 10 / d, END, END);
+ _HPlot(s, y + 2 / d + .5, x - 3 / d, y + 5 / d + .5, x, y + 8 / d, x, END, END);
+ _HPlot(s, y - 2 / d + .5, x - 3 / d, y - 5 / d + .5, x, y - 8 / d, x, END, END);
+ _HPlot(s, y + 3 / d + .5, x - 8 / d, END, END);
+ _HPlot(s, y - 3 / d + .5, x - 8 / d, END, END);
+ _HPlot(s, y + 3 / d + .5, x - 5 / d, y - 3 / d + .5, x - 5 / d, END, END);
+}
+
+void Monster::_DRAWMimic(Graphics::ManagedSurface *s, double x, double y, double d) {
+ double xx = x;
+ _HPlot(s, 139 - 10 / d, xx, 139 - 10 / d, xx - 10 / d, 139 + 10 / d, xx - 10 / d, 139 + 10 / d, xx, 139 - 10 / d, xx, END, END);
+ _HPlot(s, 139 - 10 / d, xx - 10 / d, 139 - 5 / d, xx - 15 / d, 139 + 15 / d, xx - 15 / d, 139 + 15 / d, xx - 5 / d, 139 + 10 / d, xx, END, END);
+ _HPlot(s, 139 + 10 / d, xx - 10 / d, 139 + 15 / d, xx - 15 / d, END, END);
+}
+
+void Monster::_DRAWDaemon(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y - 14 / d, x - 46 / d, y - 12 / d, x - 37 / d, y - 20 / d, x - 32 / d, y - 30 / d, x - 32 / d, y - 22 / d, x - 24 / d, y - 40 / d, x - 17 / d, y - 40 / d, x - 7 / d, y - 38 / d, x - 5 / d, y - 40 / d, x - 3 / d, y - 40 / d, x, END, END);
+ _HPlot(s, y - 36 / d, x, y - 34 / d, x - 2 / d, y - 32 / d, x, y - 28 / d, x, y - 28 / d, x - 3 / d, y - 30 / d, x - 5 / d, y - 28 / d, x - 7 / d, y - 28 / d, x - 15 / d, y, x - 27 / d, END, END);
+ _HPlot(s, y + 14 / d, x - 46 / d, y + 12 / d, x - 37 / d, y + 20 / d, x - 32 / d, y + 30 / d, x - 32 / d, y + 22 / d, x - 24 / d, y + 40 / d, x - 17 / d, y + 40 / d, x - 7 / d, y + 38 / d, x - 5 / d, y + 40 / d, x - 3 / d, y + 40 / d, x, END, END);
+ _HPlot(s, y + 36 / d, x, y + 34 / d, x - 2 / d, y + 32 / d, x, y + 28 / d, x, y + 28 / d, x - 3 / d, y + 30 / d, x - 5 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 15 / d, y, x - 27 / d, END, END);
+ _HPlot(s, y + 6 / d, x - 48 / d, y + 38 / d, x - 41 / d, y + 40 / d, x - 42 / d, y + 18 / d, x - 56 / d, y + 12 / d, x - 56 / d, y + 10 / d, x - 57 / d, y + 8 / d, x - 56 / d, y - 8 / d, x - 56 / d, y - 10 / d, x - 58 / d, y + 14 / d, x - 58 / d, y + 16 / d, x - 59 / d, END, END);
+ _HPlot(s, y + 8 / d, x - 63 / d, y + 6 / d, x - 63 / d, y + 2 / d + .5, x - 70 / d, y + 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 70 / d, y - 6 / d, x - 63 / d, y - 8 / d, x - 63 / d, y - 16 / d, x - 59 / d, y - 14 / d, x - 58 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 57 / d, y - 12 / d, x - 56 / d, y - 18 / d, x - 56 / d, y - 36 / d, x - 47 / d, y - 36 / d, x - 39 / d, y - 28 / d, x - 41 / d, y - 28 / d, x - 46 / d, y - 20 / d, x - 50 / d, y - 18 / d, x - 50 / d, y - 14 / d, x - 46 / d, END, END);
+ _HPlot(s, y - 28 / d, x - 41 / d, y + 30 / d, x - 55 / d, END, END);
+ _HPlot(s, y + 28 / d, x - 58 / d, y + 22 / d, x - 56 / d, y + 22 / d, x - 53 / d, y + 28 / d, x - 52 / d, y + 34 / d, x - 54 / d, END, END);
+ _HPlot(s, y + 20 / d, x - 50 / d, y + 26 / d, x - 47 / d, END, END);
+ _HPlot(s, y + 10 / d, x - 58 / d, y + 10 / d, x - 61 / d, y + 4 / d, x - 58 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 58 / d, y - 10 / d, x - 61 / d, y - 4 / d, x - 58 / d, END, END);
+ _HPlot(s, y + 40 / d, x - 9 / d, y + 50 / d, x - 12 / d, y + 40 / d, x - 7 / d, END, END);
+ _HPlot(s, y - 8 / d, x - 25 / d, y + 6 / d, x - 7 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 9 / d, y + 20 / d, x - 9 / d, y + 6 / d, x - 25 / d, END, END);
+}
+
+void Monster::_DRAWBalrog(Graphics::ManagedSurface *s, double x, double y, double d) {
+ _HPlot(s, y + 6 / d, x - 60 / d, y + 30 / d, x - 90 / d, y + 60 / d, x - 30 / d, y + 60 / d, x - 10 / d, y + 30 / d, x - 40 / d, y + 15 / d, x - 40 / d, END, END);
+ _HPlot(s, y - 6 / d, x - 60 / d, y - 30 / d, x - 90 / d, y - 60 / d, x - 30 / d, y - 60 / d, x - 10 / d, y - 30 / d, x - 40 / d, y - 15 / d, x - 40 / d, END, END);
+ _HPlot(s, y, x - 25 / d, y + 6 / d, x - 25 / d, y + 10 / d, x - 20 / d, y + 12 / d, x - 10 / d, y + 10 / d, x - 6 / d, y + 10 / d, x, y + 14 / d, x, y + 15 / d, x - 5 / d, y + 16 / d, x, y + 20 / d, x, END, END);
+ _HPlot(s, y + 20 / d, x - 6 / d, y + 18 / d, x - 10 / d, y + 18 / d, x - 20 / d, y + 15 / d, x - 30 / d, y + 15 / d, x - 45 / d, y + 40 / d, x - 60 / d, y + 40 / d, x - 70 / d, END, END);
+ _HPlot(s, y + 10 / d, x - 55 / d, y + 6 / d, x - 60 / d, y + 10 / d, x - 74 / d, y + 6 / d, x - 80 / d, y + 4 / d + .5, x - 80 / d, y + 3 / d + .5, x - 82 / d, y + 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
+ _HPlot(s, y, x - 25 / d, y - 6 / d, x - 25 / d, y - 10 / d, x - 20 / d, y - 12 / d, x - 10 / d, y - 10 / d, x - 6 / d, y - 10 / d, x, y - 14 / d, x, y - 15 / d, x - 5 / d, y - 16 / d, x, y - 20 / d, x, END, END);
+ _HPlot(s, y - 20 / d, x - 6 / d, y - 18 / d, x - 10 / d, y - 18 / d, x - 20 / d, y - 15 / d, x - 30 / d, y - 15 / d, x - 45 / d, y - 40 / d, x - 60 / d, y - 40 / d, x - 70 / d, END, END);
+ _HPlot(s, y - 10 / d, x - 55 / d, y - 6 / d, x - 60 / d, y - 10 / d, x - 74 / d, y - 6 / d, x - 80 / d, y - 4 / d + .5, x - 80 / d, y - 3 / d + .5, x - 82 / d, y - 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
+ _HPlot(s, y - 6 / d, x - 25 / d, y, x - 6 / d, y + 10 / d, x, y + 4 / d + .5, x - 8 / d, y + 6 / d, x - 25 / d, END, END);
+ _HPlot(s, y - 40 / d, x - 64 / d, y - 40 / d, x - 90 / d, y - 52 / d, x - 80 / d, y - 52 / d, x - 40 / d, END, END);
+ _HPlot(s, y + 40 / d, x - 86 / d, y + 38 / d, x - 92 / d, y + 42 / d, x - 92 / d, y + 40 / d, x - 86 / d, y + 40 / d, x - 50 / d, END, END);
+ _HPlot(s, y + 4 / d + .5, x - 70 / d, y + 6 / d, x - 74 / d, END, END);
+ _HPlot(s, y - 4 / d + .5, x - 70 / d, y - 6 / d, x - 74 / d, END, END);
+ _HPlot(s, y, x - 64 / d, y, x - 60 / d, END, END);
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/gfx/monster.h b/engines/ultima/ultima0/gfx/monster.h
new file mode 100644
index 00000000000..47add736c4d
--- /dev/null
+++ b/engines/ultima/ultima0/gfx/monster.h
@@ -0,0 +1,67 @@
+/* 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 ULTIMA0_GFX_MONSTER_H
+#define ULTIMA0_GFX_MONSTER_H
+
+#include "graphics/managed_surface.h"
+#include "ultima/ultima0/data/data.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Gfx {
+
+class Monster {
+private:
+ // Drawing position
+ static int xPos, yPos;
+
+ /**
+ * Emulate the Apple ][ HPLOT function
+ */
+ static void _HPlot(Graphics::ManagedSurface *s, double x, double y, ...);
+
+ /**
+ * Monster drawing functions
+ */
+ typedef void(*DrawFn)(Graphics::ManagedSurface *s, double x, double y, double d);
+ static void _DRAWSkeleton(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWThief(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWRat(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWOrc(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWViper(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWCarrion(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWGremlin(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWMimic(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWDaemon(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void _DRAWBalrog(Graphics::ManagedSurface *s, double x,double y,double d);
+ static DrawFn DRAW_FUNCTIONS[];
+
+public:
+ static void draw(Graphics::ManagedSurface *s, int x, int y,
+ int Monster, double Scale);
+};
+
+} // namespace Gfx
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
new file mode 100644
index 00000000000..ad3f67156dc
--- /dev/null
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -0,0 +1,182 @@
+/* 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 "ultima/ultima0/views/dungeon.h"
+#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/gfx/font.h"
+#include "ultima/ultima0/gfx/dungeon.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+Dungeon::Dungeon() : View("Dungeon") {
+}
+
+bool Dungeon::msgFocus(const FocusMessage &msg) {
+ return true;
+}
+
+void Dungeon::draw() {
+ auto s = getSurface();
+ s.clear();
+
+ // Allow the status area to draw
+ View::draw();
+
+ // Draw the dungeon view
+ Gfx::Dungeon::draw(&s);
+}
+
+bool Dungeon::msgAction(const ActionMessage &msg) {
+ if (isDelayActive())
+ return false;
+#ifdef TODO
+ switch (msg._action) {
+ case KEYBIND_UP:
+ showMessage("North");
+ move(0, -1);
+ break;
+ case KEYBIND_DOWN:
+ showMessage("South");
+ move(0, 1);
+ break;
+ case KEYBIND_LEFT:
+ showMessage("West");
+ move(-1, 0);
+ break;
+ case KEYBIND_RIGHT:
+ showMessage("East");
+ move(1, 0);
+ break;
+ case KEYBIND_INFO:
+ // Show character info screen
+ showMessage("");
+ replaceView("Info");
+ break;
+ case KEYBIND_ENTER:
+ case KEYBIND_SELECT:
+ enter();
+ break;
+ default:
+ showMessage("");
+ break;
+ }
+#endif
+ endOfTurn();
+ return true;
+}
+
+bool Dungeon::msgKeypress(const KeypressMessage &msg) {
+ if (isDelayActive())
+ return false;
+
+ switch (msg.keycode) {
+ case Common::KEYCODE_q:
+ // "Quit" in the original which merely saves the game. For ScummVM,
+ // we open the GMM, allowing the user to either save or quit
+ g_engine->openMainMenuDialog();
+ return true;
+
+ default:
+ break;
+ }
+
+ endOfTurn();
+ return true;
+}
+
+void Dungeon::endOfTurn() {
+#ifdef TODO
+ auto &player = g_engine->_player;
+
+ if (player.Attr[AT_HP] <= 0)
+ replaceView("Dead");
+
+ player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
+ if (player.Object[OB_FOOD] == 0) {
+ showMessage("You have starved...");
+ delaySeconds(1);
+ }
+#endif
+}
+
+void Dungeon::timeout() {
+ auto &player = g_engine->_player;
+
+ if (player.Attr[AT_HP] <= 0 || player.Object[OB_FOOD] <= 0) {
+ // Timeout from displaying player was killed
+ replaceView("Dead");
+ } else {
+ // TODO: timeout actions
+ }
+}
+
+void Dungeon::move(int xi, int yi) {
+#ifdef TODO
+ auto &player = g_engine->_player;
+ auto &map = g_engine->_worldMap;
+
+ // Calculate new position
+ int x1 = player.World.x + xi;
+ int y1 = player.World.y + yi;
+
+ if (map.read(x1, y1) == WT_MOUNTAIN) {
+ showMessage("You can't pass the mountains.");
+ } else {
+ // Move
+ player.World.x = x1;
+ player.World.y = y1;
+ redraw();
+ }
+#endif
+}
+
+void Dungeon::interact() {
+#ifdef TODO
+ const auto &player = g_engine->_player;
+ const auto &map = g_engine->_worldMap;
+
+ int t = map.read(player.World.x, player.World.y);
+ switch (t) {
+ case WT_TOWN:
+ showMessage("Enter Town.");
+ delaySeconds(1);
+ break;
+ case WT_DUNGEON:
+ showMessage("Enter Dungeon.");
+ delaySeconds(1);
+ break;
+ case WT_BRITISH:
+ showMessage("Enter Castle.");
+ delaySeconds(1);
+ break;
+ default:
+ // Nope....
+ showMessage("Huh???");
+ break;
+ }
+#endif
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/dungeon.h b/engines/ultima/ultima0/views/dungeon.h
new file mode 100644
index 00000000000..4eb19fd3d0d
--- /dev/null
+++ b/engines/ultima/ultima0/views/dungeon.h
@@ -0,0 +1,58 @@
+/* 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 ULTIMA0_VIEWS_DUNGEON_H
+#define ULTIMA0_VIEWS_DUNGEON_H
+
+#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/views/status.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Dungeon : public View {
+private:
+ Status _status = Status("DungeonStatus", this);
+
+ void move(int xi, int yi);
+ void interact();
+ void endOfTurn();
+ void showMessage(const Common::String &msg) {
+ _status.send(GameMessage("MSG", msg));
+ }
+
+public:
+ Dungeon();
+ ~Dungeon() override {}
+
+ bool msgFocus(const FocusMessage &msg) override;
+ void draw() override;
+ bool msgAction(const ActionMessage &msg) override;
+ bool msgKeypress(const KeypressMessage &msg) override;
+ void timeout() override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 006c0a823a8..c30f3e73ff5 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -25,6 +25,7 @@
#include "ultima/ultima0/views/castle.h"
#include "ultima/ultima0/views/create_character.h"
#include "ultima/ultima0/views/dead.h"
+#include "ultima/ultima0/views/dungeon.h"
#include "ultima/ultima0/views/info.h"
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
@@ -39,6 +40,7 @@ struct Views {
Castle _castle;
CreateCharacter _createCharacter;
Dead _dead;
+ Dungeon _dungeon;
Info _info;
Startup _startup;
Title _title;
Commit: 5dd272725ad38352928951b6ded0332d41e5fe3d
https://github.com/scummvm/scummvm/commit/5dd272725ad38352928951b6ded0332d41e5fe3d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Further dungeon drawing work
Changed paths:
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/dungeon.h
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 5b7181eb2b3..06b6069ec85 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -46,16 +46,16 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
s->clear();
double Level = 0;
- Common::Rect rOut(0, 1023 / 2, 1260 / 2, 10);
- Common::Rect rIn;
+ Common::Rect rIn, rOut;
COORD Dir, Pos, Next;
int Monster, Front, Left, Right;
- _DDRAWCalcRect(&rOut, 0);
+ _DDRAWCalcRect(s, &rOut, 0);
Pos = player.Dungeon; // Get position
+ // Iterate through drawing successively distinct tiles in the facing direction
do {
Level++; // Next level
- _DDRAWCalcRect(&rIn, Level);
+ _DDRAWCalcRect(s, &rIn, Level);
Next.x = Pos.x + player.DungDir.x; // Next position
Next.y = Pos.y + player.DungDir.y;
@@ -65,13 +65,13 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
Right = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
Front = dungeon.Map[Next.x][Next.y]; // What's in front ?
- Monster = DDRAWFindMonster(&Pos); // Find ID of monster here
- if (Monster >= 0) // Find Type if Found
- {
+ // Check for monster present
+ Monster = DDRAWFindMonster(&Pos);
+ if (Monster >= 0)
Monster = dungeon.Monster[Monster].Type;
- }
- DRAWDungeon(s, &rOut, &rIn, // Draw the dungeon
- Left, Front, Right,
+
+ // Draw the dungeon
+ DRAWDungeon(s, &rOut, &rIn, Left, Front, Right,
dungeon.Map[Pos.x][Pos.y], Monster);
Pos = Next; // Next position down
@@ -79,16 +79,18 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
} while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(Front));
}
-void Dungeon::_DDRAWCalcRect(Common::Rect *r, double Level) {
+void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double Level) {
+ const int surfW = s->w, surfH = s->h;
int xWidth, yWidth;
xWidth = (int) // Calculate frame size
- (atan(1.0 / (Level + 1)) / atan(1.0) * 1279 + 0.5);
- xWidth = 1279 / (Level + 1);
+ (atan(1.0 / (Level + 1)) / atan(1.0) * surfW + 0.5);
+ xWidth = surfW / (Level + 1);
yWidth = xWidth * 10 / 13;
- r->left = 640 - xWidth / 2; // Calculate drawing rectangle
- r->right = 640 + xWidth / 2;
- r->top = 512 + yWidth / 2;
- r->bottom = 512 - yWidth / 2;
+
+ r->left = surfW / 2 - xWidth / 2; // Calculate drawing rectangle
+ r->right = surfW / 2 + xWidth / 2;
+ r->top = surfH / 2 - yWidth / 2;
+ r->bottom = surfH / 2 + yWidth / 2;
}
void Dungeon::MOVERotLeft(COORD *Dir) {
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
index 51ac20c7290..fa0f51c1168 100644
--- a/engines/ultima/ultima0/gfx/dungeon.h
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -37,7 +37,7 @@ private:
/**
* Calculate display rectangle
*/
- static void _DDRAWCalcRect(Common::Rect *r, double Level);
+ static void _DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double Level);
/**
* Rotate a direction left
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index ad3f67156dc..0bf9c94861f 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -39,11 +39,12 @@ void Dungeon::draw() {
auto s = getSurface();
s.clear();
+ // Draw the dungeon view
+ Graphics::ManagedSurface dungArea(s, Common::Rect(0, 0, s.w, s.h - Gfx::CHAR_HEIGHT * 4));
+ Gfx::Dungeon::draw(&dungArea);
+
// Allow the status area to draw
View::draw();
-
- // Draw the dungeon view
- Gfx::Dungeon::draw(&s);
}
bool Dungeon::msgAction(const ActionMessage &msg) {
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 48fadaeef2b..4ea69671ce6 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -118,8 +118,9 @@ void WorldMap::endOfTurn() {
}
void WorldMap::timeout() {
- auto &player = g_engine->_player;
const auto &map = g_engine->_worldMap;
+ auto &player = g_engine->_player;
+ auto &dungeon = g_engine->_dungeon;
if (player.Attr[AT_HP] <= 0 || player.Object[OB_FOOD] <= 0) {
// Timeout from displaying player was killed
@@ -137,6 +138,7 @@ void WorldMap::timeout() {
player.Dungeon.y = 1;
player.DungDir.x = 1; // And direction
player.DungDir.y = 0;
+ dungeon.create(player);
replaceView("Dungeon");
break;
Commit: 68bca61e002785b04022ad20d6ca20a1fff4710e
https://github.com/scummvm/scummvm/commit/68bca61e002785b04022ad20d6ca20a1fff4710e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Fix aspect ratio of dungeon rendering
Changed paths:
engines/ultima/ultima0/gfx/dungeon.cpp
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 06b6069ec85..ee221de1cb8 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -80,17 +80,15 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
}
void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double Level) {
- const int surfW = s->w, surfH = s->h;
+ const int centerX = s->w / 2, centerY = s->h / 2;
int xWidth, yWidth;
- xWidth = (int) // Calculate frame size
- (atan(1.0 / (Level + 1)) / atan(1.0) * surfW + 0.5);
- xWidth = surfW / (Level + 1);
- yWidth = xWidth * 10 / 13;
-
- r->left = surfW / 2 - xWidth / 2; // Calculate drawing rectangle
- r->right = surfW / 2 + xWidth / 2;
- r->top = surfH / 2 - yWidth / 2;
- r->bottom = surfH / 2 + yWidth / 2;
+ xWidth = s->w / (Level + 1);
+ yWidth = s->h / (Level + 1); // xWidth * 10 / 13;
+
+ r->left = centerX - xWidth / 2; // Calculate drawing rectangle
+ r->right = centerX + xWidth / 2;
+ r->top = centerY - yWidth / 2;
+ r->bottom = centerY + yWidth / 2;
}
void Dungeon::MOVERotLeft(COORD *Dir) {
Commit: cb44874c2ab01b8d89958099cd692c4ac32b16ea
https://github.com/scummvm/scummvm/commit/cb44874c2ab01b8d89958099cd692c4ac32b16ea
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Display direction in Dungeon status area
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/views/dungeon.h
engines/ultima/ultima0/views/status.cpp
engines/ultima/ultima0/views/status.h
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index f395a08f126..47d5a281e03 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -49,6 +49,7 @@ const _MInfStruct MONSTER_INFO[] = {
};
const char *ATTRIB_NAMES[] = { "Hit Points", "Strength", "Dexterity", "Stamina", "Wisdom", "Gold" };
+const char *const DIRECTION_NAMES[] = { "North", "East", "South", "West" };
/*-------------------------------------------------------------------*/
@@ -99,6 +100,17 @@ void PLAYER::synchronize(Common::Serializer &s) {
}
}
+int PLAYER::dungeonDir() const {
+ if (Dungeon.y < 0)
+ return DIR_NORTH;
+ else if (Dungeon.x > 0)
+ return DIR_EAST;
+ else if (Dungeon.y > 0)
+ return DIR_SOUTH;
+ else
+ return DIR_WEST;
+}
+
/*-------------------------------------------------------------------*/
void WORLDMAP::init(PLAYER &p) {
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 53f677acf22..662dd11ecf5 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -29,6 +29,8 @@
namespace Ultima {
namespace Ultima0 {
+enum Direction { DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST };
+
struct PLAYER;
struct _OInfStruct {
@@ -44,7 +46,7 @@ struct _MInfStruct {
extern const _OInfStruct OBJECT_INFO[];
extern const _MInfStruct MONSTER_INFO[];
extern const char *ATTRIB_NAMES[];
-
+extern const char *const DIRECTION_NAMES[];
// point/rect types
typedef Common::Point COORD;
@@ -101,6 +103,11 @@ struct PLAYER {
void init();
void rollAttributes();
void synchronize(Common::Serializer &s);
+
+ /**
+ * Return the dungeon facing direction
+ */
+ int dungeonDir() const;
};
/**
diff --git a/engines/ultima/ultima0/views/dungeon.h b/engines/ultima/ultima0/views/dungeon.h
index 4eb19fd3d0d..1bf3e8aaae6 100644
--- a/engines/ultima/ultima0/views/dungeon.h
+++ b/engines/ultima/ultima0/views/dungeon.h
@@ -31,7 +31,7 @@ namespace Views {
class Dungeon : public View {
private:
- Status _status = Status("DungeonStatus", this);
+ DungeonStatus _status = DungeonStatus(this);
void move(int xi, int yi);
void interact();
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index fedcac49964..0adb0ec548b 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -37,8 +37,6 @@ void Status::draw() {
if (!_message.empty())
s.writeString(Common::Point(1, 0), _message);
- if (!_direction.empty())
- s.writeString(Common::Point(15, 0), _direction);
s.writeString(Common::Point(28, 1), "Food=");
s.writeString(Common::Point(28, 2), "H.P.=");
@@ -59,6 +57,16 @@ bool Status::msgGame(const GameMessage &msg) {
return false;
}
+/*-------------------------------------------------------------------*/
+
+void DungeonStatus::draw() {
+ Status::draw();
+
+ const auto &player = g_engine->_player;
+ auto s = getSurface();
+ s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/status.h b/engines/ultima/ultima0/views/status.h
index fbce224d4d6..32a14165336 100644
--- a/engines/ultima/ultima0/views/status.h
+++ b/engines/ultima/ultima0/views/status.h
@@ -41,6 +41,20 @@ public:
bool msgGame(const GameMessage &msg) override;
};
+class OverworldStatus : public Status {
+public:
+ OverworldStatus(UIElement *parent) : Status("OverworldStatus", parent) {
+ }
+};
+
+class DungeonStatus : public Status {
+public:
+ DungeonStatus(UIElement *parent) : Status("DungeonStatus", parent) {
+ }
+
+ void draw() override;
+};
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index d989f54ea0d..8b6cf56bdc4 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -31,7 +31,7 @@ namespace Views {
class WorldMap : public View {
private:
- Status _status = Status("MapStatus", this);
+ OverworldStatus _status = OverworldStatus(this);
void move(int xi, int yi);
void enter();
Commit: fe5368591a04892a9d083d37eaad42cf248be509
https://github.com/scummvm/scummvm/commit/fe5368591a04892a9d083d37eaad42cf248be509
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:27+11:00
Commit Message:
ULTIMA: ULTIMA0: Adding dungeon movement
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/gfx/monster.cpp
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/dungeon.h
engines/ultima/ultima0/views/info.cpp
engines/ultima/ultima0/views/status.cpp
engines/ultima/ultima0/views/status.h
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 47d5a281e03..bb261b48cbf 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -100,17 +100,46 @@ void PLAYER::synchronize(Common::Serializer &s) {
}
}
-int PLAYER::dungeonDir() const {
- if (Dungeon.y < 0)
+Direction PLAYER::dungeonDir() const {
+ if (DungDir.y < 0)
return DIR_NORTH;
- else if (Dungeon.x > 0)
+ else if (DungDir.x > 0)
return DIR_EAST;
- else if (Dungeon.y > 0)
+ else if (DungDir.y > 0)
return DIR_SOUTH;
else
return DIR_WEST;
}
+void PLAYER::setDungeonDir(Direction newDir) {
+ DungDir.x = 0;
+ DungDir.y = 0;
+ switch (newDir) {
+ case DIR_NORTH:
+ DungDir.y = -1;
+ break;
+ case DIR_EAST:
+ DungDir.x = 1;
+ break;
+ case DIR_SOUTH:
+ DungDir.y = 1;
+ break;
+ case DIR_WEST:
+ DungDir.x = -1;
+ break;
+ }
+}
+
+void PLAYER::dungeonTurnLeft() {
+ Direction dir = dungeonDir();
+ setDungeonDir((dir == DIR_NORTH) ? DIR_WEST : (Direction)((int)dir - 1));
+}
+
+void PLAYER::dungeonTurnRight() {
+ Direction dir = dungeonDir();
+ setDungeonDir((dir == DIR_WEST) ? DIR_NORTH : (Direction)((int)dir + 1));
+}
+
/*-------------------------------------------------------------------*/
void WORLDMAP::init(PLAYER &p) {
@@ -272,5 +301,14 @@ void DUNGEONMAP::synchronize(Common::Serializer &s) {
s.syncAsByte(Map[x][y]);
}
+int DUNGEONMAP::findMonster(const COORD &c) const {
+ int i, n = -1;
+ for (i = 0; i < MonstCount; i++)
+ if (c.x == Monster[i].Loc.x &&
+ c.y == Monster[i].Loc.y &&
+ Monster[i].Alive != 0) n = i;
+ return n;
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 662dd11ecf5..f4c045c08ef 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -78,6 +78,11 @@ public:
void create(const PLAYER &player);
void synchronize(Common::Serializer &s);
+
+ /**
+ * Find Monster ID at given location
+ */
+ int findMonster(const COORD &c) const;
};
/**
@@ -107,7 +112,22 @@ struct PLAYER {
/**
* Return the dungeon facing direction
*/
- int dungeonDir() const;
+ Direction dungeonDir() const;
+
+ /**
+ * Sets the dungeon direction
+ */
+ void setDungeonDir(Direction newDir);
+
+ /**
+ * Turn left in the dungeon
+ */
+ void dungeonTurnLeft();
+
+ /**
+ * Turn right in the dungeon
+ */
+ void dungeonTurnRight();
};
/**
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index 7658010c0a0..e99b12d2c6a 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -43,10 +43,8 @@ int Monster::yPos = 512;
void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
int Monster, double Scale) {
- const auto &player = g_engine->_player;
- const auto &dungeon = g_engine->_dungeon;
-
- xPos = x; yPos = y; // Save drawing pos
+ // Save drawing pos
+ xPos = x; yPos = y;
if (Monster == MN_MIMIC)
// Fix for Mimic/Chest
xPos = xPos - 90;
@@ -59,7 +57,7 @@ void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
va_list alist;
double y1, x1;
- int color;
+ int color = 0;
// Start reading values
va_start(alist, y);
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 0bf9c94861f..e13caf526f2 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -48,25 +48,28 @@ void Dungeon::draw() {
}
bool Dungeon::msgAction(const ActionMessage &msg) {
+ auto &player = g_engine->_player;
+
if (isDelayActive())
return false;
-#ifdef TODO
+
switch (msg._action) {
case KEYBIND_UP:
- showMessage("North");
- move(0, -1);
+ showMessage("Move Forward");
+ moveForward();
break;
case KEYBIND_DOWN:
- showMessage("South");
- move(0, 1);
+ showMessage("Turn Around");
+ player.dungeonTurnLeft();
+ player.dungeonTurnLeft();
break;
case KEYBIND_LEFT:
- showMessage("West");
- move(-1, 0);
+ showMessage("Turn Left");
+ player.dungeonTurnLeft();
break;
case KEYBIND_RIGHT:
- showMessage("East");
- move(1, 0);
+ showMessage("Turn Right");
+ player.dungeonTurnRight();
break;
case KEYBIND_INFO:
// Show character info screen
@@ -74,14 +77,13 @@ bool Dungeon::msgAction(const ActionMessage &msg) {
replaceView("Info");
break;
case KEYBIND_ENTER:
- case KEYBIND_SELECT:
- enter();
+ interact();
break;
default:
showMessage("");
break;
}
-#endif
+
endOfTurn();
return true;
}
@@ -106,76 +108,77 @@ bool Dungeon::msgKeypress(const KeypressMessage &msg) {
}
void Dungeon::endOfTurn() {
-#ifdef TODO
auto &player = g_engine->_player;
if (player.Attr[AT_HP] <= 0)
replaceView("Dead");
- player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
+ player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 0.1, 0.0);
if (player.Object[OB_FOOD] == 0) {
showMessage("You have starved...");
delaySeconds(1);
}
-#endif
+
+ redraw();
}
-void Dungeon::timeout() {
+void Dungeon::moveForward() {
+ const auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
+ COORD New = player.Dungeon + player.DungDir;
- if (player.Attr[AT_HP] <= 0 || player.Object[OB_FOOD] <= 0) {
- // Timeout from displaying player was killed
- replaceView("Dead");
- } else {
- // TODO: timeout actions
- }
+ if (!ISWALKTHRU(dungeon.Map[New.x][New.y]) || dungeon.findMonster(New) >= 0)
+ return;
+
+ // Set new position
+ player.Dungeon = New;
+
+ // TODO: other stuff
}
-void Dungeon::move(int xi, int yi) {
-#ifdef TODO
+void Dungeon::interact() {
+ auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
- auto &map = g_engine->_worldMap;
-
- // Calculate new position
- int x1 = player.World.x + xi;
- int y1 = player.World.y + yi;
-
- if (map.read(x1, y1) == WT_MOUNTAIN) {
- showMessage("You can't pass the mountains.");
- } else {
- // Move
- player.World.x = x1;
- player.World.y = y1;
- redraw();
+
+ // Identify what's there
+ int t = dungeon.Map[player.Dungeon.x][player.Dungeon.y];
+ bool done = false;
+
+ if (t == DT_LADDERUP) {
+ // Climbing up a ladder
+ player.Level--;
+ done = true;
+
+ if (player.Level == 0) {
+ showMessage("Leave Dungeon.");
+ showLines(Common::String::format("Thou has gained %d hit points.", player.HPGain));
+ player.Attr[AT_HP] += player.HPGain;
+ player.HPGain = 0;
+
+ } else {
+ showMessage("Use Ladder");
+ showLines(Common::String::format("Go up to Level %d.", player.Level));
+ }
+ } else if (t == DT_LADDERDN) {
+ // Climbing down a ladder
+ player.Level++;
+ done = true;
+
+ showMessage("Use Ladder");
+ showLines(Common::String::format("Go down to Level %d.\n", player.Level));
}
-#endif
+
+ if (done && player.Level > 0)
+ // New Dungeon Map Required
+ dungeon.create(player);
+ else
+ showMessage("Huh???");
}
-void Dungeon::interact() {
-#ifdef TODO
+void Dungeon::timeout() {
const auto &player = g_engine->_player;
- const auto &map = g_engine->_worldMap;
- int t = map.read(player.World.x, player.World.y);
- switch (t) {
- case WT_TOWN:
- showMessage("Enter Town.");
- delaySeconds(1);
- break;
- case WT_DUNGEON:
- showMessage("Enter Dungeon.");
- delaySeconds(1);
- break;
- case WT_BRITISH:
- showMessage("Enter Castle.");
- delaySeconds(1);
- break;
- default:
- // Nope....
- showMessage("Huh???");
- break;
- }
-#endif
+ replaceView((player.Level == 0) ? "WorldMap" : "Dead");
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/dungeon.h b/engines/ultima/ultima0/views/dungeon.h
index 1bf3e8aaae6..b2321dab0e1 100644
--- a/engines/ultima/ultima0/views/dungeon.h
+++ b/engines/ultima/ultima0/views/dungeon.h
@@ -33,12 +33,15 @@ class Dungeon : public View {
private:
DungeonStatus _status = DungeonStatus(this);
- void move(int xi, int yi);
+ void moveForward();
void interact();
void endOfTurn();
void showMessage(const Common::String &msg) {
_status.send(GameMessage("MSG", msg));
}
+ void showLines(const Common::String &msg) {
+ _status.send(GameMessage("LINES", msg));
+ }
public:
Dungeon();
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
index 788fca81ca9..cddcf993fb2 100644
--- a/engines/ultima/ultima0/views/info.cpp
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -101,7 +101,8 @@ bool Info::msgKeypress(const KeypressMessage &msg) {
}
void Info::leave() {
- replaceView("WorldMap");
+ const auto &player = g_engine->_player;
+ replaceView(player.Level == 0 ? "WorldMap" : "DungeonMap");
}
bool Info::msgAction(const ActionMessage &msg) {
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index 0adb0ec548b..c42531b7cb0 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -30,6 +30,11 @@ Status::Status(const Common::String &name, UIElement *parent) : View(name, paren
setBounds(Common::Rect(0, DEFAULT_SCY - 4 * Gfx::CHAR_HEIGHT, DEFAULT_SCX, DEFAULT_SCY));
}
+bool Status::msgFocus(const FocusMessage &msg) {
+ _message.clear();
+ return View::msgFocus(msg);
+}
+
void Status::draw() {
const auto &player = g_engine->_player;
auto s = getSurface();
@@ -59,12 +64,42 @@ bool Status::msgGame(const GameMessage &msg) {
/*-------------------------------------------------------------------*/
+bool DungeonStatus::msgFocus(const FocusMessage &msg) {
+ _lines.clear();
+ return Status::msgFocus(msg);
+}
+
void DungeonStatus::draw() {
Status::draw();
const auto &player = g_engine->_player;
auto s = getSurface();
+
+ // Display the current direction
s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
+
+ // Add any extra
+}
+
+bool DungeonStatus::msgGame(const GameMessage &msg) {
+ if (msg._name == "LINES") {
+ _lines.clear();
+
+ Common::String str = msg._stringValue;
+ uint p;
+ while ((p = str.findFirstOf('\n')) != Common::String::npos) {
+ _lines.push_back(Common::String(str.c_str(), str.c_str() + p));
+ str = Common::String(str.c_str() + p + 1);
+ }
+ if (!str.empty())
+ _lines.push_back(str);
+
+ redraw();
+ return true;
+
+ } else {
+ return Status::msgGame(msg);
+ }
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/status.h b/engines/ultima/ultima0/views/status.h
index 32a14165336..7cf5cd6b20e 100644
--- a/engines/ultima/ultima0/views/status.h
+++ b/engines/ultima/ultima0/views/status.h
@@ -37,6 +37,7 @@ public:
Status(const Common::String &name, UIElement *parent);
~Status() override {}
+ bool msgFocus(const FocusMessage &msg) override;
void draw() override;
bool msgGame(const GameMessage &msg) override;
};
@@ -48,11 +49,16 @@ public:
};
class DungeonStatus : public Status {
+private:
+ Common::StringArray _lines;
+
public:
DungeonStatus(UIElement *parent) : Status("DungeonStatus", parent) {
}
+ bool msgFocus(const FocusMessage &msg) override;
void draw() override;
+ bool msgGame(const GameMessage &msg) override;
};
} // namespace Views
Commit: 5819ba67dc261530db70fc2b6af172ae11e627d8
https://github.com/scummvm/scummvm/commit/5819ba67dc261530db70fc2b6af172ae11e627d8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:28+11:00
Commit Message:
ULTIMA: ULTIMA0: Dungeon rendering cleanup
Changed paths:
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/dungeon.h
engines/ultima/ultima0/gfx/monster.cpp
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index ee221de1cb8..8955391aa9b 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -54,19 +54,19 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
// Iterate through drawing successively distinct tiles in the facing direction
do {
- Level++; // Next level
+ Level++; // Next level
_DDRAWCalcRect(s, &rIn, Level);
Next.x = Pos.x + player.DungDir.x; // Next position
Next.y = Pos.y + player.DungDir.y;
Dir = player.DungDir; MOVERotLeft(&Dir); // To the left
Left = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
- MOVERotLeft(&Dir); MOVERotLeft(&Dir);// To the right
+ MOVERotLeft(&Dir); MOVERotLeft(&Dir); // To the right
Right = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
Front = dungeon.Map[Next.x][Next.y]; // What's in front ?
// Check for monster present
- Monster = DDRAWFindMonster(&Pos);
+ Monster = dungeon.findMonster(Pos);
if (Monster >= 0)
Monster = dungeon.Monster[Monster].Type;
@@ -81,11 +81,11 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double Level) {
const int centerX = s->w / 2, centerY = s->h / 2;
- int xWidth, yWidth;
- xWidth = s->w / (Level + 1);
- yWidth = s->h / (Level + 1); // xWidth * 10 / 13;
+ int xWidth = s->w / (Level + 1);
+ int yWidth = s->h / (Level + 1);
- r->left = centerX - xWidth / 2; // Calculate drawing rectangle
+ // Set bounding box
+ r->left = centerX - xWidth / 2;
r->right = centerX + xWidth / 2;
r->top = centerY - yWidth / 2;
r->bottom = centerY + yWidth / 2;
@@ -99,16 +99,6 @@ void Dungeon::MOVERotLeft(COORD *Dir) {
Dir->y = t;
}
-int Dungeon::DDRAWFindMonster(COORD *c) {
- const auto &dungeon = g_engine->_dungeon;
- int i, n = -1;
- for (i = 0; i < dungeon.MonstCount; i++)
- if (c->x == dungeon.Monster[i].Loc.x &&
- c->y == dungeon.Monster[i].Loc.y &&
- dungeon.Monster[i].Alive != 0) n = i;
- return n;
-}
-
void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
Common::Rect *rIn, int Left, int Centre, int Right, int Room, int Monster) {
int x1, y1, x, y, y2;
@@ -116,50 +106,55 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
double Scale;
int color;
- HWColour(COL_WALL); /* Start on the walls */
+ HWColour(COL_WALL); // Start on the walls
- if (ISDRAWOPEN(Left)) /* Do we draw the left edge */
- {
+ // Do we draw the left edge
+ if (ISDRAWOPEN(Left)) {
HWLine(rOut->left, rIn->top, rIn->left, rIn->top);
HWLine(rOut->left, rIn->bottom, rIn->left, rIn->bottom);
HWLine(rOut->left, rOut->top, rOut->left, rOut->bottom);
- } else /* If closed, draw left diags */
- {
+ } else {
+ // If closed, draw left diags
HWLine(rOut->left, rOut->top, rIn->left, rIn->top);
HWLine(rOut->left, rOut->bottom, rIn->left, rIn->bottom);
}
- if (ISDRAWOPEN(Right)) /* Do we draw the right edge */
- {
+ // Do we draw the right edge
+ if (ISDRAWOPEN(Right)) {
HWLine(rOut->right, rIn->top, rIn->right, rIn->top);
HWLine(rOut->right, rIn->bottom, rIn->right, rIn->bottom);
HWLine(rOut->right, rOut->top, rOut->right, rOut->bottom);
- } else /* If closed draw right diags */
- {
+ } else {
+ // If closed draw right diags
HWLine(rOut->right, rOut->top, rIn->right, rIn->top);
HWLine(rOut->right, rOut->bottom, rIn->right, rIn->bottom);
}
- if (!ISDRAWOPEN(Centre)) /* Back wall ? */
- {
+ // Back wall ?
+ if (!ISDRAWOPEN(Centre)) {
HWLine(rIn->left, rIn->top, rIn->right, rIn->top);
HWLine(rIn->left, rIn->bottom, rIn->right, rIn->bottom);
- if (!ISDRAWOPEN(Left)) /* Corner if left,right closed */
+ if (!ISDRAWOPEN(Left)) // Corner if left,right closed
HWLine(rIn->left, rIn->top, rIn->left, rIn->bottom);
if (!ISDRAWOPEN(Right))
HWLine(rIn->right, rIn->top, rIn->right, rIn->bottom);
}
- _DRAWSetRange(rOut->left, rIn->left, /* Set up for left side */
+ // Set up for left side
+ _DRAWSetRange(rOut->left, rIn->left,
rOut->bottom,
rOut->bottom - rOut->top,
rIn->bottom - rIn->top);
_DRAWWall(s, Left);
- _DRAWSetRange(rIn->right, rOut->right, /* Set up for right side */
+
+ // Set up for right side
+ _DRAWSetRange(rIn->right, rOut->right,
rIn->bottom,
rIn->bottom - rIn->top,
rOut->bottom - rOut->top);
- _DRAWWall(s, Right); /* Set up for centre */
+ _DRAWWall(s, Right);
+
+ // Set up for centre
_DRAWSetRange(rIn->left, rIn->right,
rIn->bottom,
rIn->bottom - rIn->top,
@@ -216,9 +211,9 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
}
void Dungeon::_DRAWSetRange(int x1, int x2, int y, int yd1, int yd2) {
- xLeft = x1; xRight = x2; /* Set x ranges */
- yBottom = y; /* Set lower left y value */
- yDiffLeft = yd1; yDiffRight = yd2; /* Set difference for either end */
+ xLeft = x1; xRight = x2; // Set x ranges
+ yBottom = y; // Set lower left y value
+ yDiffLeft = yd1; yDiffRight = yd2; // Set difference for either end
}
void Dungeon::_DRAWWall(Graphics::ManagedSurface *s, int n) {
@@ -239,16 +234,16 @@ void Dungeon::_DRAWWall(Graphics::ManagedSurface *s, int n) {
}
void Dungeon::_DRAWConvert(int *px, int *py) {
- long x, y, yd; /* Longs for overflow in 16 bit */
- x = (xRight - xLeft); /* Calculate width */
- x = x * (*px) / 100 + xLeft; /* Work out horiz value */
- yd = (yDiffRight - yDiffLeft); /* Work out height of vert for x */
+ long x, y, yd; // Longs for overflow in 16 bit
+ x = (xRight - xLeft); // Calculate width
+ x = x * (*px) / 100 + xLeft; // Work out horiz value
+ yd = (yDiffRight - yDiffLeft); // Work out height of vert for x
yd = yd * (*px) / 100;
- y = yBottom + /* Half of the distance */
- yd / 2 - /* + Scaled total size */
+ y = yBottom + // Half of the distance
+ yd / 2 - // + Scaled total size
(yd + yDiffLeft) * (*py) / 100;
- *px = (int)x; /* Write back, casting to int */
+ *px = (int)x; // Write back, casting to int
*py = (int)y;
}
@@ -270,7 +265,6 @@ void Dungeon::_DRAWPit(Graphics::ManagedSurface *s, Common::Rect *r, int Dir) {
HWLine(r->left + x1, r->top, r->left + x2, r->bottom);
HWLine(r->left + x2, r->bottom, r->right - x2, r->bottom);
HWLine(r->right - x1, r->top, r->right - x2, r->bottom);
-
}
} // namespace Views
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
index fa0f51c1168..2534dc80a9f 100644
--- a/engines/ultima/ultima0/gfx/dungeon.h
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -44,11 +44,6 @@ private:
*/
static void MOVERotLeft(COORD *Dir);
- /**
- * Find Monster ID at given location
- */
- static int DDRAWFindMonster(COORD *c);
-
/**
* Draw part of dungeon
*/
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index e99b12d2c6a..41b3fd14fcd 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -50,7 +50,7 @@ void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
xPos = xPos - 90;
// Call appropriate function
- assert(Monster <= MN_BALROG);
+ assert(Monster > 0 && Monster <= MN_BALROG);
(*DRAW_FUNCTIONS)(s, 0, 0, Scale);
}
Commit: b7e0257de76d88541cac03dc95726c9a3ba56955
https://github.com/scummvm/scummvm/commit/b7e0257de76d88541cac03dc95726c9a3ba56955
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:28+11:00
Commit Message:
ULTIMA: ULTIMA0: Fix ladder display
Changed paths:
engines/ultima/ultima0/gfx/dungeon.cpp
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 8955391aa9b..656798e9047 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -182,15 +182,15 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
HWColour(COL_LADDER);
y1 = r.top; y2 = r.bottom;
x = (r.right - r.left) * 3 / 10;
+
+ // Vertical lines
HWLine(r.left + x, y1, r.left + x, y2);
HWLine(r.right - x, y1, r.right - x, y2);
- x1 = (y1 - y2) / 5;
- y = y2 + x1 / 2;
- while (y < y1)
- {
+ x1 = (y2 - y1) / 5;
+
+ // Horizontal ladder rungs
+ for (y = y1 + x1 / 2; y < y2; y += x1)
HWLine(r.left + x, y, r.right - x, y);
- y = y + x1;
- }
}
// Scale (trial and error this :))
Commit: 5fecb72f188761d6e6c44722e074c06fb90e4c9e
https://github.com/scummvm/scummvm/commit/5fecb72f188761d6e6c44722e074c06fb90e4c9e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:28+11:00
Commit Message:
ULTIMA: ULTIMA0: Implement dungeon status messages
Changed paths:
engines/ultima/ultima0/gfx/gfx_surface.cpp
engines/ultima/ultima0/gfx/monster.cpp
engines/ultima/ultima0/views/status.cpp
diff --git a/engines/ultima/ultima0/gfx/gfx_surface.cpp b/engines/ultima/ultima0/gfx/gfx_surface.cpp
index 50dcc475852..d4ba51cca71 100644
--- a/engines/ultima/ultima0/gfx/gfx_surface.cpp
+++ b/engines/ultima/ultima0/gfx/gfx_surface.cpp
@@ -34,12 +34,16 @@ void GfxSurface::writeString(const Common::Point &pt, const Common::String &str,
}
void GfxSurface::writeString(const Common::String &str, Graphics::TextAlign align) {
+ size_t strSize = 0;
+ for (const char *p = str.c_str(); *p; ++p)
+ strSize += Common::isPrint(*p) ? 1 : 0;
+
switch (align) {
case Graphics::kTextAlignCenter:
- _textPos.x -= str.size() / 2;
+ _textPos.x -= strSize / 2;
break;
case Graphics::kTextAlignRight:
- _textPos.x -= str.size();
+ _textPos.x -= strSize;
break;
case Graphics::kTextAlignLeft:
default:
@@ -50,6 +54,8 @@ void GfxSurface::writeString(const Common::String &str, Graphics::TextAlign alig
if (*p == '\n') {
assert(align == Graphics::kTextAlignLeft);
newLine();
+ } else if (*p < 32) {
+ setColor((byte)*p);
} else {
writeChar(*p);
}
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index 41b3fd14fcd..06ebf76c61a 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -51,7 +51,7 @@ void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
// Call appropriate function
assert(Monster > 0 && Monster <= MN_BALROG);
- (*DRAW_FUNCTIONS)(s, 0, 0, Scale);
+ (*DRAW_FUNCTIONS[Monster])(s, 0, 0, Scale);
}
void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index c42531b7cb0..48558d05a66 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -78,7 +78,9 @@ void DungeonStatus::draw() {
// Display the current direction
s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
- // Add any extra
+ // Draw any extra lines
+ for (uint i = 0; i < _lines.size(); ++i)
+ s.writeString(Common::Point(0, 1 + i), _lines[i]);
}
bool DungeonStatus::msgGame(const GameMessage &msg) {
Commit: 15d2deed5ac3da296cdd03af6457801d67996397
https://github.com/scummvm/scummvm/commit/15d2deed5ac3da296cdd03af6457801d67996397
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:28+11:00
Commit Message:
ULTIMA: ULTIMA0: Fix entering/exiting dungeon
Changed paths:
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/status.cpp
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index e13caf526f2..928a6c6d556 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -32,6 +32,8 @@ Dungeon::Dungeon() : View("Dungeon") {
}
bool Dungeon::msgFocus(const FocusMessage &msg) {
+ showMessage("");
+ showLines("");
return true;
}
@@ -151,9 +153,11 @@ void Dungeon::interact() {
if (player.Level == 0) {
showMessage("Leave Dungeon.");
- showLines(Common::String::format("Thou has gained %d hit points.", player.HPGain));
+ if (player.HPGain > 0)
+ showLines(Common::String::format("Thou has gained %d HP", player.HPGain));
player.Attr[AT_HP] += player.HPGain;
player.HPGain = 0;
+ delaySeconds(1); // Brief delay to show text before leaving dungeon
} else {
showMessage("Use Ladder");
@@ -168,11 +172,13 @@ void Dungeon::interact() {
showLines(Common::String::format("Go down to Level %d.\n", player.Level));
}
- if (done && player.Level > 0)
- // New Dungeon Map Required
- dungeon.create(player);
- else
+ if (done) {
+ if (player.Level > 0)
+ // New Dungeon Map Required
+ dungeon.create(player);
+ } else {
showMessage("Huh???");
+ }
}
void Dungeon::timeout() {
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index 48558d05a66..3d22c5c9c60 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -76,7 +76,8 @@ void DungeonStatus::draw() {
auto s = getSurface();
// Display the current direction
- s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
+ if (player.Level > 0)
+ s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
// Draw any extra lines
for (uint i = 0; i < _lines.size(); ++i)
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 4ea69671ce6..a8a324cd300 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -32,6 +32,7 @@ WorldMap::WorldMap() : View("WorldMap") {
}
bool WorldMap::msgFocus(const FocusMessage &msg) {
+ showMessage("");
return true;
}
Commit: 55dbb7831c9b5620c137b604046c0b6227c9cddf
https://github.com/scummvm/scummvm/commit/55dbb7831c9b5620c137b604046c0b6227c9cddf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:28+11:00
Commit Message:
ULTIMA: ULTIMA0: Fixes for monster rendering
Changed paths:
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/monster.cpp
engines/ultima/ultima0/views/dungeon.cpp
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 656798e9047..b0b88d0b5df 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -193,9 +193,8 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
HWLine(r.left + x, y, r.right - x, y);
}
- // Scale (trial and error this :))
- Scale = 0.1;
- Scale = Scale / (r.right - r.left) * 1059.0;
+ // Scale for monsters/gold. Scale factor has been empirically chosen
+ Scale = 0.35 / (r.right - r.left) * s->w;
// Monster here ?
if (Monster > 0) {
@@ -206,7 +205,7 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
// Draw the gold (as a mimic)
if (Room == DT_GOLD) {
HWColour(COL_MONSTER);
- Monster::draw(s, (r.left + r.right) / 2, r.bottom, MN_MIMIC, Scale);
+ Monster::draw(s, (r.left + r.right) / 2, r.top, MN_MIMIC, Scale);
}
}
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index 06ebf76c61a..18bab460133 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -32,10 +32,10 @@ Monster::DrawFn Monster::DRAW_FUNCTIONS[] = {
};
int Monster::xPos = 640;
int Monster::yPos = 512;
+constexpr int color = COL_MONSTER;
#define END (-9999.99) /* End marker */
-#define HWColour(IDX) color = IDX
#define X(n) (x1 + w * (n)/10)
#define Y(n) (y1 + h * (n)/10)
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
@@ -57,7 +57,6 @@ void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
va_list alist;
double y1, x1;
- int color = 0;
// Start reading values
va_start(alist, y);
@@ -66,7 +65,7 @@ void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
x1 = va_arg(alist, double); // Get the next two
y1 = va_arg(alist, double);
if (x1 != END && y1 != END) // If legit, draw the line
- HWLine(xPos + x, yPos - y, xPos + x1, yPos - y1);
+ HWLine(xPos + x, yPos + y, xPos + x1, yPos + y1);
x = x1; y = y1;
} while (x1 != END && y1 != END);
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 928a6c6d556..9e56806b9da 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -82,7 +82,7 @@ bool Dungeon::msgAction(const ActionMessage &msg) {
interact();
break;
default:
- showMessage("");
+ showMessage("Huh???");
break;
}
@@ -102,6 +102,7 @@ bool Dungeon::msgKeypress(const KeypressMessage &msg) {
return true;
default:
+ showMessage("Huh???");
break;
}
@@ -125,7 +126,7 @@ void Dungeon::endOfTurn() {
}
void Dungeon::moveForward() {
- const auto &dungeon = g_engine->_dungeon;
+ auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
COORD New = player.Dungeon + player.DungDir;
@@ -135,7 +136,42 @@ void Dungeon::moveForward() {
// Set new position
player.Dungeon = New;
- // TODO: other stuff
+ // What's here ?
+ int n = dungeon.Map[player.Dungeon.x][player.Dungeon.y];
+
+ if (n == DT_PIT) {
+ // Fell in a pit
+ player.Level++; // Down a level
+ showMessage("Aaarrrgghhh! A Trap !");
+ showLines(Common::String::format("Falling to Level %d.", player.Level));
+
+ player.Attr[AT_HP] -= (3 + urand() % (3 * player.Level));
+ dungeon.create(player); // Create the new level
+ } else if (n == DT_GOLD) {
+ // Gold here
+ // Remove the gold
+ dungeon.Map[player.Dungeon.x][player.Dungeon.y] = DT_SPACE;
+ int gold = (urand() % (5 * player.Level)) + player.Level; // Calculate amount
+
+ showMessage("Gold !!!!!");
+ Common::String msg = Common::String::format("%d pieces of eight ", gold);
+ player.Attr[AT_GOLD] = MIN<int>(player.Attr[AT_GOLD] + gold, 9999); // Add to total
+
+ if (gold > 0) {
+ int objNum = urand() % MAX_OBJ; // Decide which object
+ const char *name = OBJECT_INFO[objNum].Name;
+ const char *prefix = "a"; // Decide a,an or some
+ if (strchr("aeiou", tolower(*name)))
+ prefix = "an";
+ if (objNum == 0)
+ prefix = "some";
+
+ msg += Common::String::format("\nand %s %s.", prefix, name);
+ player.Object[objNum] = MIN<int>(player.Object[objNum] + 1, 9999); // Bump the total
+ }
+
+ showLines(msg);
+ }
}
void Dungeon::interact() {
Commit: 68860b26e8088229a1682c98a23efff22e363a2d
https://github.com/scummvm/scummvm/commit/68860b26e8088229a1682c98a23efff22e363a2d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:28+11:00
Commit Message:
ULTIMA: ULTIMA0: Added monster attacking logic
Changed paths:
A engines/ultima/ultima0/data/monster_logic.cpp
A engines/ultima/ultima0/data/monster_logic.h
engines/ultima/module.mk
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 2f160043f50..d73a69c68bc 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -32,6 +32,7 @@ MODULE_OBJS += \
ultima0/town.o \
ultima0/world.o \
ultima0/data/data.o \
+ ultima0/data/monster_logic.o \
ultima0/gfx/dungeon.o \
ultima0/gfx/font.o \
ultima0/gfx/gfx_surface.o \
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index f4c045c08ef..4f19afe430f 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -141,7 +141,7 @@ struct WORLDMAP {
void synchronize(Common::Serializer &s);
};
-} // End of namespace Ultima4
-} // End of namespace Ultima
+} // namespace Ultima0
+} // namespace Ultima
#endif
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
new file mode 100644
index 00000000000..45c3cf0e48b
--- /dev/null
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -0,0 +1,171 @@
+/* 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 "ultima/ultima0/data/monster_logic.h"
+#include "ultima/ultima0/ultima0.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+void MonsterLogic::checkForAttacks(PLAYER &p, DUNGEONMAP &d) {
+ int i, Attacked;
+ double Dist;
+
+ // Go through all monsters
+ for (i = 0; i < d.MonstCount; i++) {
+ MONSTER &m = d.Monster[i]; // Pointer to MONSTER &/
+ Dist = pow(m.Loc.x - p.Dungeon.x, 2); // Calculate Distance
+ Dist = Dist + pow(m.Loc.y - p.Dungeon.y, 2);
+ Dist = sqrt(Dist);
+
+ // If alive
+ if (m.Alive != 0) {
+ Attacked = 0;
+
+ // If within range
+ if (Dist < 1.3)
+ Attacked = _MONSTAttack(m, p);
+
+ // If didn't attack, then move
+ if (Attacked == 0) {
+ // Mimics only if near enough
+ if (m.Type != MN_MIMIC || Dist >= 3.0)
+ _MONSTMove(m, p, d);
+
+ // Recovers if didn't attack
+ if (m.Strength < p.Level * p.Skill)
+ m.Strength = m.Strength + p.Level;
+ }
+ }
+ }
+}
+
+void MonsterLogic::showLines(const Common::String &msg) {
+ g_events->send("DungeonStatus", GameMessage("LINES", msg));
+}
+
+int MonsterLogic::_MONSTAttack(MONSTER &m, PLAYER &p) {
+ int n;
+
+ if (m.Type == MN_GREMLIN || // Special case for Gremlin/Thief
+ m.Type == MN_THIEF)
+ if (RND() > 0.5) // Half the time
+ return _MONSTSteal(m, p);
+
+ Common::String msg = Common::String::format("You are being attacked by a %s !!!.\n",
+ MONSTER_INFO[m.Type].Name);
+
+ n = urand() % 20; // Calculate hit chance
+ if (p.Object[OB_SHIELD] > 0) n--;
+ n = n - p.Attr[AT_STAMINA];
+ n = n + m.Type + p.Level;
+ if (n < 0) {
+ // Missed !
+ msg += "Missed !\n";
+ } else {
+ // Hit !
+ n = urand() % m.Type; // Calculate damage done.
+ n = n + p.Level;
+ p.Attr[AT_HP] -= n; // Adjust hit points
+ msg += "Hit !!!\n";
+ }
+
+ showLines(msg);
+ return 1;
+}
+
+void MonsterLogic::_MONSTMove(MONSTER &m, PLAYER &p, DUNGEONMAP &d) {
+ int x, y, xi, yi;
+
+ // Calculate direction
+ xi = yi = 0;
+ if (p.Dungeon.x != m.Loc.x)
+ xi = (p.Dungeon.x > m.Loc.x) ? 1 : -1;
+ if (p.Dungeon.y != m.Loc.y)
+ yi = (p.Dungeon.y > m.Loc.y) ? 1 : -1;
+
+ // Running away
+ if (m.Strength < p.Level * p.Skill) {
+ xi = -xi; yi = -yi;
+ }
+
+ // Get position
+ x = m.Loc.x; y = m.Loc.y;
+
+ // Check move okay
+ if (ABS(xi) > ABS(yi)) {
+ if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
+ else if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
+ } else {
+ if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
+ else if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
+ }
+
+ if (xi == 0 && yi == 0)
+ return; // No move
+
+ x = x + xi; y = y + yi; // Work out new position
+ if (!_MONSTCanMoveTo(d, x, y)) // Fail if can't move there
+ return;
+ if (x == p.Dungeon.x && // Can't move onto us
+ y == p.Dungeon.y) return;
+ m.Loc.x = x; m.Loc.y = y; // Move to new position
+}
+
+bool MonsterLogic::_MONSTCanMoveTo(DUNGEONMAP &d, int x, int y) {
+ COORD c;
+ int t = d.Map[x][y]; // See what's there
+ if (!ISWALKTHRU(t)) return 0; // Can't walk through walls
+ c.x = x; c.y = y; // Set up coord structure
+
+ // True if no monster here
+ return d.findMonster(c) < 0;
+}
+
+int MonsterLogic::_MONSTSteal(MONSTER &m, PLAYER &p) {
+ int n;
+ const char *s1, *s2;
+
+ if (m.Type == MN_GREMLIN) {
+ // HALVES the food.... aargh
+ p.Object[OB_FOOD] = floor(p.Object[OB_FOOD]) / 2.0;
+ showLines("A Gremlin stole some food.\n");
+
+ } else if (m.Type == MN_THIEF) {
+ // Figure out what stolen
+ do {
+ n = urand() % p.Objects;
+ } while (p.Object[n] == 0);
+
+ p.Object[n]--; // Stole one
+ s2 = OBJECT_INFO[n].Name; s1 = "a";
+
+ if (strchr("aeiou", tolower(*s2))) s1 = "an";
+ if (n == 0) s1 = "some";
+
+ showLines(Common::String::format("A Thief stole %s %s.\n", s1, s2));
+ }
+
+ return 1;
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/monster_logic.h b/engines/ultima/ultima0/data/monster_logic.h
new file mode 100644
index 00000000000..b43359c7739
--- /dev/null
+++ b/engines/ultima/ultima0/data/monster_logic.h
@@ -0,0 +1,67 @@
+/* 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 ULTIMA0_MONSTER_LOGIC_H
+#define ULTIMA0_MONSTER_LOGIC_H
+
+#include "ultima/ultima0/data/data.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+class MonsterLogic {
+private:
+ /**
+ * Shows a message in the dungeon status area
+ */
+ static void showLines(const Common::String &msg);
+
+ /**
+ * Monster Attacks
+ */
+ static int _MONSTAttack(MONSTER &m, PLAYER &p);
+
+ /**
+ * Monster Moves
+ */
+ static void _MONSTMove(MONSTER &m, PLAYER &p, DUNGEONMAP &d);
+
+ /**
+ * Can monster move to a square
+ */
+ static bool _MONSTCanMoveTo(DUNGEONMAP &d, int x, int y);
+
+ /**
+ * Monster Stealing
+ */
+ static int _MONSTSteal(MONSTER &m, PLAYER &p);
+
+public:
+ /**
+ * Check Monsters Attacking
+ */
+ static void checkForAttacks(PLAYER &p, DUNGEONMAP &d);
+};
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 9e56806b9da..be3ed4c6afb 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -23,6 +23,7 @@
#include "ultima/ultima0/ultima0.h"
#include "ultima/ultima0/gfx/font.h"
#include "ultima/ultima0/gfx/dungeon.h"
+#include "ultima/ultima0/data/monster_logic.h"
namespace Ultima {
namespace Ultima0 {
@@ -112,9 +113,15 @@ bool Dungeon::msgKeypress(const KeypressMessage &msg) {
void Dungeon::endOfTurn() {
auto &player = g_engine->_player;
+ auto &dungeon = g_engine->_dungeon;
- if (player.Attr[AT_HP] <= 0)
+ if (player.Attr[AT_HP] <= 0) {
replaceView("Dead");
+ return;
+ }
+
+ // Check for monster attacks
+ MonsterLogic::checkForAttacks(player, dungeon);
player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 0.1, 0.0);
if (player.Object[OB_FOOD] == 0) {
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index a8a324cd300..401b58509ab 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -108,13 +108,15 @@ bool WorldMap::msgKeypress(const KeypressMessage &msg) {
void WorldMap::endOfTurn() {
auto &player = g_engine->_player;
- if (player.Attr[AT_HP] <= 0)
+ if (player.Attr[AT_HP] <= 0) {
replaceView("Dead");
- player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
- if (player.Object[OB_FOOD] == 0) {
- showMessage("You have starved...");
- delaySeconds(1);
+ } else {
+ player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
+ if (player.Object[OB_FOOD] == 0) {
+ showMessage("You have starved...");
+ delaySeconds(1);
+ }
}
}
Commit: a47c659181f62629f35d3e06e39dece6aafdc5e5
https://github.com/scummvm/scummvm/commit/a47c659181f62629f35d3e06e39dece6aafdc5e5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Cleanup of monster attack logic
Changed paths:
engines/ultima/ultima0/data/monster_logic.cpp
engines/ultima/ultima0/data/monster_logic.h
engines/ultima/ultima0/monst.cpp
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
index 45c3cf0e48b..abcf00ebade 100644
--- a/engines/ultima/ultima0/data/monster_logic.cpp
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -42,13 +42,13 @@ void MonsterLogic::checkForAttacks(PLAYER &p, DUNGEONMAP &d) {
// If within range
if (Dist < 1.3)
- Attacked = _MONSTAttack(m, p);
+ Attacked = attack(m, p);
// If didn't attack, then move
if (Attacked == 0) {
// Mimics only if near enough
if (m.Type != MN_MIMIC || Dist >= 3.0)
- _MONSTMove(m, p, d);
+ move(m, p, d);
// Recovers if didn't attack
if (m.Strength < p.Level * p.Skill)
@@ -62,13 +62,13 @@ void MonsterLogic::showLines(const Common::String &msg) {
g_events->send("DungeonStatus", GameMessage("LINES", msg));
}
-int MonsterLogic::_MONSTAttack(MONSTER &m, PLAYER &p) {
+int MonsterLogic::attack(MONSTER &m, PLAYER &p) {
int n;
if (m.Type == MN_GREMLIN || // Special case for Gremlin/Thief
m.Type == MN_THIEF)
if (RND() > 0.5) // Half the time
- return _MONSTSteal(m, p);
+ return steal(m, p);
Common::String msg = Common::String::format("You are being attacked by a %s !!!.\n",
MONSTER_INFO[m.Type].Name);
@@ -92,7 +92,7 @@ int MonsterLogic::_MONSTAttack(MONSTER &m, PLAYER &p) {
return 1;
}
-void MonsterLogic::_MONSTMove(MONSTER &m, PLAYER &p, DUNGEONMAP &d) {
+void MonsterLogic::move(MONSTER &m, PLAYER &p, DUNGEONMAP &d) {
int x, y, xi, yi;
// Calculate direction
@@ -112,25 +112,25 @@ void MonsterLogic::_MONSTMove(MONSTER &m, PLAYER &p, DUNGEONMAP &d) {
// Check move okay
if (ABS(xi) > ABS(yi)) {
- if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
- else if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
+ if (canMoveTo(d, x + xi, yi)) yi = 0;
+ else if (canMoveTo(d, x, y + yi)) xi = 0;
} else {
- if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
- else if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
+ if (canMoveTo(d, x, y + yi)) xi = 0;
+ else if (canMoveTo(d, x + xi, yi)) yi = 0;
}
if (xi == 0 && yi == 0)
return; // No move
x = x + xi; y = y + yi; // Work out new position
- if (!_MONSTCanMoveTo(d, x, y)) // Fail if can't move there
+ if (!canMoveTo(d, x, y)) // Fail if can't move there
return;
if (x == p.Dungeon.x && // Can't move onto us
y == p.Dungeon.y) return;
m.Loc.x = x; m.Loc.y = y; // Move to new position
}
-bool MonsterLogic::_MONSTCanMoveTo(DUNGEONMAP &d, int x, int y) {
+bool MonsterLogic::canMoveTo(DUNGEONMAP &d, int x, int y) {
COORD c;
int t = d.Map[x][y]; // See what's there
if (!ISWALKTHRU(t)) return 0; // Can't walk through walls
@@ -140,7 +140,7 @@ bool MonsterLogic::_MONSTCanMoveTo(DUNGEONMAP &d, int x, int y) {
return d.findMonster(c) < 0;
}
-int MonsterLogic::_MONSTSteal(MONSTER &m, PLAYER &p) {
+int MonsterLogic::steal(MONSTER &m, PLAYER &p) {
int n;
const char *s1, *s2;
diff --git a/engines/ultima/ultima0/data/monster_logic.h b/engines/ultima/ultima0/data/monster_logic.h
index b43359c7739..5560133c1ce 100644
--- a/engines/ultima/ultima0/data/monster_logic.h
+++ b/engines/ultima/ultima0/data/monster_logic.h
@@ -37,22 +37,22 @@ private:
/**
* Monster Attacks
*/
- static int _MONSTAttack(MONSTER &m, PLAYER &p);
+ static int attack(MONSTER &m, PLAYER &p);
/**
* Monster Moves
*/
- static void _MONSTMove(MONSTER &m, PLAYER &p, DUNGEONMAP &d);
+ static void move(MONSTER &m, PLAYER &p, DUNGEONMAP &d);
/**
* Can monster move to a square
*/
- static bool _MONSTCanMoveTo(DUNGEONMAP &d, int x, int y);
+ static bool canMoveTo(DUNGEONMAP &d, int x, int y);
/**
* Monster Stealing
*/
- static int _MONSTSteal(MONSTER &m, PLAYER &p);
+ static int steal(MONSTER &m, PLAYER &p);
public:
/**
diff --git a/engines/ultima/ultima0/monst.cpp b/engines/ultima/ultima0/monst.cpp
index 17a9cad8872..067648cf53c 100644
--- a/engines/ultima/ultima0/monst.cpp
+++ b/engines/ultima/ultima0/monst.cpp
@@ -33,10 +33,10 @@
namespace Ultima {
namespace Ultima0 {
-static int _MONSTAttack(MONSTER *, PLAYER *);
-static int _MONSTSteal(MONSTER *, PLAYER *);
-static void _MONSTMove(MONSTER *, PLAYER *, DUNGEONMAP *);
-static int _MONSTCanMoveTo(DUNGEONMAP *, int, int);
+static int attack(MONSTER *, PLAYER *);
+static int steal(MONSTER *, PLAYER *);
+static void move(MONSTER *, PLAYER *, DUNGEONMAP *);
+static int canMoveTo(DUNGEONMAP *, int, int);
/************************************************************************/
/* */
@@ -58,12 +58,12 @@ void MONSTAttack(PLAYER *p, DUNGEONMAP *d) {
{
Attacked = 0;
if (Dist < 1.3) /* If within range */
- Attacked = _MONSTAttack(m, p);
+ Attacked = attack(m, p);
if (Attacked == 0) /* If didn't attack, then move */
{
if (m->Type != MN_MIMIC || /* Mimics only if near enough */
Dist >= 3.0)
- _MONSTMove(m, p, d);
+ move(m, p, d);
if (m->Strength < /* Recovers if didn't attack */
p->Level * p->Skill)
m->Strength = m->Strength + p->Level;
@@ -78,13 +78,13 @@ void MONSTAttack(PLAYER *p, DUNGEONMAP *d) {
/* */
/************************************************************************/
-static int _MONSTAttack(MONSTER *m, PLAYER *p) {
+static int attack(MONSTER *m, PLAYER *p) {
int n;
if (m->Type == MN_GREMLIN || /* Special case for Gremlin/Thief */
m->Type == MN_THIEF)
if (RND() > 0.5) /* Half the time */
- return _MONSTSteal(m, p);
+ return steal(m, p);
DRAWText("You are being attacked by a %s !!!.\n",
GLOMonsterName(m->Type));
@@ -111,7 +111,7 @@ static int _MONSTAttack(MONSTER *m, PLAYER *p) {
/* */
/************************************************************************/
-static void _MONSTMove(MONSTER *m, PLAYER *p, DUNGEONMAP *d) {
+static void move(MONSTER *m, PLAYER *p, DUNGEONMAP *d) {
int x, y, xi, yi;
xi = yi = 0; /* Calculate direction */
@@ -129,16 +129,16 @@ static void _MONSTMove(MONSTER *m, PLAYER *p, DUNGEONMAP *d) {
if (abs(xi) > abs(yi)) /* Check move okay */
{
- if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
- else if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
+ if (canMoveTo(d, x + xi, yi)) yi = 0;
+ else if (canMoveTo(d, x, y + yi)) xi = 0;
} else
{
- if (_MONSTCanMoveTo(d, x, y + yi)) xi = 0;
- else if (_MONSTCanMoveTo(d, x + xi, yi)) yi = 0;
+ if (canMoveTo(d, x, y + yi)) xi = 0;
+ else if (canMoveTo(d, x + xi, yi)) yi = 0;
}
if (xi == 0 && yi == 0) return; /* No move */
x = x + xi; y = y + yi; /* Work out new position */
- if (_MONSTCanMoveTo(d, x, y) == 0) /* Fail if can't move there */
+ if (canMoveTo(d, x, y) == 0) /* Fail if can't move there */
return;
if (x == p->Dungeon.x && /* Can't move onto us */
y == p->Dungeon.y) return;
@@ -151,7 +151,7 @@ static void _MONSTMove(MONSTER *m, PLAYER *p, DUNGEONMAP *d) {
/* */
/************************************************************************/
-static int _MONSTCanMoveTo(DUNGEONMAP *d, int x, int y) {
+static int canMoveTo(DUNGEONMAP *d, int x, int y) {
COORD c;
int t = d->Map[x][y]; /* See what's there */
if (!ISWALKTHRU(t)) return 0; /* Can't walk through walls */
@@ -165,7 +165,7 @@ static int _MONSTCanMoveTo(DUNGEONMAP *d, int x, int y) {
/* */
/************************************************************************/
-static int _MONSTSteal(MONSTER *m, PLAYER *p) {
+static int steal(MONSTER *m, PLAYER *p) {
int n;
const char *s1, *s2;
Commit: 27e0a2d51adcac784fb561335e330f81441a5896
https://github.com/scummvm/scummvm/commit/27e0a2d51adcac784fb561335e330f81441a5896
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Adding keybinding modes
Changed paths:
engines/ultima/POTFILES
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/metaengine.h
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/dungeon.h
engines/ultima/ultima0/views/world_map.cpp
engines/ultima/ultima0/views/world_map.h
diff --git a/engines/ultima/POTFILES b/engines/ultima/POTFILES
index df92bdaba3e..310e9ffdc23 100644
--- a/engines/ultima/POTFILES
+++ b/engines/ultima/POTFILES
@@ -1,6 +1,7 @@
engines/ultima/metaengine.cpp
engines/ultima/shared/early/ultima_early.cpp
engines/ultima/shared/engine/data_archive.cpp
+engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima4/metaengine.cpp
engines/ultima/nuvie/keybinding/key_help_dialog.cpp
engines/ultima/nuvie/keybinding/keys.cpp
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index f986ef507c2..1f6e7876469 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -36,16 +36,29 @@ struct KeybindingRecord {
const char *_joy;
};
-static const KeybindingRecord NORMAL_KEYS[] = {
- { KEYBIND_UP, "UP", _s("Up/Forward"), "UP", "JOY_UP" },
- { KEYBIND_DOWN, "DOWN", _s("Down/Backwards"), "DOWN", "JOY_DOWN" },
- { KEYBIND_LEFT, "LEFT", _s("Left"), "LEFT", "JOY_LEFT" },
- { KEYBIND_RIGHT, "RIGHT", _s("Right"), "RIGHT", "JOY_RIGHT" },
- { KEYBIND_SELECT, "INTERACT", _s("Interact"), "SPACE", "JOY_A" },
- { KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
+static const KeybindingRecord MINIMAL_KEYS[] = {
{ KEYBIND_ESCAPE, "ESCAPE", _s("Escape"), "ESCAPE", "JOY_Y" },
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
+};
+
+static const KeybindingRecord OVERWORLD_KEYS[] = {
+ { KEYBIND_UP, "UP", _s("North"), "UP", "JOY_UP" },
+ { KEYBIND_DOWN, "DOWN", _s("South"), "DOWN", "JOY_DOWN" },
+ { KEYBIND_LEFT, "LEFT", _s("West"), "LEFT", "JOY_LEFT" },
+ { KEYBIND_RIGHT, "RIGHT", _s("East"), "RIGHT", "JOY_RIGHT" },
+ { KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
+};
+static const KeybindingRecord DUNGEON_KEYS[] = {
+ { KEYBIND_UP, "UP", _s("Move Forward"), "UP", "JOY_UP" },
+ { KEYBIND_DOWN, "DOWN", _s("Turn Around"), "DOWN", "JOY_DOWN" },
+ { KEYBIND_LEFT, "LEFT", _s("Turn Left"), "LEFT", "JOY_LEFT" },
+ { KEYBIND_RIGHT, "RIGHT", _s("Turn Right"), "RIGHT", "JOY_RIGHT" },
+ { KEYBIND_ATTACK, "ATTACK", _s("Attack"), "a", "JOY_A" },
+ { KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
+ { KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
@@ -55,14 +68,35 @@ struct KeysRecord {
const KeybindingRecord *_keys;
};
-static const KeysRecord NORMAL_RECORDS[] = {
- { "ultima0", "Akalabeth", NORMAL_KEYS },
+static const KeysRecord ALL_RECORDS[] = {
+ { "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
+ { "overworld", _s("Overworld Keys"), OVERWORLD_KEYS },
+ { "dungeon", _s("Dungeon Keys"), DUNGEON_KEYS },
{ nullptr, nullptr, nullptr }
};
+static const KeysRecord MINIMAL_RECORDS[] = {
+ { "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
+ { nullptr, nullptr, nullptr }
+};
+
+static const KeysRecord OVERWORLD_RECORDS[] = {
+ { "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
+ { "overworld", _s("Overworld Keys"), OVERWORLD_KEYS },
+ { nullptr, nullptr, nullptr }
+};
+
+static const KeysRecord DUNGEON_RECORDS[] = {
+ { "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
+ { "dungeon", _s("Dungeon Keys"), DUNGEON_KEYS },
+ { nullptr, nullptr, nullptr }
+};
-static const KeysRecord *MODE_RECORDS[1] = {
- NORMAL_RECORDS
+static const KeysRecord *MODE_RECORDS[] = {
+ ALL_RECORDS,
+ MINIMAL_RECORDS,
+ OVERWORLD_RECORDS,
+ DUNGEON_RECORDS,
};
Common::KeymapArray MetaEngine::initKeymaps(KeybindingMode mode) {
diff --git a/engines/ultima/ultima0/metaengine.h b/engines/ultima/ultima0/metaengine.h
index 9291745ac21..2f76249476b 100644
--- a/engines/ultima/ultima0/metaengine.h
+++ b/engines/ultima/ultima0/metaengine.h
@@ -30,12 +30,16 @@ namespace Ultima0 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
KEYBIND_SELECT, KEYBIND_ESCAPE, KEYBIND_ENTER, KEYBIND_INFO,
+ KEYBIND_ATTACK,
KEYBIND_NONE
};
enum KeybindingMode {
- KBMODE_NORMAL ///< Keys available when normal in-game
+ KBMODE_ALL,
+ KBMODE_MINIMAL,
+ KBMODE_OVERWORLD,
+ KBMODE_DUNGEONS
};
class MetaEngine {
@@ -48,7 +52,7 @@ public:
/**
* Initialize keymaps
*/
- static Common::KeymapArray initKeymaps(KeybindingMode mode = KBMODE_NORMAL);
+ static Common::KeymapArray initKeymaps(KeybindingMode mode = KBMODE_ALL);
/**
* Sets the current set of actions which are active
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index b3855a4fcfc..f7c7bf434aa 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -64,6 +64,7 @@ Common::Error Ultima0Engine::run() {
// Set the debugger console
setDebugger(new Console());
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
// Play the game
runGame();
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index be3ed4c6afb..9ac2544c12c 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -21,6 +21,7 @@
#include "ultima/ultima0/views/dungeon.h"
#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/metaengine.h"
#include "ultima/ultima0/gfx/font.h"
#include "ultima/ultima0/gfx/dungeon.h"
#include "ultima/ultima0/data/monster_logic.h"
@@ -35,6 +36,12 @@ Dungeon::Dungeon() : View("Dungeon") {
bool Dungeon::msgFocus(const FocusMessage &msg) {
showMessage("");
showLines("");
+ MetaEngine::setKeybindingMode(KBMODE_DUNGEONS);
+ return true;
+}
+
+bool Dungeon::msgUnfocus(const UnfocusMessage &msg) {
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
return true;
}
diff --git a/engines/ultima/ultima0/views/dungeon.h b/engines/ultima/ultima0/views/dungeon.h
index b2321dab0e1..cbe745ada12 100644
--- a/engines/ultima/ultima0/views/dungeon.h
+++ b/engines/ultima/ultima0/views/dungeon.h
@@ -48,6 +48,7 @@ public:
~Dungeon() override {}
bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
bool msgAction(const ActionMessage &msg) override;
bool msgKeypress(const KeypressMessage &msg) override;
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 401b58509ab..6d117171d94 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -21,6 +21,7 @@
#include "ultima/ultima0/views/world_map.h"
#include "ultima/ultima0/ultima0.h"
+#include "ultima/ultima0/metaengine.h"
#include "ultima/ultima0/gfx/font.h"
#include "ultima/ultima0/gfx/map.h"
@@ -33,6 +34,12 @@ WorldMap::WorldMap() : View("WorldMap") {
bool WorldMap::msgFocus(const FocusMessage &msg) {
showMessage("");
+ MetaEngine::setKeybindingMode(KBMODE_OVERWORLD);
+ return true;
+}
+
+bool WorldMap::msgUnfocus(const UnfocusMessage &msg) {
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
return true;
}
@@ -74,7 +81,6 @@ bool WorldMap::msgAction(const ActionMessage &msg) {
replaceView("Info");
break;
case KEYBIND_ENTER:
- case KEYBIND_SELECT:
enter();
break;
default:
diff --git a/engines/ultima/ultima0/views/world_map.h b/engines/ultima/ultima0/views/world_map.h
index 8b6cf56bdc4..96b037c06da 100644
--- a/engines/ultima/ultima0/views/world_map.h
+++ b/engines/ultima/ultima0/views/world_map.h
@@ -45,6 +45,7 @@ public:
~WorldMap() override {}
bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
bool msgAction(const ActionMessage &msg) override;
bool msgKeypress(const KeypressMessage &msg) override;
Commit: 1b42abbaf5a6eae98d9bd503d69beb17d42fdbb0
https://github.com/scummvm/scummvm/commit/1b42abbaf5a6eae98d9bd503d69beb17d42fdbb0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Beginnings of attack selection view
Changed paths:
A engines/ultima/ultima0/views/attack.cpp
A engines/ultima/ultima0/views/attack.h
engines/ultima/module.mk
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index d73a69c68bc..4f9a5a1b319 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -39,6 +39,7 @@ MODULE_OBJS += \
ultima0/gfx/map.o \
ultima0/gfx/monster.o \
ultima0/views/view.o \
+ ultima0/views/attack.o \
ultima0/views/castle.o \
ultima0/views/create_character.o \
ultima0/views/dungeon.o \
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
new file mode 100644
index 00000000000..c6f9fd5932b
--- /dev/null
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -0,0 +1,43 @@
+/* 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 "ultima/ultima0/views/attack.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+Attack::Attack() : View("Attack") {
+ setBounds(Gfx::TextRect(0, 22, 26, 24));
+}
+
+void Attack::draw() {
+ auto s = getSurface();
+ s.clear(4);
+}
+
+bool Attack::msgKeypress(const KeypressMessage &msg) {
+ return false;
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/attack.h b/engines/ultima/ultima0/views/attack.h
new file mode 100644
index 00000000000..794296f5f3a
--- /dev/null
+++ b/engines/ultima/ultima0/views/attack.h
@@ -0,0 +1,45 @@
+/* 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 ULTIMA0_VIEWS_ATTACK_H
+#define ULTIMA0_VIEWS_ATTACK_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Attack : public View {
+public:
+ Attack();
+ ~Attack() override {}
+
+ void draw() override;
+
+ bool msgKeypress(const KeypressMessage &msg) override;
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 9ac2544c12c..e73536c482e 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -89,6 +89,11 @@ bool Dungeon::msgAction(const ActionMessage &msg) {
case KEYBIND_ENTER:
interact();
break;
+ case KEYBIND_ATTACK:
+ showMessage("\x9""Attack!");
+ _status.draw(); // Render the message before we switch views
+ addView("Attack");
+ break;
default:
showMessage("Huh???");
break;
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index c30f3e73ff5..45d45ad49e2 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_VIEWS_H
#define ULTIMA0_VIEWS_H
+#include "ultima/ultima0/views/attack.h"
#include "ultima/ultima0/views/castle.h"
#include "ultima/ultima0/views/create_character.h"
#include "ultima/ultima0/views/dead.h"
@@ -37,6 +38,7 @@ namespace Ultima0 {
namespace Views {
struct Views {
+ Attack _attack;
Castle _castle;
CreateCharacter _createCharacter;
Dead _dead;
Commit: f44ad9a93b6ef2c554dd087e21e9e6aa94b5602c
https://github.com/scummvm/scummvm/commit/f44ad9a93b6ef2c554dd087e21e9e6aa94b5602c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Fleshing out attack details view
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/globals.cpp
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/attack.h
engines/ultima/ultima0/views/info.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index bb261b48cbf..1f294da9619 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -26,12 +26,12 @@ namespace Ultima {
namespace Ultima0 {
const _OInfStruct OBJECT_INFO[] = {
- { "Food", 1, 0, 'F' },
- { "Rapier", 8, 10, 'R' },
- { "Axe", 5, 5, 'A' },
- { "Shield", 6, 1, 'S' },
- { "Bow and Arrow", 3, 4, 'B' },
- { "Magic Amulet", 15, 0, 'M' }
+ { "Food", 1, 0, Common::KEYCODE_f },
+ { "Rapier", 8, 10, Common::KEYCODE_r },
+ { "Axe", 5, 5, Common::KEYCODE_a },
+ { "Shield", 6, 1, Common::KEYCODE_s },
+ { "Bow and Arrow", 3, 4, Common::KEYCODE_b },
+ { "Magic Amulet", 15, 0, Common::KEYCODE_m }
};
const _MInfStruct MONSTER_INFO[] = {
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 4f19afe430f..7c2613959da 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_DATA_H
#define ULTIMA0_DATA_H
+#include "common/keyboard.h"
#include "common/rect.h"
#include "common/serializer.h"
#include "ultima/ultima0/data/defines.h"
@@ -37,7 +38,7 @@ struct _OInfStruct {
const char *Name;
int Cost;
int MaxDamage;
- char Key;
+ Common::KeyCode keycode;
};
struct _MInfStruct {
const char *Name; int Level;
diff --git a/engines/ultima/ultima0/globals.cpp b/engines/ultima/ultima0/globals.cpp
index 8cd977f0343..42562380db1 100644
--- a/engines/ultima/ultima0/globals.cpp
+++ b/engines/ultima/ultima0/globals.cpp
@@ -44,9 +44,11 @@ const char *GLOObjName(int n) {
}
void GLOGetInfo(int n, int *pDamage, int *pCost, int *pKey) {
+#if 0
if (pDamage != nullptr) *pDamage = OBJECT_INFO[n].MaxDamage;
if (pCost != nullptr) *pCost = OBJECT_INFO[n].Cost;
if (pKey != nullptr) *pKey = OBJECT_INFO[n].Key;
+#endif
}
/************************************************************************/
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index c6f9fd5932b..9ae56776942 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -20,6 +20,8 @@
*/
#include "ultima/ultima0/views/attack.h"
+#include "ultima/ultima0/data/data.h"
+#include "ultima/ultima0/ultima0.h"
namespace Ultima {
namespace Ultima0 {
@@ -29,15 +31,300 @@ Attack::Attack() : View("Attack") {
setBounds(Gfx::TextRect(0, 22, 26, 24));
}
+bool Attack::msgFocus(const FocusMessage &msg) {
+ _mode = WHICH_WEAPON;
+ _message = "";
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
+ return true;
+}
+
+bool Attack::msgUnfocus(const UnfocusMessage &msg) {
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
+ return true;
+}
+
void Attack::draw() {
auto s = getSurface();
- s.clear(4);
+ s.clear();
+
+ if (_mode == AMULET) {
+ s.writeString(Common::Point(1, 0), "1] Ladder Up");
+ s.writeString(Common::Point(1, 1), "2] Ladder Down");
+ s.writeString(Common::Point(1, 2), "3] Attack Monster");
+ s.writeString(Common::Point(1, 3), "4] Bad Magic");
+ return;
+ }
+
+ s.writeString(Common::Point(1, 1), "Which Weapon? ");
+ if (_mode != WHICH_WEAPON)
+ s.writeString(_weapon <= 0 ? "Hands" : OBJECT_INFO[_weapon].Name);
+
+ if (!_message.empty())
+ s.writeString(Common::Point(1, 2), _message);
}
bool Attack::msgKeypress(const KeypressMessage &msg) {
+ int objNum;
+
+ switch (_mode) {
+ case WHICH_WEAPON:
+ // Check for object selection, anything but food
+ objNum = -1;
+ for (uint i = OB_RAPIER; i < MAX_OBJ; ++i) {
+ if (msg.keycode == OBJECT_INFO[i].keycode) {
+ objNum = i;
+ break;
+ }
+ }
+
+ selectObject(objNum);
+ break;
+
+ case AMULET:
+ if (msg.keycode >= Common::KEYCODE_1 && msg.keycode <= Common::KEYCODE_4) {
+ selectMagic(msg.keycode - Common::KEYCODE_1);
+ }
+ break;
+
+ case THROW_SWING:
+ if (msg.keycode == Common::KEYCODE_t) {
+ _message += "Throw\n";
+ attackMissile();
+ } else if (msg.keycode == Common::KEYCODE_s) {
+ _message += "Swing\n";
+ attackWeapon();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool Attack::msgAction(const ActionMessage &msg) {
+ if (_mode == WHICH_WEAPON) {
+ selectObject(-1);
+ return true;
+ }
+
return false;
}
+void Attack::selectObject(int objNum) {
+ auto &player = g_engine->_player;
+
+ _weapon = objNum;
+ _damage = (objNum <= 0) ? 0 : OBJECT_INFO[objNum].MaxDamage;
+
+ // Must own an object
+ if (player.Object[_weapon] == 0) {
+ showMessage("Not owned.");
+ return;
+ }
+
+ // Mages are limited
+ if (player.Class == 'M' && (objNum == OB_BOW || objNum == OB_RAPIER)) {
+ showMessage("Mages can't use that.");
+ return;
+ }
+
+ // Use an amulet
+ if (objNum == OB_AMULET) {
+ if (player.Class == 'M') {
+ // Mages can properly select the magic to use
+ _mode = AMULET;
+
+ // Amulet selection requires all four lines
+ _bounds = Gfx::TextRect(0, 22, 26, 24);
+
+ redraw();
+ } else {
+ // Fighters get a random effect
+ selectMagic(g_engine->getRandomNumber(3));
+ }
+ return;
+ }
+
+ if (objNum == OB_BOW) {
+ attackMissile();
+ } else if (objNum == OB_AXE) {
+ _mode = THROW_SWING;
+ _message += "Throw or Swing ? ";
+ redraw();
+ } else {
+ attackWeapon();
+ }
+}
+
+void Attack::selectMagic(int magicNum) {
+ auto &dungeon = g_engine->_dungeon;
+ auto &player = g_engine->_player;
+ int i;
+
+ // Last charge?
+ Common::String msg;
+ if (urand() % 5 == 0) {
+ msg = "Last charge on this Amulet.\n";
+ player.Object[OB_AMULET]--;
+ }
+
+ switch (magicNum) {
+ case 0:
+ // Ladder up
+ dungeon.Map[player.Dungeon.x][player.Dungeon.y] = DT_LADDERUP;
+ break;
+ case 1:
+ // Ladder down
+ dungeon.Map[player.Dungeon.x][player.Dungeon.y] = DT_LADDERDN;
+ break;
+ case 2:
+ // Amulet Attack
+ attackMissile();
+ break;
+ case 3:
+ // Bad Magic
+ switch (urand() % 3) {
+ case 0:
+ msg += "You have been turned into a Toad.\n";
+ for (i = AT_STRENGTH; i <= AT_WISDOM; i++)
+ player.Attr[i] = 3;
+ break;
+ case 1:
+ msg += "You have been turned into a Lizard Man.\n";
+ for (i = AT_HP; i <= AT_WISDOM; i++)
+ player.Attr[i] = floor(player.Attr[i] * 5 / 2);
+ break;
+ case 2:
+ msg += "Backfire !!\n";
+ player.Attr[AT_HP] = floor(player.Attr[AT_HP]) / 2;
+ break;
+ }
+ break;
+ }
+
+ if (msg.empty()) {
+ timeout();
+ } else {
+ redraw();
+ delaySeconds(1);
+ }
+}
+
+void Attack::attackMissile() {
+ const auto &dungeon = g_engine->_dungeon;
+ auto &player = g_engine->_player;
+ COORD c1, c = player.Dungeon;
+ int Dist = -1;
+
+ // A maximum distance of 5
+ for (int y = 0; y < 5; y++) {
+ c += player.DungDir;
+ int n = dungeon.findMonster(c); // Monster there ?
+ if (n >= 0) {
+ c1 = c;
+ Dist = n;
+ }
+
+ // If wall, or door, stop
+ if (!ISDRAWOPEN(dungeon.Map[c.x][c.y]))
+ break;
+ }
+
+ if (Dist < 0) {
+ // Hit nothing
+ _message += "You missed !!\n";
+ _mode = DONE;
+ delaySeconds(1);
+ } else {
+ attackHitMonster(c1);
+ }
+}
+
+void Attack::attackWeapon() {
+ const auto &player = g_engine->_player;
+ COORD c = player.Dungeon + player.DungDir;
+ attackHitMonster(c);
+}
+
+void Attack::attackHitMonster(const COORD &c) {
+ auto &player = g_engine->_player;
+ auto &dungeon = g_engine->_dungeon;
+ int n = 0, Monster, Damage;
+ MONSTER *m = nullptr;
+
+ // Is there a monster there ?
+ Monster = dungeon.findMonster(c);
+ if (Monster >= 0) {
+ // Set up a pointer
+ m = &dungeon.Monster[Monster];
+ n = m->Type;
+ }
+
+ // Get weaponry info
+ Damage = 0;
+ if (_weapon >= 0 && _weapon != OB_AMULET)
+ Damage = OBJECT_INFO[_weapon].MaxDamage;
+ if (_weapon == OB_AMULET)
+ // Amulet Special Case
+ Damage = 10 + player.Level;
+
+ // If no, or not dexterous
+ if (Monster < 0 || player.Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player.Level) {
+ // Then a miss.
+ _message += "You missed !!\n";
+ _mode = DONE;
+ redraw();
+ delaySeconds(1);
+ return;
+ }
+
+ // Scored a hit
+ _message += "Hit !!!\n";
+
+ // Calculate HPs lost
+ n = 0;
+ if (Damage > 0)
+ n = (urand() % Damage);
+ n = n + player.Attr[AT_STRENGTH] / 5;
+ m->Strength = m->Strength - n; // Lose them
+
+ if (m->Strength < 0)
+ m->Strength = 0;
+ _message += Common::String::format("%s's Hit\nPoints now %d.\n",
+ MONSTER_INFO[m->Type].Name, m->Strength);
+
+ // Killed it ?
+ if (m->Strength == 0) {
+ m->Alive = 0; // It has ceased to be
+ int gold = (m->Type + player.Level); // Amount of gold
+ _message += Common::String::format("You get %d pieces of eight.\n", gold);
+ player.Attr[AT_GOLD] += gold;
+
+ player.HPGain += (m->Type * player.Level) / 2; // Calculate Gain
+
+ if (m->Type == player.Task) // Check done LB's task
+ player.TaskCompleted = 1;
+ }
+
+ _mode = DONE;
+ redraw();
+ delaySeconds(1);
+}
+
+void Attack::showMessage(const Common::String &msg) {
+ _message = msg;
+ _mode = DONE;
+ redraw();
+ delaySeconds(1);
+}
+
+void Attack::timeout() {
+ close();
+ g_events->send("Dungeon", GameMessage("ENDOFTURN"));
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/attack.h b/engines/ultima/ultima0/views/attack.h
index 794296f5f3a..b57115fe442 100644
--- a/engines/ultima/ultima0/views/attack.h
+++ b/engines/ultima/ultima0/views/attack.h
@@ -23,19 +23,40 @@
#define ULTIMA0_VIEWS_ATTACK_H
#include "ultima/ultima0/views/view.h"
+#include "ultima/ultima0/data/data.h"
namespace Ultima {
namespace Ultima0 {
namespace Views {
class Attack : public View {
+private:
+ enum Mode {
+ WHICH_WEAPON, AMULET, THROW_SWING, DONE
+ };
+ Mode _mode = WHICH_WEAPON;
+ int _weapon = -1;
+ int _damage = 0;
+ Common::String _message;
+
+ void selectObject(int objNum);
+ void selectMagic(int magicNum);
+ void attackMissile();
+ void attackWeapon();
+ void attackHitMonster(const COORD &c);
+ void showMessage(const Common::String &msg);
+
public:
Attack();
~Attack() override {}
+ bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
bool msgKeypress(const KeypressMessage &msg) override;
+ bool msgAction(const ActionMessage &msg) override;
+ void timeout();
};
} // namespace Views
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
index cddcf993fb2..aba80eebf1e 100644
--- a/engines/ultima/ultima0/views/info.cpp
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -85,7 +85,7 @@ bool Info::msgKeypress(const KeypressMessage &msg) {
return false;
for (int i = 0; i < MAX_OBJ; ++i) {
- if (toupper(msg.ascii) == OBJECT_INFO[i].Key ||
+ if (msg.keycode == OBJECT_INFO[i].keycode ||
(Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i].Cost)) {
selectObject(i);
return true;
Commit: 1ea0551b6fbed0e780b3546e39b6a98707e28bcf
https://github.com/scummvm/scummvm/commit/1ea0551b6fbed0e780b3546e39b6a98707e28bcf
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Add Akalabeth project author to credits
Changed paths:
engines/ultima/credits.pl
diff --git a/engines/ultima/credits.pl b/engines/ultima/credits.pl
index c75ed89611e..e1d93eba033 100644
--- a/engines/ultima/credits.pl
+++ b/engines/ultima/credits.pl
@@ -3,6 +3,7 @@ begin_section("Ultima");
add_person("Matthew Duggan", "stauff", "");
add_person("Matthew Jimenez", "OMGPizzaGuy", "");
+ add_person("Paul Robson", "", "(Akalabeth)");
add_person("Daniel c. Würl", "dwuerl", "(Nuvie)");
add_person("Eric Fry", "yuv422", "(Nuvie)");
add_person("Jeremy Newman", "laxdragon", "(Nuvie)");
Commit: 5c57c867654492301ef107c3033bf253058feefa
https://github.com/scummvm/scummvm/commit/5c57c867654492301ef107c3033bf253058feefa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Remove original project files
Changed paths:
R engines/ultima/ultima0/akalabeth.h
R engines/ultima/ultima0/attack.cpp
R engines/ultima/ultima0/british.cpp
R engines/ultima/ultima0/ddraw.cpp
R engines/ultima/ultima0/dead.cpp
R engines/ultima/ultima0/draw.cpp
R engines/ultima/ultima0/draw2.cpp
R engines/ultima/ultima0/draw3.cpp
R engines/ultima/ultima0/dungeon.cpp
R engines/ultima/ultima0/globals.cpp
R engines/ultima/ultima0/hardware.cpp
R engines/ultima/ultima0/main.cpp
R engines/ultima/ultima0/monst.cpp
R engines/ultima/ultima0/move.cpp
R engines/ultima/ultima0/player.cpp
R engines/ultima/ultima0/sdw.cpp
R engines/ultima/ultima0/sdw.h
R engines/ultima/ultima0/struct.h
R engines/ultima/ultima0/town.cpp
R engines/ultima/ultima0/world.cpp
engines/ultima/module.mk
engines/ultima/ultima0/ultima0.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 4f9a5a1b319..428cb2dcfb0 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -13,24 +13,6 @@ MODULE_OBJS += \
ultima0/events.o \
ultima0/messages.o \
ultima0/metaengine.o \
- ultima0/attack.o \
- ultima0/british.o \
- ultima0/ddraw.o \
- ultima0/dead.o \
- ultima0/draw.o \
- ultima0/draw2.o \
- ultima0/draw3.o \
- ultima0/dungeon.o \
- ultima0/globals.o \
- ultima0/hardware.o \
- ultima0/hdr.o \
- ultima0/main.o \
- ultima0/monst.o \
- ultima0/move.o \
- ultima0/player.o \
- ultima0/sdw.o \
- ultima0/town.o \
- ultima0/world.o \
ultima0/data/data.o \
ultima0/data/monster_logic.o \
ultima0/gfx/dungeon.o \
@@ -42,6 +24,7 @@ MODULE_OBJS += \
ultima0/views/attack.o \
ultima0/views/castle.o \
ultima0/views/create_character.o \
+ ultima0/views/dead.o \
ultima0/views/dungeon.o \
ultima0/views/info.o \
ultima0/views/startup.o \
diff --git a/engines/ultima/ultima0/akalabeth.h b/engines/ultima/ultima0/akalabeth.h
deleted file mode 100644
index 23f58e967f6..00000000000
--- a/engines/ultima/ultima0/akalabeth.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 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 ULTIMA0_AKALABETH_H
-#define ULTIMA0_AKALABETH_H
-
-#include "common/str.h"
-#include "ultima/ultima0/struct.h" /* Our structure file */
-
-namespace Ultima {
-namespace Ultima0 {
-
-void HWInitialise(void); /* HARDWARE.C prototyping */
-void HWTerminate(void);
-void HWColour(int);
-void HWLine(int, int, int, int);
-void HWStatus(double, int, int);
-void HWChar(int);
-int HWGetKey(void);
-void HWClear(void);
-
-void DRAWTile(RECT *, int); /* DRAW.C prototyping */
-void DRAWSetRect(RECT *, int, int, int, int);
-void DRAWMonster(int, int, int, double);
-void DRAWDungeon(RECT *, RECT *, int, int, int, int, int);
-void DRAWText(const char *, ...);
-
-void MONSTAttack(PLAYER *, DUNGEONMAP *); /* MONST.C prototyping */
-
-int MAINSuper(void); /* MAIN.C prototyping */
-void MAINSetup(void);
-void MAINStart(void);
-
-void PLAYERInit(PLAYER *); /* PLAYER.C prototyping */
-void PLAYERCharacter(PLAYER *);
-void PLAYERInv(PLAYER *);
-
-void DEADCode(PLAYER *); /* DEAD.C prototyping */
-int DEADGetYesNo(void);
-
-const char *GLOObjName(int); /* GLOBAL.C prototyping */
-const char *GLOAttribName(int);
-const char *GLOClassName(char);
-const char *GLOMonsterName(int);
-int GLOMonsterLevel(int);
-void GLOGetInfo(int n, int *, int *, int *);
-
-void TOWNEnter(WORLDMAP *, PLAYER *); /* TOWN.C prototyping */
-
-void BRITISHEnter(WORLDMAP *, PLAYER *); /* BRITISH.C prototyping */
-
-void WORLDCreate(PLAYER *, WORLDMAP *); /* WORLD.C prototyping */
-void WORLDDraw(PLAYER *, WORLDMAP *, int);
-int WORLDRead(WORLDMAP *, int, int);
-
-void DUNGEONCreate(PLAYER *, DUNGEONMAP *); /* DUNGEON.C prototyping */
-
-void DDRAWDraw(PLAYER *, DUNGEONMAP *); /* DDRAW.C prototyping */
-int DDRAWFindMonster(DUNGEONMAP *, COORD *);
-
-void ATTACKMonster(PLAYER *, DUNGEONMAP *); /* ATTACK.C prototyping */
-
-/* MOVE.C prototyping */
-void MOVEEnterExit(WORLDMAP *, PLAYER *, DUNGEONMAP *);
-void MOVEMove(int, WORLDMAP *, PLAYER *, DUNGEONMAP *, int, int);
-void MOVERotLeft(COORD *);
-
-} // namespace Ultima0
-} // namespace Ultima
-
-#endif
diff --git a/engines/ultima/ultima0/attack.cpp b/engines/ultima/ultima0/attack.cpp
deleted file mode 100644
index 88e84e094fd..00000000000
--- a/engines/ultima/ultima0/attack.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Attack any nearby monsters */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-static void _ATTACKWeapon(PLAYER *, DUNGEONMAP *, int);
-static int _ATTACKMissile(PLAYER *, DUNGEONMAP *, int);
-static void _ATTACKKill(MONSTER *, PLAYER *);
-static void _ATTACKAmulet(PLAYER *, DUNGEONMAP *);
-static void _ATTACKHitMonster(PLAYER *, DUNGEONMAP *, int, COORD *);
-
-/************************************************************************/
-/* */
-/* Attack any nearby monsters */
-/* */
-/************************************************************************/
-
-void ATTACKMonster(PLAYER *p, DUNGEONMAP *d) {
- int c, Key, i, n, Damage;
- DRAWText("With what ? "); /* Which weapon */
- c = HWGetKey();
- n = -1; /* Discover which. */
- for (i = 0; i < p->Objects; i++)
- {
- GLOGetInfo(i, nullptr, nullptr, &Key); /* Get the associated key */
- if (toupper(Key) == c) /* Found the object ? */
- if (i != OB_FOOD) n = i;/* Not food ! */
- }
- if (n < 0) /* Check the result */
- {
- Damage = 0; DRAWText("Hands.\n");
- } else
- {
- DRAWText("%s.\n", GLOObjName(n));
- GLOGetInfo(n, &Damage, nullptr, nullptr);
- }
-
- if (p->Object[n] == 0) /* Must own an object */
- {
- DRAWText("Not owned.\n");
- return;
- }
- if (p->Class == 'M' && /* Mages are limited */
- (n == OB_BOW || n == OB_RAPIER))
- {
- DRAWText("Mages can't use\n%ss.\n", GLOObjName(n));
- return;
- }
-
- if (n == OB_AMULET) /* Use an amulet */
- {
- _ATTACKAmulet(p, d);
- return;
- }
-
- if (n == OB_BOW || n == OB_AXE) /* Check for axe work */
- {
- if (_ATTACKMissile(p, d, n) == 0) /* Throw code */
- _ATTACKWeapon(p, d, n); /* if not thrown, use as weapon */
- } else
- _ATTACKWeapon(p, d, n); /* use as bashing weapon */
-}
-
-/************************************************************************/
-/* */
-/* Attack using object as a hand held weapon */
-/* */
-/************************************************************************/
-
-static void _ATTACKWeapon(PLAYER *p, DUNGEONMAP *d, int Weapon) {
- COORD c;
- c.x = p->Dungeon.x + p->DungDir.x; /* Look at what's there */
- c.y = p->Dungeon.y + p->DungDir.y;
- _ATTACKHitMonster(p, d, Weapon, &c);
-}
-
-/************************************************************************/
-/* */
-/* Use weapon on monster */
-/* */
-/************************************************************************/
-
-static void _ATTACKHitMonster(PLAYER *p, DUNGEONMAP *d, int Weapon, COORD *c) {
- int n = 0, Monster, Damage;
- MONSTER *m = nullptr;
-
- Monster = DDRAWFindMonster(d, c); /* Is there a monster there ? */
- if (Monster >= 0) /* Set up a pointer */
- {
- m = &(d->Monster[Monster]);
- n = m->Type;
- }
-
- Damage = 0; /* Get weaponry info */
- if (Weapon >= 0 && Weapon != OB_AMULET)
- GLOGetInfo(Weapon, &Damage, nullptr, nullptr);
- if (Weapon == OB_AMULET) /* Amulet Special Case */
- Damage = 10 + p->Level;
-
- if (Monster < 0 || /* If no, or not dexterous */
- p->Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + p->Level)
- {
- DRAWText("You missed !!\n"); /* Then a miss. */
- return;
- }
-
- DRAWText("Hit !!!\n"); /* Scored a hit */
- n = 0; /* Calculate HPs lost */
- if (Damage > 0) n = (urand() % Damage);
- n = n + p->Attr[AT_STRENGTH] / 5;
- m->Strength = m->Strength - n; /* Lose them */
- if (m->Strength < 0) m->Strength = 0;
- DRAWText("%s's Hit\nPoints now %d.\n", /* Display the HP Value */
- GLOMonsterName(m->Type), m->Strength);
- if (m->Strength == 0)_ATTACKKill(m, p); /* Killed it ? */
-
-}
-
-/************************************************************************/
-/* */
-/* Kill off a monster */
-/* */
-/************************************************************************/
-
-static void _ATTACKKill(MONSTER *m, PLAYER *p) {
- int n;
- m->Alive = 0; /* Deaded */
- n = (m->Type + p->Level); /* Amount of Gold */
- DRAWText("You get %d\npieces of eight.\n", n);
- p->Attr[AT_GOLD] += n;
- p->HPGain += (m->Type * p->Level) / 2; /* Calculate Gain */
- if (m->Type == p->Task) /* Check done LB's task */
- p->TaskCompleted = 1;
-}
-
-/************************************************************************/
-/* */
-/* Attack using object as a missile */
-/* */
-/************************************************************************/
-
-static int _ATTACKMissile(PLAYER *p, DUNGEONMAP *d, int Weapon) {
- int n, y, Dist;
- char ch;
- COORD c, c1;
- if (Weapon == OB_AXE) /* Axes can be thrown or swung */
- {
- DRAWText("Throw or Swing ? ");
- while (ch = HWGetKey(), ch != 'T' && ch != 'S') {
- }
- DRAWText(ch == 'T' ? "Throw.\n" : "Swing.\n");
- if (ch == 'S') return 0;
- p->Object[OB_AXE]--; /* Lose a thrown axe */
- }
- c.x = p->Dungeon.x; /* See what's to hit */
- c.y = p->Dungeon.y;
- Dist = -1;
- for (y = 0; y < 5; y++) /* A maximum distance of 5 */
- {
- c.x = c.x + p->DungDir.x; /* Next position */
- c.y = c.y + p->DungDir.y;
- n = DDRAWFindMonster(d, &c); /* Monster there ? */
- if (n >= 0) {
- c1 = c; Dist = n;
- } /* If so , record that */
- if (!ISDRAWOPEN /* If wall, or door, stop */
- (d->Map[c.x][c.y])) y = 99;
- }
- if (Dist < 0) /* Hit nothing */
- DRAWText("You missed !!\n"); /* Then a miss. */
- else
- _ATTACKHitMonster(p, d, Weapon, &c1);
- return 1;
-}
-
-/************************************************************************/
-/* */
-/* Use an amulet */
-/* */
-/************************************************************************/
-
-static void _ATTACKAmulet(PLAYER *p, DUNGEONMAP *d) {
- int i, Magic = urand() % 4;
- if (p->Class == 'M') /* Mages use them properly ! */
- {
- DRAWText("1] Ladder Up\n");
- DRAWText("2] Ladder Down\n");
- DRAWText("3] Attack Monster\n");
- DRAWText("4] Bad Magic\n");
- do
- Magic = HWGetKey() - '1';
- while (Magic < 0 || Magic > 3);
- }
- if (urand() % 5 == 0) /* Last charge */
- {
- DRAWText("Last charge on this Amulet.\n");
- p->Object[OB_AMULET]--;
- }
- switch (Magic)
- {
- case 0: /* Ladder up */
- d->Map[p->Dungeon.x][p->Dungeon.y] = DT_LADDERUP;
- break;
- case 1: /* Ladder down */
- d->Map[p->Dungeon.x][p->Dungeon.y] = DT_LADDERDN;
- break;
- case 2: /* Amulet Attack */
- _ATTACKMissile(p, d, OB_AMULET);
- break;
- case 3: /* Bad Magic */
- switch (urand() % 3)
- {
- case 0:
- DRAWText("You have been turned into a Toad.\n");
- for (i = AT_STRENGTH; i <= AT_WISDOM; i++)
- p->Attr[i] = 3;
- break;
- case 1:
- DRAWText("You have been turned into a Lizard Man.\n");
- for (i = AT_HP; i <= AT_WISDOM; i++)
- p->Attr[i] = floor(p->Attr[i] * 5 / 2);
- break;
- case 2:
- DRAWText("Backfire !!\n");
- p->Attr[AT_HP] = floor(p->Attr[AT_HP]) / 2;
- break;
- }
- break;
- }
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/british.cpp b/engines/ultima/ultima0/british.cpp
deleted file mode 100644
index d48dc4345c8..00000000000
--- a/engines/ultima/ultima0/british.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Lord British's Castle */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-static char *_BRITISHName(int);
-
-/************************************************************************/
-/* */
-/* Visit Lord British */
-/* */
-/************************************************************************/
-
-void BRITISHEnter(WORLDMAP *w, PLAYER *p) {
- int NextTask = p->Task + 1;
- int c, i;
-
- if (*p->Name == '\0') /* Require the player name */
- {
- DRAWText("Welcome, peasant into\nthe Halls of the\nmighty Lord British.");
- DRAWText("Herein thou may choose\nto do battle with\nthe evil creatures of the\ndepths, for great\nreward.\n\n");
- DRAWText("What is thy name,\npeasant ?\n");
-
- do /* Read the name. */
- {
- c = HWGetKey();
- if (Common::isAlpha(c) && strlen(p->Name) < MAX_NAME)
- {
- if (*p->Name != '\0') c = tolower(c);
- Common::sprintf_s(p->Name + strlen(p->Name), 9 - strlen(p->Name), "%c", c);
- HWChar(c);
- }
- } while (c >= ' ');
- DRAWText("\n\n");
- /* Great adventure question */
- DRAWText("Doest thou wish\nfor great adventure ?\n\n");
- if (DEADGetYesNo() == 0)
- {
- DRAWText("Then leave and begone!\n\n");
- Common::strcpy_s(p->Name, "");
- return;
- }
- }
-
- if (p->Task > 0) /* Set a task before ? */
- {
- if (p->TaskCompleted == 0) /* Outstanding task */
- {
- DRAWText("%s, why hast\nthou returned ?\nThou must kill\n%s.\nGo now and complete\nthy quest !\n",
- p->Name, _BRITISHName(p->Task));
- } else
- {
- DRAWText("\nAaaahhhh....\n%s.\n\n", p->Name);
- DRAWText("Thou has accomplished\nthy quest.\n\n");
- if (p->Task == MAX_MONSTERS)
- {
- DRAWText("Lord %s,thou\nhast proved thyself worthy of\nKnighthood, continue\nif thou doth wish\nbut thou hast \naccomplished the\nmain objective of\nthe game.\n\n");
- DRAWText("Now, maybe thou art\nfoolhardy enough to\ntry difficulty level %d.\n\n", p->Skill + 1);
- } else
- {
- DRAWText("Unfortunately, this\nis not enough to\nbecome a knight.\n\n");
- p->Task = 0; /* We need another task */
- }
- }
- }
- if (p->Task == 0) /* Need a new task..... */
- {
- if (NextTask == 1)
- {
- DRAWText("Good ! Thou shalt try\nto become a knight.\nThy first task is to\ngointo the dungeons\nand return only after\nkilling %s.\n\n",
- _BRITISHName(NextTask));
- } else
- {
- DRAWText("Thou must now kill\n%s.\n\n", _BRITISHName(NextTask));
- }
- DRAWText("Go now upon this\nQuest, and may lady\nluck fair be upon you\nAlso I, Lord British\n,have increased each\nof your attributes\nby one.\n\n");
- p->Task = NextTask;
- p->TaskCompleted = 0;
- for (i = 0; i < p->Attributes; i++) /* LB gives you extra attribs */
- p->Attr[i]++;
- }
-}
-
-/************************************************************************/
-/* */
-/* Get name modified with a or an */
-/* */
-/************************************************************************/
-
-static char *_BRITISHName(int m) {
- static char _Buffer[64];
- const char *p = GLOMonsterName(m);
- Common::sprintf_s(_Buffer, "%s %s",
- (strchr("aeiou", tolower(*p)) != nullptr) ? "an" : "a",
- p);
- return(_Buffer);
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/ddraw.cpp b/engines/ultima/ultima0/ddraw.cpp
deleted file mode 100644
index 3f7b2346ee7..00000000000
--- a/engines/ultima/ultima0/ddraw.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Dungeon Drawing Code */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-static void _DDRAWCalcRect(RECT *, double);
-
-/************************************************************************/
-/* */
-/* Draw the dungeon */
-/* */
-/************************************************************************/
-
-void DDRAWDraw(PLAYER *p, DUNGEONMAP *d) {
- double Level = 0;
- RECT rOut, rIn;
- COORD Dir, Pos, Next;
- int Monster, Front, Left, Right;
- DRAWSetRect(&rOut, 0, 1023, 1260, 10);
- _DDRAWCalcRect(&rOut, 0);
- Pos = p->Dungeon; /* Get position */
- do
- {
- Level++; /* Next level */
- _DDRAWCalcRect(&rIn, Level);
- Next.x = Pos.x + p->DungDir.x; /* Next position */
- Next.y = Pos.y + p->DungDir.y;
-
- Dir = p->DungDir; MOVERotLeft(&Dir); /* To the left */
- Left = d->Map[Pos.x + Dir.x][Pos.y + Dir.y];
- MOVERotLeft(&Dir); MOVERotLeft(&Dir);/* To the right */
- Right = d->Map[Pos.x + Dir.x][Pos.y + Dir.y];
- Front = d->Map[Next.x][Next.y]; /* What's in front ? */
-
- Monster = DDRAWFindMonster(d, &Pos); /* Find ID of monster here */
- if (Monster >= 0) /* Find Type if Found */
- {
- Monster = d->Monster[Monster].Type;
- }
- DRAWDungeon(&rOut, &rIn, /* Draw the dungeon */
- Left, Front, Right,
- d->Map[Pos.x][Pos.y], Monster);
-
- Pos = Next; /* Next position down */
- rOut = rIn; /* Last in is new out */
- } while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(Front));
-}
-
-/************************************************************************/
-/* */
-/* Calculate display rectangle */
-/* */
-/************************************************************************/
-
-static void _DDRAWCalcRect(RECT *r, double Level) {
- int xWidth, yWidth;
- xWidth = (int) /* Calculate frame size */
- (atan(1.0 / (Level + 1)) / atan(1.0) * 1279 + 0.5);
- xWidth = 1279 / (Level + 1);
- yWidth = xWidth * 10 / 13;
- r->left = 640 - xWidth / 2; /* Calculate drawing rectangle */
- r->right = 640 + xWidth / 2;
- r->top = 512 + yWidth / 2;
- r->bottom = 512 - yWidth / 2;
-}
-
-/************************************************************************/
-/* */
-/* Find Monster ID at given location */
-/* */
-/************************************************************************/
-
-int DDRAWFindMonster(DUNGEONMAP *d, COORD *c) {
- int i, n = -1;
- for (i = 0; i < d->MonstCount; i++)
- if (c->x == d->Monster[i].Loc.x &&
- c->y == d->Monster[i].Loc.y &&
- d->Monster[i].Alive != 0) n = i;
- return n;
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/dead.cpp b/engines/ultima/ultima0/dead.cpp
deleted file mode 100644
index 96d08dd5cb3..00000000000
--- a/engines/ultima/ultima0/dead.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Dead Code */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* You have died */
-/* */
-/************************************************************************/
-
-void DEADCode(PLAYER *p) {
- const char *s = p->Name;
- if (*s == '\0') s = "the peasant";
- DRAWText("\nWe mourn the passing of %s and his computer.\n\n", s);
- DRAWText("Dost thou wish resurrection ?\n\n");
-
- if (DEADGetYesNo())
- {
- DRAWText("Yes.\n");
- MAINSetup();
- }
-}
-
-/************************************************************************/
-/* */
-/* Get a yes or no */
-/* */
-/************************************************************************/
-
-int DEADGetYesNo(void) {
- char c;
- do
- c = HWGetKey();
- while (c != 'Y' && c != 'N');
- return (c == 'Y');
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/draw.cpp b/engines/ultima/ultima0/draw.cpp
deleted file mode 100644
index 5df4bd97fcb..00000000000
--- a/engines/ultima/ultima0/draw.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Draw World Objects */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h" /* Our prototypes */
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* Draw object in a given rectangle */
-/* */
-/************************************************************************/
-
-#define X(n) (x1 + w * (n)/10)
-#define Y(n) (y1 + h * (n)/10)
-#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
-
-void DRAWTile(RECT *r, int Obj) {
- int x1 = r->left; /* Extract values */
- int y1 = r->top;
- int w = r->right - r->left; /* Calculate width and height */
- int h = r->bottom - r->top;
-
- switch (Obj) /* Decide on the object */
- {
- case WT_SPACE: /* Space does nothing at all */
- break;
-
- case WT_MOUNTAIN: /* Mountain the cracked effect */
- HWColour(COL_MOUNTAIN);
- HWLine(X(2), Y(6), X(2), Y(10));
- HWLine(X(0), Y(8), X(2), Y(8));
- HWLine(X(2), Y(6), X(4), Y(6));
- HWLine(X(4), Y(6), X(4), Y(4));
- HWLine(X(2), Y(2), X(4), Y(4));
- HWLine(X(2), Y(2), X(2), Y(0));
- HWLine(X(2), Y(2), X(0), Y(2));
- HWLine(X(8), Y(4), X(4), Y(4));
- HWLine(X(8), Y(4), X(8), Y(0));
- HWLine(X(8), Y(2), X(10), Y(2));
- HWLine(X(6), Y(4), X(6), Y(8));
- HWLine(X(10), Y(8), X(6), Y(8));
- HWLine(X(8), Y(8), X(8), Y(10));
- break;
-
- case WT_TREE: /* Tree is just a box */
- HWColour(COL_TREE);
- BOX(3, 3, 7, 7);
- break;
-
- case WT_TOWN: /* Down is 5 boxes */
- HWColour(COL_TOWN);
- BOX(2, 2, 4, 4); BOX(4, 4, 6, 6); BOX(6, 6, 8, 8);
- BOX(6, 2, 8, 4); BOX(2, 6, 4, 8);
- break;
-
- case WT_DUNGEON: /* Dungeon is a cross */
- HWColour(COL_DUNGEON);
- HWLine(X(3), Y(3), X(7), Y(7));
- HWLine(X(7), Y(3), X(3), Y(7));
- break;
-
- case WT_BRITISH: /* British castle */
- HWColour(COL_BRITISH);
- HWLine(X(2), Y(2), X(8), Y(8));
- HWLine(X(8), Y(2), X(2), Y(8));
- BOX(0, 0, 10, 10);
- BOX(2, 2, 8, 8);
- break;
-
- case WT_PLAYER:
- HWColour(COL_PLAYER);
- HWLine(X(4), Y(5), X(6), Y(5));
- HWLine(X(5), Y(4), X(5), Y(6));
- break;
-
- default:
- break;
- }
-}
-
-/************************************************************************/
-/* */
-/* Copy values into a rectangle */
-/* */
-/************************************************************************/
-
-void DRAWSetRect(RECT *r, int x1, int y1, int x2, int y2) {
- r->left = x1; r->right = x2;
- r->top = y1; r->bottom = y2;
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/draw2.cpp b/engines/ultima/ultima0/draw2.cpp
deleted file mode 100644
index e21722fd58f..00000000000
--- a/engines/ultima/ultima0/draw2.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Draw Dungeon View Part */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-static void _DRAWRect(int, int, int, int);
-static void _DRAWSetRange(int, int, int, int, int);
-static void _DRAWConvert(int *, int *);
-static void _DRAWWall(int);
-static void _DRAWPit(RECT *, int);
-
-int xLeft, xRight, yBottom, /* Slanted drawing constants */
-yDiffLeft, yDiffRight;
-
-/************************************************************************/
-/* */
-/* Draw part of dungeon */
-/* */
-/************************************************************************/
-
-void DRAWDungeon(RECT *rOut, RECT *rIn,
- int Left, int Centre, int Right,
- int Room, int Monster) {
- int x1, y1, x, y, y2;
- RECT r;
- double Scale;
-
- HWColour(COL_WALL); /* Start on the walls */
-
- if (ISDRAWOPEN(Left)) /* Do we draw the left edge */
- {
- HWLine(rOut->left, rIn->top, rIn->left, rIn->top);
- HWLine(rOut->left, rIn->bottom, rIn->left, rIn->bottom);
- HWLine(rOut->left, rOut->top, rOut->left, rOut->bottom);
- } else /* If closed, draw left diags */
- {
- HWLine(rOut->left, rOut->top, rIn->left, rIn->top);
- HWLine(rOut->left, rOut->bottom, rIn->left, rIn->bottom);
- }
-
- if (ISDRAWOPEN(Right)) /* Do we draw the right edge */
- {
- HWLine(rOut->right, rIn->top, rIn->right, rIn->top);
- HWLine(rOut->right, rIn->bottom, rIn->right, rIn->bottom);
- HWLine(rOut->right, rOut->top, rOut->right, rOut->bottom);
- } else /* If closed draw right diags */
- {
- HWLine(rOut->right, rOut->top, rIn->right, rIn->top);
- HWLine(rOut->right, rOut->bottom, rIn->right, rIn->bottom);
- }
-
- if (!ISDRAWOPEN(Centre)) /* Back wall ? */
- {
- HWLine(rIn->left, rIn->top, rIn->right, rIn->top);
- HWLine(rIn->left, rIn->bottom, rIn->right, rIn->bottom);
- if (!ISDRAWOPEN(Left)) /* Corner if left,right closed */
- HWLine(rIn->left, rIn->top, rIn->left, rIn->bottom);
- if (!ISDRAWOPEN(Right))
- HWLine(rIn->right, rIn->top, rIn->right, rIn->bottom);
- }
-
- _DRAWSetRange(rOut->left, rIn->left, /* Set up for left side */
- rOut->bottom,
- rOut->bottom - rOut->top,
- rIn->bottom - rIn->top);
- _DRAWWall(Left);
- _DRAWSetRange(rIn->right, rOut->right, /* Set up for right side */
- rIn->bottom,
- rIn->bottom - rIn->top,
- rOut->bottom - rOut->top);
- _DRAWWall(Right); /* Set up for centre */
- _DRAWSetRange(rIn->left, rIn->right,
- rIn->bottom,
- rIn->bottom - rIn->top,
- rIn->bottom - rIn->top);
- _DRAWWall(Centre);
-
- if (Room == DT_LADDERUP)
- {
- DRAWSetRect(&r, rOut->left, rOut->top, rOut->right, rIn->top);
- _DRAWPit(&r, 1);
- }
- if (Room == DT_LADDERDN || Room == DT_PIT)
- {
- DRAWSetRect(&r, rOut->left, rIn->bottom, rOut->right, rOut->bottom);
- _DRAWPit(&r, -1);
- }
-
- DRAWSetRect(&r, /* Get the object area */
- (rIn->left + rOut->left) / 2,
- (rIn->top + rOut->top) / 2,
- (rIn->right + rOut->right) / 2,
- (rIn->bottom + rOut->bottom) / 2);
-
- if (Room == DT_LADDERUP || /* Ladder here ? */
- Room == DT_LADDERDN)
- {
- HWColour(COL_LADDER);
- y1 = r.top; y2 = r.bottom;
- x = (r.right - r.left) * 3 / 10;
- HWLine(r.left + x, y1, r.left + x, y2);
- HWLine(r.right - x, y1, r.right - x, y2);
- x1 = (y1 - y2) / 5;
- y = y2 + x1 / 2;
- while (y < y1)
- {
- HWLine(r.left + x, y, r.right - x, y);
- y = y + x1;
- }
- }
-
- Scale = 0.1; /* Scale (trial and error this :)) */
- Scale = Scale / (r.right - r.left) * 1059.0;
-
- if (Monster > 0) /* Monster here ? */
- {
- HWColour(COL_MONSTER);
- DRAWMonster((r.left + r.right) / 2, r.bottom, Monster, Scale);
- }
-
- if (Room == DT_GOLD) /* Draw the gold (as a mimic) */
- {
- HWColour(COL_MONSTER);
- DRAWMonster((r.left + r.right) / 2, r.bottom, MN_MIMIC, Scale);
- }
-
-}
-
-/************************************************************************/
-/* */
-/* Set the oblique drawing routine */
-/* */
-/************************************************************************/
-
-static void _DRAWSetRange(int x1, int x2, int y, int yd1, int yd2) {
- xLeft = x1; xRight = x2; /* Set x ranges */
- yBottom = y; /* Set lower left y value */
- yDiffLeft = yd1; yDiffRight = yd2; /* Set difference for either end */
-}
-
-/************************************************************************/
-/* */
-/* Convert coordinates from oblique to logical */
-/* */
-/************************************************************************/
-
-static void _DRAWConvert(int *px, int *py) {
- long x, y, yd; /* Longs for overflow in 16 bit */
- x = (xRight - xLeft); /* Calculate width */
- x = x * (*px) / 100 + xLeft; /* Work out horiz value */
- yd = (yDiffRight - yDiffLeft); /* Work out height of vert for x */
- yd = yd * (*px) / 100;
- y = yBottom + /* Half of the distance */
- yd / 2 - /* + Scaled total size */
- (yd + yDiffLeft) * (*py) / 100;
-
- *px = (int)x; /* Write back, casting to int */
- *py = (int)y;
-}
-
-/************************************************************************/
-/* */
-/* Draw a rectangle */
-/* */
-/************************************************************************/
-
-static void _DRAWRect(int x1, int y1, int x2, int y2) {
- HWLine(x1, y1, x2, y1); HWLine(x1, y1, x1, y2);
- HWLine(x2, y2, x2, y1); HWLine(x2, y2, x1, y2);
-}
-
-/************************************************************************/
-/* */
-/* Draw the pits/ladder hole */
-/* */
-/************************************************************************/
-
-static void _DRAWPit(RECT *r, int Dir) {
- int x1, x2, y1;
- HWColour(COL_HOLE);
- y1 = (r->top - r->bottom) / 5;
- r->bottom += y1; r->top -= y1;
- x1 = (r->right - r->left) / 5;
- r->left += x1; r->right -= x1;
- x2 = 0; x1 = x1 / 2;
- if (Dir > 0)
- {
- y1 = x1; x1 = x2; x2 = y1;
- }
- HWLine(r->left + x1, r->top, r->right - x1, r->top);
- HWLine(r->left + x1, r->top, r->left + x2, r->bottom);
- HWLine(r->left + x2, r->bottom, r->right - x2, r->bottom);
- HWLine(r->right - x1, r->top, r->right - x2, r->bottom);
-
-}
-
-/************************************************************************/
-/* */
-/* Draw wall object using current setting */
-/* */
-/************************************************************************/
-
-static void _DRAWWall(int n) {
- int x1, y1, x2, y2;
- if (n == DT_DOOR)
- {
- HWColour(COL_DOOR);
- x1 = 35; y1 = 0; x2 = 35; y2 = 60;
- _DRAWConvert(&x1, &y1);
- _DRAWConvert(&x2, &y2);
- HWLine(x1, y1, x2, y2);
- x1 = 65; y1 = 60; _DRAWConvert(&x1, &y1);
- HWLine(x1, y1, x2, y2);
- x2 = 65; y2 = 0; _DRAWConvert(&x2, &y2);
- HWLine(x1, y1, x2, y2);
- }
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/draw3.cpp b/engines/ultima/ultima0/draw3.cpp
deleted file mode 100644
index 20796b80a73..00000000000
--- a/engines/ultima/ultima0/draw3.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Draw Monster Graphics */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-#define PARAMS double x,double y,double d /* Parameters for Draw funcs */
-#define END (-9999.99) /* End marker */
-
-static void _DRAWSkeleton(PARAMS); /* Local Prototypes */
-static void _DRAWThief(PARAMS);
-static void _DRAWRat(PARAMS);
-static void _DRAWOrc(PARAMS);
-static void _DRAWViper(PARAMS);
-static void _DRAWCarrion(PARAMS);
-static void _DRAWGremlin(PARAMS);
-static void _DRAWMimic(PARAMS);
-static void _DRAWDaemon(PARAMS);
-static void _DRAWBalrog(PARAMS);
-
-int xPos = 640; /* Drawing position */
-int yPos = 512;
-
-/************************************************************************/
-/* */
-/* Draw Monster Graphics */
-/* */
-/************************************************************************/
-
-void DRAWMonster(int x, int y, int Monster, double Scale) {
- xPos = x; yPos = y; /* Save drawing pos */
- if (Monster == MN_MIMIC) /* Fix for Mimic/Chest */
- xPos = xPos - 90;
- switch (Monster) /* Call appropriate function */
- {
- case MN_SKELETON: _DRAWSkeleton(0, 0, Scale); break;
- case MN_THIEF: _DRAWThief(0, 0, Scale); break;
- case MN_RAT: _DRAWRat(0, 0, Scale); break;
- case MN_ORC: _DRAWOrc(0, 0, Scale); break;
- case MN_VIPER: _DRAWViper(0, 0, Scale); break;
- case MN_CARRION: _DRAWCarrion(0, 0, Scale); break;
- case MN_GREMLIN: _DRAWGremlin(0, 0, Scale); break;
- case MN_MIMIC: _DRAWMimic(0, 0, Scale); break;
- case MN_DAEMON: _DRAWDaemon(0, 0, Scale); break;
- case MN_BALROG: _DRAWBalrog(0, 0, Scale); break;
- }
-}
-
-/************************************************************************/
-/* */
-/* Draw a text string. Here because use of ... like HPLOT */
-/* */
-/************************************************************************/
-
-void DRAWText(const char *Format, ...) {
- va_list alist;
- char Buffer[512], *p;
- va_start(alist, Format);
- Common::vsprintf_s(Buffer, Format, alist);
- p = Buffer;
- while (*p != '\0')
- {
- if (*p == '\n') HWChar(13), p++;
- else HWChar(*p++);
- }
- va_end(alist);
-}
-
-/************************************************************************/
-/* */
-/* Emulate the Apple ][ HPLOT function */
-/* */
-/************************************************************************/
-
-static void _HPlot(double x, double y, ...) {
- va_list alist;
- double y1, x1;
- va_start(alist, y); /* Start reading values */
- do
- {
- x1 = va_arg(alist, double); /* Get the next two */
- y1 = va_arg(alist, double);
- if (x1 != END && y1 != END) /* If legit, draw the line */
- HWLine(xPos + x, yPos - y, xPos + x1, yPos - y1);
- x = x1; y = y1;
- } while (x1 != END && y1 != END);
- va_end(alist);
-}
-
-/************************************************************************/
-/* */
-/* Drawing functions, grabbed from the Apple II original */
-/* */
-/************************************************************************/
-
-static void _DRAWSkeleton(PARAMS) {
- _HPlot(y - 23 / d, x, y - 15 / d, x, y - 15 / d, x - 15 / d, y - 8 / d, x - 30 / d, y + 8 / d, x - 30 / d, y + 15 / d, x - 15 / d, y + 15 / d, x, y + 23 / d, x, END, END);
- _HPlot(y, x - 26 / d, y, x - 65 / d, END, END);
- _HPlot(y - 2 / d + .5, x - 38 / d, y + 2 / d + .5, x - 38 / d, END, END);
- _HPlot(y - 3 / d + .5, x - 45 / d, y + 3 / d + .5, x - 45 / d, END, END);
- _HPlot(y - 5 / d + .5, x - 53 / d, y + 5 / d + .5, x - 53 / d, END, END);
- _HPlot(y - 23 / d, x - 56 / d, y - 30 / d, x - 53 / d, y - 23 / d, x - 45 / d, y - 23 / d, x - 53 / d, y - 8 / d, x - 38 / d, END, END);
- _HPlot(y - 15 / d, x - 45 / d, y - 8 / d, x - 60 / d, y + 8 / d, x - 60 / d, y + 15 / d, x - 45 / d, END, END);
- _HPlot(y + 15 / d, x - 42 / d, y + 15 / d, x - 57 / d, END, END);
- _HPlot(y + 12 / d, x - 45 / d, y + 20 / d, x - 45 / d, END, END);
- _HPlot(y, x - 75 / d, y - 5 / d + .5, x - 80 / d, y - 8 / d, x - 75 / d, y - 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 65 / d, END, END);
- _HPlot(y + 5 / d + .5, x - 65 / d, y + 8 / d, x - 75 / d, y + 5 / d + .5, x - 80 / d, y - 5 / d + .5, x - 80 / d, END, END);
- _HPlot(y - 5 / d + .5, x - 72 / d, END, END);
- _HPlot(y + 5 / d + .5, x - 72 / d, END, END);
-}
-
-static void _DRAWThief(PARAMS) {
- _HPlot(y, x - 56 / d, y, x - 8 / d, y + 10 / d, x, y + 30 / d, x, y + 30 / d, x - 45 / d, y + 10 / d, x - 64 / d, y, x - 56 / d, END, END);
- _HPlot(y - 10 / d, x - 64 / d, y - 30 / d, x - 45 / d, y - 30 / d, x, y - 10 / d, x, y, x - 8 / d, END, END);
- _HPlot(y - 10 / d, x - 64 / d, y - 10 / d, x - 75 / d, y, x - 83 / d, y + 10 / d, x - 75 / d, y, x - 79 / d, y - 10 / d, x - 75 / d, y, x - 60 / d, y + 10 / d, x - 75 / d, y + 10 / d, x - 64 / d, END, END);
-}
-
-static void _DRAWRat(PARAMS) {
- _HPlot(y + 5 / d, x - 30 / d, y, x - 25 / d, y - 5 / d, x - 30 / d, y - 15 / d, x - 5 / d, y - 10 / d, x, y + 10 / d, x, y + 15 / d, x - 5 / d, END, END);
- _HPlot(y + 20 / d, x - 5 / d, y + 10 / d, x, y + 15 / d, x - 5 / d, y + 5 / d, x - 30 / d, y + 10 / d, x - 40 / d, y + 3 / d + .5, x - 35 / d, y - 3 / d + .5, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 30 / d, END, END);
- _HPlot(y - 5 / d, x - 33 / d, y - 3 / d + .5, x - 30 / d, END, END);
- _HPlot(y + 5 / d, x - 33 / d, y + 3 / d + .5, x - 30 / d, END, END);
- _HPlot(y - 5 / d, x - 20 / d, y - 5 / d, x - 15 / d, END, END);
- _HPlot(y + 5 / d, x - 20 / d, y + 5 / d, x - 15 / d, END, END);
- _HPlot(y - 7 / d, x - 20 / d, y - 7 / d, x - 15 / d, END, END);
- _HPlot(y + 7 / d, x - 20 / d, y + 7 / d, x - 15 / d, END, END);
-}
-
-static void _DRAWOrc(PARAMS) {
- _HPlot(y, x, y - 15 / d, x, y - 8 / d, x - 8 / d, y - 8 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 23 / d, END, END);
- _HPlot(y - 23 / d, x - 45 / d, y - 15 / d, x - 53 / d, y - 8 / d, x - 53 / d, y - 15 / d, x - 68 / d, y - 8 / d, x - 75 / d, y, x - 75 / d, END, END);
- _HPlot(y, x, y + 15 / d, x, y + 8 / d, x - 8 / d, y + 8 / d, x - 15 / d, y + 15 / d, x - 23 / d, y + 15 / d, x - 15 / d, y + 23 / d, x - 23 / d, END, END);
- _HPlot(y + 23 / d, x - 45 / d, y + 15 / d, x - 53 / d, y + 8 / d, x - 53 / d, y + 15 / d, x - 68 / d, y + 8 / d, x - 75 / d, y, x - 75 / d, END, END);
- _HPlot(y - 15 / d, x - 68 / d, y + 15 / d, x - 68 / d, END, END);
- _HPlot(y - 8 / d, x - 53 / d, y + 8 / d, x - 53 / d, END, END);
- _HPlot(y - 23 / d, x - 15 / d, y + 8 / d, x - 45 / d, END, END);
- _HPlot(y - 8 / d, x - 68 / d, y, x - 60 / d, y + 8 / d, x - 68 / d, y + 8 / d, x - 60 / d, y - 8 / d, x - 60 / d, y - 8 / d, x - 68 / d, END, END);
- _HPlot(y, x - 38 / d, y - 8 / d, x - 38 / d, y + 8 / d, x - 53 / d, y + 8 / d, x - 45 / d, y + 15 / d, x - 45 / d, y, x - 30 / d, y, x - 38 / d, END, END);
-}
-
-static void _DRAWViper(PARAMS) {
- _HPlot(y - 10 / d, x - 15 / d, y - 10 / d, x - 30 / d, y - 15 / d, x - 20 / d, y - 15 / d, x - 15 / d, y - 15 / d, x, y + 15 / d, x, y + 15 / d, x - 15 / d, y - 15 / d, x - 15 / d, END, END);
- _HPlot(y - 15 / d, x - 10 / d, y + 15 / d, x - 10 / d, END, END);
- _HPlot(y - 15 / d, x - 5 / d, y + 15 / d, x - 5 / d, END, END);
- _HPlot(y, x - 15 / d, y - 5 / d, x - 20 / d, y - 5 / d, x - 35 / d, y + 5 / d, x - 35 / d, y + 5 / d, x - 20 / d, y + 10 / d, x - 15 / d, END, END);
- _HPlot(y - 5 / d, x - 20 / d, y + 5 / d, x - 20 / d, END, END);
- _HPlot(y - 5 / d, x - 25 / d, y + 5 / d, x - 25 / d, END, END);
- _HPlot(y - 5 / d, x - 30 / d, y + 5 / d, x - 30 / d, END, END);
- _HPlot(y - 10 / d, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 45 / d, y + 5 / d, x - 45 / d, y + 10 / d, x - 40 / d, y + 10 / d, x - 35 / d, END, END);
- _HPlot(y - 10 / d, x - 40 / d, y, x - 45 / d, y + 10 / d, x - 40 / d, END, END);
- _HPlot(y - 5 / d, x - 40 / d, y + 5 / d, x - 40 / d, y + 15 / d, x - 30 / d, y, x - 40 / d, y - 15 / d, x - 30 / d, y - 5 / d + .5, x - 40 / d, END, END);
-}
-
-static void _DRAWCarrion(PARAMS) {
- /* 79-dst.recty(d) line here */
- _HPlot(y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
- _HPlot(y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
- _HPlot(y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
- _HPlot(y - 15 / d, x - 86 / d, y - 20 / d, x - 83 / d, y - 20 / d, x - 78 / d, y - 30 / d, x - 73 / d, y - 30 / d, x - 68 / d, y - 20 / d, x - 63 / d, END, END);
- _HPlot(y - 10 / d, x - 83 / d, y - 10 / d, x - 58 / d, y, x - 50 / d, END, END);
- _HPlot(y + 10 / d, x - 83 / d, y + 10 / d, x - 78 / d, y + 20 / d, x - 73 / d, y + 20 / d, x - 40 / d, END, END);
- _HPlot(y + 15 / d, x - 85 / d, y + 20 / d, x - 78 / d, y + 30 / d, x - 76 / d, y + 30 / d, x - 60 / d, END, END);
- _HPlot(y, x - 83 / d, y, x - 73 / d, y + 10 / d, x - 68 / d, y + 10 / d, x - 63 / d, y, x - 58 / d, END, END);
-}
-
-static void _DRAWGremlin(PARAMS) {
- _HPlot(y + 5 / d + .5, x - 10 / d, y - 5 / d + .5, x - 10 / d, y, x - 15 / d, y + 10 / d, x - 20 / d, y + 5 / d + .5, x - 15 / d, y + 5 / d + .5, x - 10 / d, END, END);
- _HPlot(y + 7 / d + .5, x - 6 / d, y + 5 / d + .5, x - 3 / d, y - 5 / d + .5, x - 3 / d, y - 7 / d + .5, x - 6 / d, y - 5 / d + .5, x - 10 / d, END, END);
- _HPlot(y + 2 / d + .5, x - 3 / d, y + 5 / d + .5, x, y + 8 / d, x, END, END);
- _HPlot(y - 2 / d + .5, x - 3 / d, y - 5 / d + .5, x, y - 8 / d, x, END, END);
- _HPlot(y + 3 / d + .5, x - 8 / d, END, END);
- _HPlot(y - 3 / d + .5, x - 8 / d, END, END);
- _HPlot(y + 3 / d + .5, x - 5 / d, y - 3 / d + .5, x - 5 / d, END, END);
-}
-
-static void _DRAWMimic(PARAMS) {
- double xx = x;
- _HPlot(139 - 10 / d, xx, 139 - 10 / d, xx - 10 / d, 139 + 10 / d, xx - 10 / d, 139 + 10 / d, xx, 139 - 10 / d, xx, END, END);
- _HPlot(139 - 10 / d, xx - 10 / d, 139 - 5 / d, xx - 15 / d, 139 + 15 / d, xx - 15 / d, 139 + 15 / d, xx - 5 / d, 139 + 10 / d, xx, END, END);
- _HPlot(139 + 10 / d, xx - 10 / d, 139 + 15 / d, xx - 15 / d, END, END);
-}
-
-static void _DRAWDaemon(PARAMS) {
- _HPlot(y - 14 / d, x - 46 / d, y - 12 / d, x - 37 / d, y - 20 / d, x - 32 / d, y - 30 / d, x - 32 / d, y - 22 / d, x - 24 / d, y - 40 / d, x - 17 / d, y - 40 / d, x - 7 / d, y - 38 / d, x - 5 / d, y - 40 / d, x - 3 / d, y - 40 / d, x, END, END);
- _HPlot(y - 36 / d, x, y - 34 / d, x - 2 / d, y - 32 / d, x, y - 28 / d, x, y - 28 / d, x - 3 / d, y - 30 / d, x - 5 / d, y - 28 / d, x - 7 / d, y - 28 / d, x - 15 / d, y, x - 27 / d, END, END);
- _HPlot(y + 14 / d, x - 46 / d, y + 12 / d, x - 37 / d, y + 20 / d, x - 32 / d, y + 30 / d, x - 32 / d, y + 22 / d, x - 24 / d, y + 40 / d, x - 17 / d, y + 40 / d, x - 7 / d, y + 38 / d, x - 5 / d, y + 40 / d, x - 3 / d, y + 40 / d, x, END, END);
- _HPlot(y + 36 / d, x, y + 34 / d, x - 2 / d, y + 32 / d, x, y + 28 / d, x, y + 28 / d, x - 3 / d, y + 30 / d, x - 5 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 15 / d, y, x - 27 / d, END, END);
- _HPlot(y + 6 / d, x - 48 / d, y + 38 / d, x - 41 / d, y + 40 / d, x - 42 / d, y + 18 / d, x - 56 / d, y + 12 / d, x - 56 / d, y + 10 / d, x - 57 / d, y + 8 / d, x - 56 / d, y - 8 / d, x - 56 / d, y - 10 / d, x - 58 / d, y + 14 / d, x - 58 / d, y + 16 / d, x - 59 / d, END, END);
- _HPlot(y + 8 / d, x - 63 / d, y + 6 / d, x - 63 / d, y + 2 / d + .5, x - 70 / d, y + 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 70 / d, y - 6 / d, x - 63 / d, y - 8 / d, x - 63 / d, y - 16 / d, x - 59 / d, y - 14 / d, x - 58 / d, END, END);
- _HPlot(y - 10 / d, x - 57 / d, y - 12 / d, x - 56 / d, y - 18 / d, x - 56 / d, y - 36 / d, x - 47 / d, y - 36 / d, x - 39 / d, y - 28 / d, x - 41 / d, y - 28 / d, x - 46 / d, y - 20 / d, x - 50 / d, y - 18 / d, x - 50 / d, y - 14 / d, x - 46 / d, END, END);
- _HPlot(y - 28 / d, x - 41 / d, y + 30 / d, x - 55 / d, END, END);
- _HPlot(y + 28 / d, x - 58 / d, y + 22 / d, x - 56 / d, y + 22 / d, x - 53 / d, y + 28 / d, x - 52 / d, y + 34 / d, x - 54 / d, END, END);
- _HPlot(y + 20 / d, x - 50 / d, y + 26 / d, x - 47 / d, END, END);
- _HPlot(y + 10 / d, x - 58 / d, y + 10 / d, x - 61 / d, y + 4 / d, x - 58 / d, END, END);
- _HPlot(y - 10 / d, x - 58 / d, y - 10 / d, x - 61 / d, y - 4 / d, x - 58 / d, END, END);
- _HPlot(y + 40 / d, x - 9 / d, y + 50 / d, x - 12 / d, y + 40 / d, x - 7 / d, END, END);
- _HPlot(y - 8 / d, x - 25 / d, y + 6 / d, x - 7 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 9 / d, y + 20 / d, x - 9 / d, y + 6 / d, x - 25 / d, END, END);
-}
-
-static void _DRAWBalrog(PARAMS) {
- _HPlot(y + 6 / d, x - 60 / d, y + 30 / d, x - 90 / d, y + 60 / d, x - 30 / d, y + 60 / d, x - 10 / d, y + 30 / d, x - 40 / d, y + 15 / d, x - 40 / d, END, END);
- _HPlot(y - 6 / d, x - 60 / d, y - 30 / d, x - 90 / d, y - 60 / d, x - 30 / d, y - 60 / d, x - 10 / d, y - 30 / d, x - 40 / d, y - 15 / d, x - 40 / d, END, END);
- _HPlot(y, x - 25 / d, y + 6 / d, x - 25 / d, y + 10 / d, x - 20 / d, y + 12 / d, x - 10 / d, y + 10 / d, x - 6 / d, y + 10 / d, x, y + 14 / d, x, y + 15 / d, x - 5 / d, y + 16 / d, x, y + 20 / d, x, END, END);
- _HPlot(y + 20 / d, x - 6 / d, y + 18 / d, x - 10 / d, y + 18 / d, x - 20 / d, y + 15 / d, x - 30 / d, y + 15 / d, x - 45 / d, y + 40 / d, x - 60 / d, y + 40 / d, x - 70 / d, END, END);
- _HPlot(y + 10 / d, x - 55 / d, y + 6 / d, x - 60 / d, y + 10 / d, x - 74 / d, y + 6 / d, x - 80 / d, y + 4 / d + .5, x - 80 / d, y + 3 / d + .5, x - 82 / d, y + 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
- _HPlot(y, x - 25 / d, y - 6 / d, x - 25 / d, y - 10 / d, x - 20 / d, y - 12 / d, x - 10 / d, y - 10 / d, x - 6 / d, y - 10 / d, x, y - 14 / d, x, y - 15 / d, x - 5 / d, y - 16 / d, x, y - 20 / d, x, END, END);
- _HPlot(y - 20 / d, x - 6 / d, y - 18 / d, x - 10 / d, y - 18 / d, x - 20 / d, y - 15 / d, x - 30 / d, y - 15 / d, x - 45 / d, y - 40 / d, x - 60 / d, y - 40 / d, x - 70 / d, END, END);
- _HPlot(y - 10 / d, x - 55 / d, y - 6 / d, x - 60 / d, y - 10 / d, x - 74 / d, y - 6 / d, x - 80 / d, y - 4 / d + .5, x - 80 / d, y - 3 / d + .5, x - 82 / d, y - 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
- _HPlot(y - 6 / d, x - 25 / d, y, x - 6 / d, y + 10 / d, x, y + 4 / d + .5, x - 8 / d, y + 6 / d, x - 25 / d, END, END);
- _HPlot(y - 40 / d, x - 64 / d, y - 40 / d, x - 90 / d, y - 52 / d, x - 80 / d, y - 52 / d, x - 40 / d, END, END);
- _HPlot(y + 40 / d, x - 86 / d, y + 38 / d, x - 92 / d, y + 42 / d, x - 92 / d, y + 40 / d, x - 86 / d, y + 40 / d, x - 50 / d, END, END);
- _HPlot(y + 4 / d + .5, x - 70 / d, y + 6 / d, x - 74 / d, END, END);
- _HPlot(y - 4 / d + .5, x - 70 / d, y - 6 / d, x - 74 / d, END, END);
- _HPlot(y, x - 64 / d, y, x - 60 / d, END, END);
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/dungeon.cpp b/engines/ultima/ultima0/dungeon.cpp
deleted file mode 100644
index db425d6710a..00000000000
--- a/engines/ultima/ultima0/dungeon.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Dungeon Create and Draw Code */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* Create Dungeon Level */
-/* */
-/************************************************************************/
-
-void DUNGEONCreate(PLAYER *p, DUNGEONMAP *d) {
- d->create(*p);
-}
-
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/globals.cpp b/engines/ultima/ultima0/globals.cpp
deleted file mode 100644
index 42562380db1..00000000000
--- a/engines/ultima/ultima0/globals.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Global Constants : Lists of things, etc. */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/data/data.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* Return name of object */
-/* */
-/************************************************************************/
-
-const char *GLOObjName(int n) {
- return OBJECT_INFO[n].Name;
-}
-
-void GLOGetInfo(int n, int *pDamage, int *pCost, int *pKey) {
-#if 0
- if (pDamage != nullptr) *pDamage = OBJECT_INFO[n].MaxDamage;
- if (pCost != nullptr) *pCost = OBJECT_INFO[n].Cost;
- if (pKey != nullptr) *pKey = OBJECT_INFO[n].Key;
-#endif
-}
-
-/************************************************************************/
-/* */
-/* Return name of attribute */
-/* */
-/************************************************************************/
-
-const char *GLOAttribName(int n) {
- return ATTRIB_NAMES[n];
-}
-
-/************************************************************************/
-/* */
-/* Return name of class */
-/* */
-/************************************************************************/
-
-const char *GLOClassName(char c) {
- return (c == 'F') ? "Fighter" : "Mage";
-}
-
-const char *GLOMonsterName(int n) {
- return MONSTER_INFO[n - 1].Name;
-}
-
-int GLOMonsterLevel(int n) {
- return MONSTER_INFO[n - 1].Level;
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/hardware.cpp b/engines/ultima/ultima0/hardware.cpp
deleted file mode 100644
index 9afbdf13354..00000000000
--- a/engines/ultima/ultima0/hardware.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* System independent routines */
-/* */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h" /* Our prototypes */
-#include "ultima/ultima0/sdw.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-using namespace SDLWrapper;
-
-int CharHeight = 16; /* Height of one character */
-int CharWidth = 16; /* Width of one character */
-int TextLines = 22; /* Number of chars in visible line */
-int TextLeft, xc, yc;
-int TextOrigin;
-int Red, Green, Blue;
-Surface *MainSurface;
-
-/************************************************************************/
-/* */
-/* Initialise all internal graphics routines */
-/* */
-/************************************************************************/
-
-void HWInitialise(void) {
- MainSurface = new Surface(DEFAULT_SCX, DEFAULT_SCY);
- TextLeft = DEFAULT_SCX - CharWidth * TextLines;
- TextOrigin = 224;
- xc = TextLeft; yc = TextOrigin;
-}
-
-/************************************************************************/
-/* */
-/* Refresh Status Area */
-/* */
-/************************************************************************/
-
-void HWStatus(double Food, int HP, int Gold) {
- char Temp[32];
- MainSurface->SetColour(0, 0, 0);
- MainSurface->FillRect(TextLeft, 0, DEFAULT_SCX, TextOrigin - 1);
- MainSurface->SetColour(0, 255, 255);
- Common::sprintf_s(Temp, "%.1f", Food);
- MainSurface->String(TextLeft + 16, 32, TextLeft + 16 + 32 * strlen(Temp), 32 + 32, Temp);
- Common::sprintf_s(Temp, "%u", HP);
- MainSurface->String(TextLeft + 16, 96, TextLeft + 16 + 32 * strlen(Temp), 96 + 32, Temp);
- Common::sprintf_s(Temp, "%u", Gold);
- MainSurface->String(TextLeft + 16, 160, TextLeft + 16 + 32 * strlen(Temp), 160 + 32, Temp);
-
- MainSurface->SetColour(255, 0, 0);
- MainSurface->String(TextLeft, 8, TextLeft + 64, 24, "Food");
- MainSurface->String(TextLeft, 72, TextLeft + 16 * 9, 88, "Hit Points");
- MainSurface->String(TextLeft, 136, TextLeft + 64, 152, "Gold");
-
- // /* char Temp[32];
- // setfillstyle(SOLID_FILL,BLACK); /* Set up colours */
- // setcolor(LIGHTCYAN);
- // settextstyle(SMALL_FONT,HORIZ_DIR,6);
- // bar(xText+110,22,xMax-4,yScroll-4); /* Erase old status values */
- // Common::sprintf_s(Temp,"%.1f",Food); /* Fill in the new ones */
- // outtextxy(xText+110,22,Temp);
- // Common::sprintf_s(Temp,"%u",HP);
- // outtextxy(xText+110,37,Temp);
- // Common::sprintf_s(Temp,"%u",Gold);
- // outtextxy(xText+110,52,Temp);
- // HWColour(CurrentColour); /* Set the current colour */*/
-}
-
-/************************************************************************/
-/* */
-/* Terminate all internal graphics routines */
-/* */
-/************************************************************************/
-
-void HWTerminate(void) {
-}
-
-/************************************************************************/
-/* */
-/* Output text to the scrolling text area */
-/* */
-/************************************************************************/
-
-void HWChar(int ch) {
- Rect src(TextLeft, TextOrigin + CharHeight, DEFAULT_SCX, DEFAULT_SCY);
- if (ch >= ' ')
- {
- MainSurface->SetColour(0, 255, 0);
- MainSurface->Char(xc, yc, xc + CharWidth - 1, yc + CharHeight - 1, ch);
- xc = xc + CharWidth;
- }
- if (xc >= DEFAULT_SCX || ch == 13)
- {
- xc = TextLeft;
- yc = yc + CharHeight;
- if (yc + CharHeight >= DEFAULT_SCY)
- {
- MainSurface->Copy(*MainSurface, src, TextLeft, TextOrigin);
- MainSurface->SetColour(0, 0, 0);
- MainSurface->FillRect(TextLeft, yc, DEFAULT_SCX, DEFAULT_SCY);
- yc = yc - CharHeight;
- }
- }
-}
-
-/************************************************************************/
-/* */
-/* Select the current drawing colour, should use RGB() */
-/* */
-/************************************************************************/
-
-void HWColour(int c) {
- Red = (c & 4) ? 255 : 0;
- Green = (c & 2) ? 255 : 0;
- Blue = (c & 1) ? 255 : 0;
-}
-
-/************************************************************************/
-/* */
-/* Draw line in current colour */
-/* */
-/************************************************************************/
-
-void HWLine(int x1, int y1, int x2, int y2) {
- x1 = x1 * TextLeft / 1280; y1 = DEFAULT_SCY - y1 * DEFAULT_SCY / 1024;
- x2 = x2 * TextLeft / 1280; y2 = DEFAULT_SCY - y2 * DEFAULT_SCY / 1024;
- MainSurface->SetColour(Red, Green, Blue);
- MainSurface->Line(x1, y1, x2, y2);
-}
-
-/***********************************************************************/
-/* */
-/* Read an upper case ASCII key, or Carriage Return (13) */
-/* */
-/************************************************************************/
-
-int HWGetKey(void) {
- int n;
- MainSurface->Copy();
- MainSurface->Flip();
- do
- {
- n = GetKey();
- if (n == 273) n = 'N';
- if (n == 274) n = 'S';
- if (n == 275) n = 'E';
- if (n == 276) n = 'W';
-
- } while (n < ' ' || n > 127);
- return toupper(n);
-}
-
-
-/************************************************************************/
-/* */
-/* Clear the graphics area */
-/* */
-/************************************************************************/
-
-void HWClear(void) {
- MainSurface->SetColour(0, 0, 0);
- MainSurface->FillRect(0, 0, TextLeft - 1, DEFAULT_SCY);
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/main.cpp b/engines/ultima/ultima0/main.cpp
deleted file mode 100644
index 39af768cde9..00000000000
--- a/engines/ultima/ultima0/main.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* M A I N P R O G R A M */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-/************************************************************************/
-/* Outstanding work :- LOAD AND SAVE, FIX THE DOOR PROBLEM.
-************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-PLAYER Player; /* Player data */
-WORLDMAP World; /* Current world map */
-DUNGEONMAP Dungeon; /* Current dungeon map */
-
-static void _MAINIntro(void);
-static void _MAINDisplay(WORLDMAP *, PLAYER *, DUNGEONMAP *);
-static void _MAINCommand(int, WORLDMAP *, PLAYER *, DUNGEONMAP *);
-
-/************************************************************************/
-/* */
-/* Main Program */
-/* */
-/************************************************************************/
-
-void MAINStart(void) {
- int c;
- RECT r1, r2;
- HWInitialise(); /* Initialise the game */
- HWClear(); /* Clear the graphic display */
- HWStatus(0, 0, 0); /* Zero the status */
- _MAINIntro(); /* Print startup information */
- MAINSetup(); /* Set up the player */
-
- do
- {
- _MAINDisplay(&World, &Player, /* Redraw the main display */
- &Dungeon);
- DRAWText("]"); c = HWGetKey(); /* Read the next command */
- _MAINCommand(c, &World, &Player, /* Do it */
- &Dungeon);
- if (Player.Attr[AT_HP] <= 0) /* Died.... */
- DEADCode(&Player);
- if (c == 'Q') /* Confirm exit */
- {
- DRAWText("Are you sure ?\n");
- if (DEADGetYesNo() == 0) c = '\0';
- }
- } while (c != 'Q' && Player.Attr[AT_HP] > 0);
- HWTerminate();
-}
-
-/************************************************************************/
-/* */
-/* Set everything up */
-/* */
-/************************************************************************/
-
-void MAINSetup(void) {
- PLAYERInit(&Player); /* Initialise the player */
- PLAYERCharacter(&Player); /* Character information */
- WORLDCreate(&Player, &World); /* Create the over world */
- WORLDDraw(&Player, &World, 0); /* Draw the player map */
- TOWNEnter(&World, &Player); /* Visit the shops */
-}
-
-/************************************************************************/
-/* */
-/* Execute a command */
-/* */
-/************************************************************************/
-
-static void _MAINCommand(int c, WORLDMAP *w, PLAYER *p, DUNGEONMAP *d) {
- if (c == 'A' && p->Level == 0) /* Only attack in dungeon */
- c = '\0';
- switch (c)
- {
- case 'A':
- DRAWText("Attack.\n");
- ATTACKMonster(p, d);
- break;
-
- case 'N':
- DRAWText(p->Level == 0 ? "Go North.\n" : "Move.\n");
- MOVEMove(c, w, p, d, 0, -1);
- break;
- case 'S':
- DRAWText(p->Level == 0 ? "Go South.\n" : "Turn Around.\n");
- MOVEMove(c, w, p, d, 0, 1);
- break;
- case 'E':
- DRAWText(p->Level == 0 ? "Go East.\n" : "Turn Right.\n");
- MOVEMove(c, w, p, d, 1, 0);
- break;
- case 'W':
- DRAWText(p->Level == 0 ? "Go West.\n" : "Turn Left.\n");
- MOVEMove(c, w, p, d, -1, 0);
- break;
- case 'I':
- DRAWText("Inventory.\n");
- PLAYERInv(&Player);
- break;
- case 'Q':
- DRAWText("Quit.\n");
- break;
- case 'X':
- MOVEEnterExit(w, p, d);
- break;
- default:
- DRAWText("Huh???\n");
- break;
- }
-}
-
-/************************************************************************/
-/* */
-/* Introduction text */
-/* */
-/************************************************************************/
-
-static void _MAINIntro(void) {
- DRAWText("Aklabeth by P Robson\n\n");
- DRAWText("From the Apple II\n");
- DRAWText("game by R Garriott\n\n");
- DRAWText("Press any key.\n\n");
- HWGetKey();
-}
-
-/************************************************************************/
-/* */
-/* Do we support improved features ? */
-/* */
-/************************************************************************/
-
-int MAINSuper(void) {
- return 1;
-}
-
-/************************************************************************/
-/* */
-/* Redraw the main display */
-/* */
-/************************************************************************/
-
-static void _MAINDisplay(WORLDMAP *w, PLAYER *p, DUNGEONMAP *d) {
- HWStatus(p->Object[OB_FOOD], /* Refresh the status bar */
- p->Attr[AT_HP], p->Attr[AT_GOLD]);
- HWClear(); /* Clear the screen */
- if (p->Level == 0) /* Above ground, draw it */
- WORLDDraw(p, w, 0);
- else
- DDRAWDraw(p, d);
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/monst.cpp b/engines/ultima/ultima0/monst.cpp
deleted file mode 100644
index 067648cf53c..00000000000
--- a/engines/ultima/ultima0/monst.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Attacking Monsters Code */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-static int attack(MONSTER *, PLAYER *);
-static int steal(MONSTER *, PLAYER *);
-static void move(MONSTER *, PLAYER *, DUNGEONMAP *);
-static int canMoveTo(DUNGEONMAP *, int, int);
-
-/************************************************************************/
-/* */
-/* Check Monsters Attacking */
-/* */
-/************************************************************************/
-
-void MONSTAttack(PLAYER *p, DUNGEONMAP *d) {
- int i, Attacked;
- double Dist;
- MONSTER *m;
- for (i = 0; i < d->MonstCount; i++) /* Go through all monsters */
- {
- m = &(d->Monster[i]); /* Pointer to monster */
- Dist = pow(m->Loc.x - p->Dungeon.x, 2); /* Calculate Distance */
- Dist = Dist + pow(m->Loc.y - p->Dungeon.y, 2);
- Dist = sqrt(Dist);
- if (m->Alive != 0) /* If alive */
- {
- Attacked = 0;
- if (Dist < 1.3) /* If within range */
- Attacked = attack(m, p);
- if (Attacked == 0) /* If didn't attack, then move */
- {
- if (m->Type != MN_MIMIC || /* Mimics only if near enough */
- Dist >= 3.0)
- move(m, p, d);
- if (m->Strength < /* Recovers if didn't attack */
- p->Level * p->Skill)
- m->Strength = m->Strength + p->Level;
- }
- }
- }
-}
-
-/************************************************************************/
-/* */
-/* Monster Attacks */
-/* */
-/************************************************************************/
-
-static int attack(MONSTER *m, PLAYER *p) {
- int n;
-
- if (m->Type == MN_GREMLIN || /* Special case for Gremlin/Thief */
- m->Type == MN_THIEF)
- if (RND() > 0.5) /* Half the time */
- return steal(m, p);
-
- DRAWText("You are being attacked by a %s !!!.\n",
- GLOMonsterName(m->Type));
-
- n = urand() % 20; /* Calculate hit chance */
- if (p->Object[OB_SHIELD] > 0) n--;
- n = n - p->Attr[AT_STAMINA];
- n = n + m->Type + p->Level;
- if (n < 0) /* Missed ! */
- DRAWText("Missed !\n");
- else /* Hit ! */
- {
- n = urand() % (m->Type); /* Calculate damage done. */
- n = n + p->Level;
- p->Attr[AT_HP] -= n; /* Adjust hit points */
- DRAWText("Hit !!!\n");
- }
- return 1;
-}
-
-/************************************************************************/
-/* */
-/* Monster Moves */
-/* */
-/************************************************************************/
-
-static void move(MONSTER *m, PLAYER *p, DUNGEONMAP *d) {
- int x, y, xi, yi;
-
- xi = yi = 0; /* Calculate direction */
- if (p->Dungeon.x != m->Loc.x)
- xi = (p->Dungeon.x > m->Loc.x) ? 1 : -1;
- if (p->Dungeon.y != m->Loc.y)
- yi = (p->Dungeon.y > m->Loc.y) ? 1 : -1;
-
- /* Running away */
- if (m->Strength < p->Level * p->Skill)
- {
- xi = -xi; yi = -yi;
- }
- x = m->Loc.x; y = m->Loc.y; /* Get position */
-
- if (abs(xi) > abs(yi)) /* Check move okay */
- {
- if (canMoveTo(d, x + xi, yi)) yi = 0;
- else if (canMoveTo(d, x, y + yi)) xi = 0;
- } else
- {
- if (canMoveTo(d, x, y + yi)) xi = 0;
- else if (canMoveTo(d, x + xi, yi)) yi = 0;
- }
- if (xi == 0 && yi == 0) return; /* No move */
- x = x + xi; y = y + yi; /* Work out new position */
- if (canMoveTo(d, x, y) == 0) /* Fail if can't move there */
- return;
- if (x == p->Dungeon.x && /* Can't move onto us */
- y == p->Dungeon.y) return;
- m->Loc.x = x; m->Loc.y = y; /* Move to new position */
-}
-
-/************************************************************************/
-/* */
-/* Can monster move to a square */
-/* */
-/************************************************************************/
-
-static int canMoveTo(DUNGEONMAP *d, int x, int y) {
- COORD c;
- int t = d->Map[x][y]; /* See what's there */
- if (!ISWALKTHRU(t)) return 0; /* Can't walk through walls */
- c.x = x; c.y = y; /* Set up coord structure */
- return DDRAWFindMonster(d, &c) < 0; /* True if no monster here */
-}
-
-/************************************************************************/
-/* */
-/* Monster Stealing */
-/* */
-/************************************************************************/
-
-static int steal(MONSTER *m, PLAYER *p) {
- int n;
- const char *s1, *s2;
-
- if (m->Type == MN_GREMLIN) /* Gremlin */
- {
- p->Object[OB_FOOD] = /* HALVES the food.... aargh */
- floor(p->Object[OB_FOOD]) / 2.0;
- DRAWText("A Gremlin stole some food.\n");
- }
-
- if (m->Type == MN_THIEF) /* Thief */
- {
- do /* Figure out what stolen */
- n = urand() % (p->Objects);
- while (p->Object[n] == 0);
- p->Object[n]--; /* Stole one */
- s2 = GLOObjName(n); s1 = "a";
- if (strchr("aeiou", tolower(*s2))) s1 = "an";
- if (n == 0) s1 = "some";
- DRAWText("A Thief stole %s %s.\n", s1, s2);
- }
- return 1;
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/move.cpp b/engines/ultima/ultima0/move.cpp
deleted file mode 100644
index a1d71e1f454..00000000000
--- a/engines/ultima/ultima0/move.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Moving and Entry/Exit Code */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* Movement code */
-/* */
-/************************************************************************/
-
-void MOVEMove(int c, WORLDMAP *w, PLAYER *p, DUNGEONMAP *d, int xi, int yi) {
- int z, x1, y1, Moved = 0;
- const char *s1, *s2;
- double n;
- COORD New;
- if (p->Level == 0) /* If above ground in world map */
- {
- x1 = p->World.x + xi; /* Calculate new position */
- y1 = p->World.y + yi;
- if (WORLDRead(w, x1, y1) == WT_MOUNTAIN)
- DRAWText("You can't pass\nthe mountains.\n");
- else
- {
- p->World.x = x1; /* Move */
- p->World.y = y1;
- }
- } else /* If in the dungeon */
- {
- switch (c)
- {
- case 'N': x1 = p->Dungeon.x + p->DungDir.x;
- y1 = p->Dungeon.y + p->DungDir.y;
- New.x = x1; New.y = y1;
- if (ISWALKTHRU(d->Map[x1][y1]) &&
- DDRAWFindMonster(d, &New) < 0)
- {
- Moved = 1;
- p->Dungeon = New;
- }
- break;
-
- case 'E': MOVERotLeft(&(p->DungDir));
- MOVERotLeft(&(p->DungDir));
- MOVERotLeft(&(p->DungDir));
- break;
- case 'W': MOVERotLeft(&(p->DungDir));
- break;
- case 'S': MOVERotLeft(&(p->DungDir));
- MOVERotLeft(&(p->DungDir));
- break;
- }
-
- if (Moved != 0)
- {
- n = d->Map[p->Dungeon.x] /* What's here ? */
- [p->Dungeon.y];
- if (n == DT_PIT) /* Fell in a pit */
- {
- p->Level++; /* Down a level */
- DRAWText("Aaarrrgghhh! A Trap !\n");
- p->Attr[AT_HP] -= /* It hurts ! */
- (3 + urand() % (3 * p->Level));
- DRAWText("Falling to Level %d.\n", p->Level);
- DUNGEONCreate(p, d); /* Create the new level */
- }
- if (n == DT_GOLD) /* Gold here */
- {
- d->Map[p->Dungeon.x] /* Remove the gold */
- [p->Dungeon.y] = 0;
- DRAWText("Gold !!!!!\n");
- z = (urand() % (5 * p->Level)) /* Calculate amount */
- + p->Level;
- DRAWText("%d pieces of eight ", z);
- p->Attr[AT_GOLD] += z; /* Add to total */
- if (z > 0) /* Object ? */
- {
- z = urand() % (p->Objects);/* Decide which object */
- s2 = GLOObjName(z); /* Get the name */
- s1 = "a"; /* Decide a,an or some */
- if (strchr("aeiou", tolower(*s2))) s1 = "an";
- if (z == 0) s1 = "some";
- DRAWText("and %s %s.\n", s1, s2);
- p->Object[z]++; /* Bump the total */
- }
- }
- }
- MONSTAttack(p, d); /* Monster attacks ? */
- }
- n = p->Object[OB_FOOD];
- p->Object[OB_FOOD] = p->Object[OB_FOOD] /* Consume some food */
- - ((p->Level > 0) ? 0.1 : 1);
- p->Object[OB_FOOD] = /* Make it integer */
- floor(p->Object[OB_FOOD] * 10) / 10;
- if (p->Object[OB_FOOD] <= 0) /* Starved us ? */
- {
- DRAWText("You have starved...\n");
- p->Attr[AT_HP] = 0; /* Dead */
- }
-}
-
-
-/************************************************************************/
-/* */
-/* Handle entry,exit */
-/* */
-/************************************************************************/
-
-void MOVEEnterExit(WORLDMAP *w, PLAYER *p, DUNGEONMAP *d) {
- int t, Done = 0;
- if (p->Level == 0) /* Entry/Exit on world map */
- {
- t = WORLDRead(w, p->World.x, /* Read tile */
- p->World.y);
- Done = 1;
- switch (t)
- {
- case WT_TOWN: /* Enter the town */
- DRAWText("Enter Town.\n");
- TOWNEnter(w, p);
- break;
- case WT_DUNGEON: /* Enter the dungeon */
- DRAWText("Enter Dungeon.\n");
- p->Level = 1; /* Go to level 1 */
- p->Dungeon.x = 1; /* Set initial position */
- p->Dungeon.y = 1;
- p->DungDir.x = 1; /* And direction */
- p->DungDir.y = 0;
- DUNGEONCreate(p, d); /* Create the dungeon map */
- break;
- case WT_BRITISH: /* Enter the castle */
- DRAWText("Enter Castle.\n");
- BRITISHEnter(w, p);
- break;
- default: /* Nope.... */
- Done = 0; break;
- }
- } else /* Entry/Exit in dungeons */
- {
- t = d->Map[p->Dungeon.x] /* Identify what's there */
- [p->Dungeon.y];
- if (t == DT_LADDERUP) /* Climbing up a ladder */
- {
- p->Level--;
- Done = 1;
- if (p->Level == 0)
- {
- DRAWText("Leave the Dungeon.\n");
- DRAWText("Thou has gained %d hit points.\n", p->HPGain);
- p->Attr[AT_HP] += p->HPGain;
- p->HPGain = 0;
- } else
- DRAWText("Go up to Level %d.\n", p->Level);
- }
- if (t == DT_LADDERDN) /* Climbing down a ladder */
- {
- p->Level++;
- Done = 1;
- DRAWText("Go down to Level %d.\n", p->Level);
- }
- if (Done != 0 && p->Level > 0) /* New Dungeon Map Required */
- DUNGEONCreate(p, d);
- }
- if (Done == 0) /* Can't do it */
- DRAWText("Huh???\n");
-}
-
-/************************************************************************/
-/* */
-/* Rotate a direction left */
-/* */
-/************************************************************************/
-
-void MOVERotLeft(COORD *Dir) {
- int t;
- if (Dir->y == 0) Dir->x = -Dir->x;
- t = Dir->x;
- Dir->x = Dir->y;
- Dir->y = t;
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/player.cpp b/engines/ultima/ultima0/player.cpp
deleted file mode 100644
index 947e9fc6b83..00000000000
--- a/engines/ultima/ultima0/player.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Manage Player Structures */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* Initialise the player character */
-/* */
-/************************************************************************/
-
-void PLAYERInit(PLAYER *p) {
- p->init();
-}
-
-/************************************************************************/
-/* */
-/* Player Inventory */
-/* */
-/************************************************************************/
-
-void PLAYERInv(PLAYER *p) {
- int i;
- HWStatus(p->Object[OB_FOOD], /* Refresh the status */
- p->Attr[AT_HP], p->Attr[AT_GOLD]);
- if (p->Name[0] != '\0') /* Display the name */
- DRAWText("\n%s the %s.\n\n", p->Name, GLOClassName(p->Class));
- else
- DRAWText("\nA %s.\n\n", GLOClassName(p->Class));
- for (i = 0; i < p->Attributes; i++) /* Display the attributes */
- if (i != AT_HP && i != AT_GOLD)
- DRAWText("%s: %d\n", GLOAttribName(i), p->Attr[i]);
- DRAWText("\n");
- for (i = 0; i < p->Objects; i++) /* Display the objects */
- if (i != OB_FOOD)
- DRAWText("%s: %u\n", GLOObjName(i), (int)p->Object[i]);
- DRAWText("\n");
-}
-
-/************************************************************************/
-/* */
-/* Create a player character */
-/* */
-/************************************************************************/
-
-void PLAYERCharacter(PLAYER *p) {
- int i;
- DRAWText("Select skill level.\n");
- while (i = HWGetKey(), !Common::isDigit(i)) {
- };
- i = i & 15; if (i == 0) i = 10;
- DRAWText("Level %d.\n\n", i);
-
- DRAWText("Hit your lucky key.\n\n");
- p->LuckyNumber = HWGetKey();
- DRAWText("Game Number %d.\n\n", p->LuckyNumber);
-
- do
- {
- for (i = 0; i < p->Attributes; i++)
- {
- p->Attr[i] = floor(sqrt(RND()) * 21 + 4);
- DRAWText("%s : %d.\n", GLOAttribName(i), p->Attr[i]);
- }
- DRAWText("\nWilt thou play with\nthese qualities ?\n\n");
- } while (DEADGetYesNo() == 0);
- DRAWText("And shalt thou be a\nFighter or a Mage ?\n\n");
- do
- {
- p->Class = HWGetKey();
- } while (p->Class != 'M' && p->Class != 'F');
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/sdw.cpp b/engines/ultima/ultima0/sdw.cpp
deleted file mode 100644
index d12398bfc9a..00000000000
--- a/engines/ultima/ultima0/sdw.cpp
+++ /dev/null
@@ -1,1147 +0,0 @@
-/* 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 "common/events.h"
-#include "common/file.h"
-#include "audio/decoders/wave.h"
-#include "image/bmp.h"
-#include "graphics/screen.h"
-#include "ultima/ultima0/sdw.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-using namespace SDLWrapper;
-
-Graphics::Screen *Display; // The Display screen
-int GameSpeed = 120; // Scales the system clock.
-constexpr bool Joystick = true; // Do we have a joystick or do we mimic it ?
-//static SDL_Joystick *JoyPtr; // Pointer to a joystick object
-//static SDL_AudioSpec AudioFmt; // Audio system specification
-static AudioObject *SoundList[MAXSOUND]; // Audio objects in use.
-
-static uint32 _GetPixel(Graphics::ManagedSurface *Surface, int x, int y);
-
-static void SoundInitialise(void);
-static void SoundTerminate(void);
-static void SoundCallBack(void *Data, uint8 *Stream, int Length);
-
-// **************************************************************************************************************************
-//
-// Called when ERROR or ASSERT failes
-//
-// **************************************************************************************************************************
-
-void SDLWrapper::FatalError(int Line, const char *File) {
- error("Fatal Error at line %d of %s", Line, File);
-}
-
-// **************************************************************************************************************************
-//
-// Set the game running speed, percent of normal
-//
-// **************************************************************************************************************************
-
-void SDLWrapper::SetSpeed(int n) {
- GameSpeed = n;
-}
-
-
-// **************************************************************************************************************************
-//
-// Constructor for a surface
-//
-// **************************************************************************************************************************
-
-Surface::Surface(int x, int y, int Trans, int UseDisplay, const char *File) {
-// unsigned int Flags;
-
- IsTransparent = Trans; // Save transparency flag
- IsDisplay = UseDisplay; // Save physical display flag
- TransColour = 0;
- SetScale(); // Reset scale and origin
- SetOrigin();
-#if 0
- Flags = SDL_SWSURFACE; // Default flags
- if (IsTransparent) // If transparent.
- Flags |= SDL_SRCCOLORKEY;
-#endif
-
- if (File == NULL) // Not loading a bitmap
- {
- if (x == 0) x = Display->w; // if x = y = 0 use whole screen
- if (y == 0) y = Display->h;
- xSize = x; ySize = y; // Store width and height
-
- if (IsDisplay == 0)
- {
- sSurface = new Graphics::ManagedSurface(x, y);
- TransColour = 254; // A horrible transparency colour
-// SDL_MapRGB(((SDL_Surface *)sSurface)->format, 220, 20, 130);
- SetColour(); // Set the colour to the default (normally black)
- FillRect(); // Erase the surface
- } else {
- // Use the display surface
- sSurface = Display;
- SetColour();
- }
- } else {
- // Loading a bitmp
- Common::File f;
- Image::BitmapDecoder decoder;
-
- if (!f.open(File) || !decoder.loadStream(f))
- SDWERROR();
-
- sSurface = new Graphics::ManagedSurface();
- sSurface->copyFrom(*decoder.getSurface());
-
- xSize = sSurface->w;
- ySize = sSurface->h;
-
- if (IsTransparent) // The colour is the top left pixel if transparent
- TransColour = _GetPixel(sSurface, 0, 0);
-
- SetColour();
- }
-}
-
-// **************************************************************************************************************************
-//
-// Destructor for a surface
-//
-// **************************************************************************************************************************
-
-
-Surface::~Surface() {
- if (!IsDisplay)
- delete sSurface;
- sSurface = nullptr;
-}
-
-// **************************************************************************************************************************
-//
-// Translate Points
-//
-// **************************************************************************************************************************
-
-void Surface::PointProcess(int &x, int &y) {
- x = ((x * xScale) >> 8) + xOrigin;
-
- y = ((y * yScale) >> 8) + yOrigin;
-}
-
-// **************************************************************************************************************************
-//
-// Set drawing colour
-//
-// **************************************************************************************************************************
-
-void Surface::SetColour(int r, int g, int b) {
- Colour = sSurface->format.RGBToColor(r, g, b);
-#if 0
- if (r >= 0 && g >= 0 && b >= 0) // Setting a colour normally
- Colour = SDL_MapRGB(((SDL_Surface *)sSurface)->format, r, g, b);
- else
- { // Default behaviour
- if (IsTransparent) // Transparency, or not.
- {
- Colour = TransColour;
- SDL_SetColorKey((SDL_Surface *)sSurface, SDL_SRCCOLORKEY, (uint32)TransColour);
- } else
- SetColour(0, 0, 0);
- }
-#endif
-}
-
-// **************************************************************************************************************************
-//
-// Single Pixel Plot
-//
-// **************************************************************************************************************************
-
-void Surface::Plot(int x1, int y1) {
- SDL_Rect rc;
- PointProcess(x1, y1);
- SortAndValidate(x1, y1, x1, y1); // Doesn't Sort the 2 corners - still validates point
- rc.x = x1; rc.y = y1; // Copy into the SDL Rectangle
- rc.w = rc.h = 1;
- SDL_FillRect((SDL_Surface *)sSurface, &rc, (uint32)Colour);
-}
-
-// **************************************************************************************************************************
-//
-// Fill a solid rectangle
-//
-// **************************************************************************************************************************
-
-void Surface::FillRect(int x1, int y1, int x2, int y2) {
- SDL_Rect rc;
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
- rc.x = x1; rc.y = y1; // Copy into the SDL Rectangle
- rc.w = x2 - x1 + 1; rc.h = y2 - y1 + 1;
- SDL_FillRect((SDL_Surface *)sSurface, &rc, (uint32)Colour);
-}
-
-// **************************************************************************************************************************
-//
-// Frame a rectangle
-//
-// **************************************************************************************************************************
-
-void Surface::FrameRect(int x1, int y1, int x2, int y2) {
- SDL_Rect rc, rc2;
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
- rc.x = x1; rc.y = y1; // Copy into the SDL Rectangle
- rc.w = x2 - x1 + 1; rc.h = y2 - y1 + 1;
-
- rc2 = rc; rc2.h = 1; // Draw the four frame edges
- SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
- rc2.y = rc.y + rc.h - 1;
- SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
- rc2 = rc; rc2.w = 1;
- SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
- rc2.x = rc.x + rc.w - 1;
- SDL_FillRect((SDL_Surface *)sSurface, &rc2, (uint32)Colour);
-}
-
-
-// **************************************************************************************************************************
-//
-// Sort coordinates , x and y into order. Check they are in range
-//
-// **************************************************************************************************************************
-
-void Surface::SortAndValidate(int &x1, int &y1, int &x2, int &y2) {
- int t;
- if (x1 > x2) {
- t = x1; x1 = x2; x2 = t;
- }
- if (y1 > y2) {
- t = y1; y1 = y2; y2 = t;
- }
- // SDWASSERT(x1 >= 0 && x1 < xSize);
- // SDWASSERT(y1 >= 0 && y1 < ySize);
- // SDWASSERT(x2 >= 0 && x2 < xSize);
- // SDWASSERT(y2 >= 0 && y2 < ySize);
-}
-
-// **************************************************************************************************************************
-//
-// Copying from one surface to another : Copying is ALWAYS Physical Coordinates
-//
-// (1) From this to a target, given a source rectangle and optional position
-// (2) From this to the display, given a source rectangle and optional position
-
-// (3) From this to the display, whole surface, optional position
-// (4) From this to a target, whole surface, optional position
-//
-// **************************************************************************************************************************
-
-static void _SurfaceCopier(SDL_Surface *Src, SDL_Surface *Tgt,
- int left, int top, int right, int bottom,
- int x, int y);
-
-void Surface::Copy(Surface &Target, Rect &SrcRect, int x, int y) {
- _SurfaceCopier((SDL_Surface *)sSurface,
- (SDL_Surface *)Target.sSurface,
- SrcRect.Left, SrcRect.Top, SrcRect.Right, SrcRect.Bottom, x, y);
-}
-
-void Surface::Copy(Rect &SrcRect, int x, int y) {
- _SurfaceCopier((SDL_Surface *)sSurface,
-
-
- (SDL_Surface *)Display,
- SrcRect.Left, SrcRect.Top, SrcRect.Right, SrcRect.Bottom, x, y);
-}
-
-void Surface::Copy(int x, int y) {
- _SurfaceCopier((SDL_Surface *)sSurface,
- (SDL_Surface *)Display,
- 0, 0, xSize - 1, ySize - 1, x, y);
-}
-
-void Surface::Copy(Surface &Target, int x, int y) {
- _SurfaceCopier((SDL_Surface *)sSurface,
- (SDL_Surface *)Target.sSurface,
- 0, 0, xSize - 1, ySize - 1, x, y);
-}
-
-static void _SurfaceCopier(SDL_Surface *Src, SDL_Surface *Tgt,
-
-
- int left, int top, int right, int bottom,
- int x, int y) {
- SDL_Rect rc, rc2;
- rc.x = left; rc.y = top; rc.w = right - left + 1; rc.h = bottom - top + 1;
- rc2.x = x; rc2.y = y;
- SDL_BlitSurface(Src, &rc, Tgt, &rc2);
-}
-
-
-
-// **************************************************************************************************************************
-//
-// These routines draw filled and outline ellipses
-
-//
-// **************************************************************************************************************************
-
-static void _EllipsePoint(SDL_Surface *s, // This one draws two points or a line per vertical slice of ellipse
- int x, int y, int w, uint32 c, int Solid) {
- SDL_Rect rc;
- if (Solid)
- {
- rc.x = x; rc.y = y; rc.w = w; rc.h = 1;
- SDL_FillRect(s, &rc, c);
- } else
- {
-
- rc.x = x; rc.y = y; rc.w = 1; rc.h = 1;
- SDL_FillRect(s, &rc, c);
- rc.x = x + w;
- SDL_FillRect(s, &rc, c);
- }
-}
-
-static void _DrawEllipse(SDL_Surface *s, // A Bresenham Algorithm I found originated by gerd.platl at siemens.at
- int mx, int my, int a, int b, uint32 c, int Solid) {
- int x, mx1, mx2, my1, my2;
- int aq, bq, dx, dy, r, rx, ry;
-
- _EllipsePoint(s, mx - a, my, a * 2, c, Solid);
-
- mx1 = mx - a; my1 = my;
- mx2 = mx + a; my2 = my;
-
-
- aq = a * a; bq = b * b;
-
- dx = aq * 2; dy = bq * 2;
- r = a * bq;
- rx = r * 2;
- ry = 0;
- x = a;
-
- while (x > 0)
- {
- if (r > 0)
-
- {
- my1++; my2--;
- ry = ry + dx;
- r = r - ry;
- }
- if (r <= 0)
- {
- x--;
- mx1++; mx2--;
- rx = rx - dy;
- r = r + rx;
-
- }
-
- _EllipsePoint(s, mx1, my1, mx2 - mx1, c, Solid);
- _EllipsePoint(s, mx1, my2, mx2 - mx1, c, Solid);
- }
-}
-
-void Surface::FillEllipse(int x1, int y1, int x2, int y2) {
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
- _DrawEllipse((SDL_Surface *)sSurface, // Draw filled ellipse
- (x1 + x2) / 2, (y1 + y2) / 2,
- (x2 - x1) / 2, (y2 - y1) / 2,
- (uint32)Colour, 1);
-}
-
-void Surface::FrameEllipse(int x1, int y1, int x2, int y2) {
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
- _DrawEllipse((SDL_Surface *)sSurface, // Draw outline ellipse
- (x1 + x2) / 2, (y1 + y2) / 2,
- (x2 - x1) / 2, (y2 - y1) / 2,
- (uint32)Colour, 0);
-}
-
-
-// **************************************************************************************************************************
-//
-// This is a Bresenham Line Algorithm for drawing lines
-//
-// **************************************************************************************************************************
-
-static void _LinePixel(SDL_Surface *s, int x, int y, int c) {
- SDL_Rect rc;
- if (x >= 0 && y >= 0 && x < s->w && y < s->h)
- {
- rc.x = x; rc.y = y; rc.w = rc.h = 1;
- SDL_FillRect(s, &rc, (uint32)c);
- }
-}
-
-void Surface::Line(int x1, int y1, int x2, int y2) {
- int x, y, dx, dy, s1, s2;
- int i, dp, temp, swap = 0;
-
- PointProcess(x1, y1);
- PointProcess(x2, y2);
-
- x = x1; y = y1;
- _LinePixel((SDL_Surface *)sSurface, x1, y1, Colour);
- dx = abs(x2 - x1);
- dy = abs(y2 - y1);
-
- if (x2 < x1) s1 = -1;
- else if (x2 > x1) s1 = 1;
- else s1 = 0;
-
- if (y2 < y1) s2 = -1;
- else if (y2 > y1) s2 = 1;
- else s2 = 0;
-
- dp = 2 * dy - dx;
- if (dy > dx)
- {
- temp = dx; dx = dy; dy = temp; swap = 1;
- }
- for (i = 1; i <= dx; i++)
- {
- if (dp < 0)
- {
- if (swap)
-
- _LinePixel((SDL_Surface *)sSurface, x, y = y + s2, Colour);
- else
- _LinePixel((SDL_Surface *)sSurface, x = x + s1, y, Colour);
- dp = dp + 2 * dy;
- } else
- {
- _LinePixel((SDL_Surface *)sSurface, x = x + s1, y = y + s2, Colour);
- dp = dp + 2 * dy - 2 * dx;
- }
- }
-}
-
-// **************************************************************************************************************************
-
-//
-// An 8x8 pixel font, just alphanumeric characters
-//
-// **************************************************************************************************************************
-
-unsigned char font1[2048] =
-{
- 124,130,186,162,186,130,124,0,126,129,165,129,165,153,129,126,
- 126,129,165,129,153,165,129,126,108,246,246,254,124,56,16,0,
- 16,56,124,254,124,56,16,0,16,56,84,254,84,16,56,0,
- 56,124,254,254,108,16,56,0,16,24,20,20,48,112,96,0,
- 254,254,254,238,254,254,254,0,236,138,138,170,170,170,236,0,
- 142,136,136,140,136,136,232,0,174,170,170,234,170,170,174,0,
- 238,136,136,204,136,136,136,0,238,138,138,142,140,138,234,0,
- 62,34,62,34,102,238,204,0,16,84,40,198,40,84,16,0,
- 240,248,252,254,252,248,240,0,30,62,126,254,126,62,30,0,
- 16,56,124,16,124,56,16,0,238,238,238,238,238,0,238,0,
- 254,68,68,68,68,68,68,0,126,128,188,198,122,2,252,0,
- 0,0,0,0,255,255,0,0,16,56,124,16,124,56,16,254,
- 16,56,124,254,56,56,56,0,56,56,56,254,124,56,16,0,
- 16,24,252,254,252,24,16,0,16,48,126,254,126,48,16,0,
-
-
-
- 144,72,36,18,36,72,144,0,18,36,72,144,72,36,18,0,
- 16,40,68,146,40,68,130,0,130,68,40,146,68,40,16,0,
- 0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,0,
-
- 40,40,40,0,0,0,0,0,68,254,68,68,68,254,68,0,
- 16,126,144,124,18,252,16,0,66,164,72,16,36,74,132,0,
- 56,68,56,112,138,132,122,0,16,16,32,0,0,0,0,0,
- 8,16,16,16,16,16,8,0,32,16,16,16,16,16,32,0,
- 16,84,56,254,56,84,16,0,16,16,16,254,16,16,16,0,
- 0,0,0,0,0,16,16,32,0,0,0,254,0,0,0,0,
- 0,0,0,0,0,0,16,0,2,4,8,16,32,64,128,0,
- 124,130,130,130,130,130,124,0,240,16,16,16,16,16,254,0,
- 252,2,2,124,128,128,254,0,252,2,2,28,2,2,252,0,
- 130,130,130,126,2,2,2,0,254,128,252,2,2,2,252,0,
- 126,128,252,130,130,130,124,0,252,2,2,2,2,2,2,0,
- 124,130,130,124,130,130,124,0,126,130,130,126,2,2,252,0,
- 0,0,0,16,0,0,16,0,0,0,0,16,0,0,16,32,
- 8,16,32,64,32,16,8,0,0,0,0,254,0,254,0,0,
- 64,32,16,8,16,32,64,0,56,68,4,8,16,0,16,0,
- 60,66,154,170,156,64,62,0,124,130,130,254,130,130,130,0,
- 252,130,130,252,130,130,252,0,124,130,128,128,128,130,124,0,
- 252,130,130,130,130,130,252,0,254,128,128,240,128,128,254,0,
- 254,128,128,240,128,128,128,0,124,130,128,142,130,130,124,0,
- 130,130,130,254,130,130,130,0,254,16,16,16,16,16,254,0,
- 62,2,2,2,130,130,124,0,130,132,136,240,136,132,130,0,
- 128,128,128,128,128,128,254,0,252,146,146,146,146,146,146,0,
- 130,194,162,146,138,134,130,0,124,130,130,130,130,130,124,0,
- 252,130,130,252,128,128,128,0,124,130,130,130,138,134,126,0,
- 252,130,130,252,130,130,130,0,126,128,128,124,2,2,252,0,
- 254,16,16,16,16,16,16,0,130,130,130,130,130,130,124,0,
- 130,130,68,68,40,40,16,0,130,130,130,146,146,146,108,0,
- 130,68,40,16,40,68,130,0,130,130,130,126,2,2,252,0,
- 254,4,8,16,32,64,254,0,56,32,32,32,32,32,56,0,
- 128,64,32,16,8,4,2,0,56,8,8,8,8,8,56,0,
- 16,40,68,130,0,0,0,0,0,0,0,0,0,0,0,255,
- 32,32,16,0,0,0,0,0,0,0,56,68,124,68,68,0,
- 0,0,120,68,120,68,120,0,0,0,60,64,64,64,60,0,
- 0,0,120,68,68,68,120,0,0,0,124,64,112,64,124,0,
- 0,0,124,64,112,64,64,0,0,0,60,64,76,68,60,0,
- 0,0,68,68,124,68,68,0,0,0,124,16,16,16,124,0,
- 0,0,28,4,4,68,56,0,0,0,68,72,112,72,68,0,
- 0,0,64,64,64,64,124,0,0,0,120,84,84,84,84,0,
- 0,0,120,68,68,68,68,0,0,0,56,68,68,68,56,0,
- 0,0,120,68,120,64,64,0,0,0,56,68,68,76,54,0,
- 0,0,120,68,120,68,68,0,0,0,60,64,56,4,120,0,
- 0,0,124,16,16,16,16,0,0,0,68,68,68,68,56,0,
- 0,0,68,68,40,40,16,0,0,0,68,68,84,108,68,0,
- 0,0,68,40,16,40,68,0,0,0,68,68,60,4,120,0,
- 0,0,124,8,16,32,124,0,8,16,16,32,16,16,8,0,
- 16,16,16,0,16,16,16,0,32,16,16,8,16,16,32,0,
- 80,40,0,0,0,0,0,0,0,16,40,68,130,130,254,0,
- 254,254,254,254,254,254,254,0,0,0,0,0,0,254,254,0,
- 0,0,124,124,124,124,124,0,0,0,0,0,0,0,124,0,
- 128,128,128,128,128,128,128,0,0,64,64,64,64,64,64,0,
- 16,24,28,30,28,24,16,0,16,48,112,240,112,48,16,0,
- 62,30,30,62,114,224,64,0,4,14,156,248,240,240,248,0,
- 64,224,114,62,30,30,62,0,248,240,240,248,156,14,4,0,
- 56,68,130,130,130,68,56,0,56,124,254,254,254,124,56,0,
- 0,124,68,68,68,124,0,0,0,124,124,124,124,124,0,0,
- 0,60,110,126,112,126,60,0,0,60,118,126,14,126,60,0,
- 0,60,126,106,126,126,106,0,0,60,126,86,126,126,86,0,
- 0,0,0,24,24,0,0,0,0,0,24,60,60,24,0,0,
-
- 0,12,52,36,36,108,72,0,0,0,0,0,0,0,0,0,
- 60,126,198,231,255,224,126,60,60,126,227,231,255,7,126,60,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,52,118,118,94,126,60,0,0,60,110,126,112,126,60,0,
- 0,60,126,122,110,110,44,0,0,60,126,14,126,118,60,0,
- 0,0,0,0,0,0,0,0,126,126,126,126,60,0,0,0,
- 0,15,31,31,31,31,15,0,126,127,127,127,127,127,63,0,
- 0,0,0,60,126,126,126,126,126,126,126,126,126,126,126,126,
- 0,63,127,127,127,127,127,126,126,127,127,127,127,127,127,126,
-
-
- 0,240,248,248,248,248,240,0,126,254,254,254,254,254,252,0,
- 0,255,255,255,255,255,255,0,126,255,255,255,255,255,255,0,
- 0,252,254,254,254,254,254,126,126,254,254,254,254,254,254,126,
- 0,255,255,255,255,255,255,126,126,255,255,255,255,255,255,126,
- 0,0,63,63,48,55,52,52,0,0,255,255,0,255,0,0,
- 0,0,248,248,24,216,88,88,88,88,88,88,88,88,88,88,
- 88,216,24,248,248,0,0,0,0,255,0,255,255,0,0,0,
- 52,55,48,63,63,0,0,0,52,52,52,52,52,52,52,52,
- 0,0,0,31,24,24,24,24,0,0,0,255,0,0,0,0,
- 0,0,0,240,48,48,48,48,48,48,48,48,48,48,48,48,
- 48,48,48,240,0,0,0,0,0,0,0,255,0,0,0,0,
- 24,24,24,31,0,0,0,0,24,24,24,24,24,24,24,24,
- 136,34,136,34,136,34,136,34,85,170,85,170,85,170,85,170,
- 68,170,68,170,68,170,68,170,51,102,204,153,51,102,204,153,
- 204,102,51,153,204,102,51,153,199,143,31,62,124,248,241,227,
- 227,241,248,124,62,31,143,199,174,128,186,2,234,8,171,32,
- 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,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,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,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,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,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,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,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,
- 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,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,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,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,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,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,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,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,
- 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,0,0,0,0,0,0,
-};
-
-
-// **************************************************************************************************************************
-//
-// Check if pixel is set in character
-//
-// **************************************************************************************************************************
-
-static int _FONTPixelSet(unsigned char *Data, int x, int y) {
- if (x < 0 || y < 0 || x > 7 || y > 7) return 0;
-
- return (Data[y] & (0x80 >> x)) ? 1 : 0;
-}
-
-// **************************************************************************************************************************
-
-//
-// Draw an angled line - this stops the squared corners on diagonals showing
-//
-// **************************************************************************************************************************
-
-static void _FONTAngleDraw(SDL_Surface *s, SDL_Rect *rc, int w, int h, uint32 Colour) {
- int i, m;
- SDL_Rect rc3;
-
- m = abs(w); if (abs(h) > m) m = abs(h);
- for (i = 0; i < m; i++)
- {
- rc3.x = rc->x + w * i / m;
- rc3.y = rc->y + h * i / m;
- rc3.w = rc->w; rc3.h = rc->h;
- SDL_FillRect(s, &rc3, Colour);
- }
-}
-
-// **************************************************************************************************************************
-//
-// Draw an 8x8 pixellated character (for fonts), does some rounding etc.
-//
-// **************************************************************************************************************************
-
-static void _FONTChar(SDL_Surface *s, SDL_Rect *rc, uint32 Colour, int Char) {
- int x, y, w, h;
- unsigned char *GfxData;
- SDL_Rect rc2;
- w = rc->w / 8; h = rc->h / 8; // work out the box sizes
- SDWASSERT(w != 0 && h != 0); // At least one pixel !
- if (Char == ' ') return; // Don't do anything for spaces
- GfxData = font1 + Char * 8;
- for (x = 0; x < 8; x++) // Work through the 64 pixel array
- for (y = 0; y < 8; y++)
-
- if (_FONTPixelSet(GfxData, x, y)) // If set.
- {
- rc2.x = rc->x + rc->w * x / 8; // Calculate the bounding rectangle
- rc2.y = rc->y + rc->h * y / 8;
- rc2.w = rc->x + rc->w * (x + 1) / 8 - rc2.x;
-
- rc2.h = rc->y + rc->h * (y + 1) / 8 - rc2.y;
- SDL_FillRect(s, &rc2, Colour); // Draw an pixel there
-
- // Neaten the diagonals
- if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
- _FONTPixelSet(GfxData, x - 1, y) == 0 &&
- _FONTPixelSet(GfxData, x - 1, y + 1) != 0)
- _FONTAngleDraw(s, &rc2, -w, h, Colour);
-
- if (_FONTPixelSet(GfxData, x, y + 1) == 0 &&
- _FONTPixelSet(GfxData, x + 1, y) == 0 &&
- _FONTPixelSet(GfxData, x + 1, y + 1) != 0)
- _FONTAngleDraw(s, &rc2, w, h, Colour);
- }
-}
-
-// **************************************************************************************************************************
-//
-// Draw a single character using the bevelled font
-//
-// **************************************************************************************************************************
-
-void Surface::Char(int x1, int y1, int x2, int y2, char c) {
- SDL_Rect rc;
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
-
- rc.x = x1; rc.y = y1; // Set up bounding rectangle
- rc.w = x2 - x1 + 1; rc.h = y2 - y1 + 1;
-
- _FONTChar((SDL_Surface *)sSurface, &rc, (uint32)Colour, c);
-}
-
-
-// **************************************************************************************************************************
-//
-// Draw a string using the bevelled font
-//
-// **************************************************************************************************************************
-
-
-void Surface::String(int x1, int y1, int x2, int y2, const char *s) {
- int i, n;
- if (s == NULL) SDWERROR(); // Don't pass me NULL !
- if (*s == '\0') return; // Empty string.
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
- n = strlen(s); // Length of string
- for (i = 0; i < n; i++)
- Char(x1 + i * (x2 - x1) / n, y1, x1 + (i + 1) * (x2 - x1) / n, y2, s[i]);
-}
-
-// **************************************************************************************************************************
-//
-// Pixel Reader (from the SDL Documentation)
-//
-// **************************************************************************************************************************
-
-static uint32 _GetPixel(SDL_Surface *Surface, int x, int y) {
- const byte *p = (const byte *)Surface->getBasePtr(x, y);
- int bpp = Surface->format.bytesPerPixel;
-
- switch (bpp) {
- case 1:
- return *p;
- case 2:
- return READ_LE_UINT16(p);
- case 3:
- return p[0] << 16 | p[1] << 8 | p[2];
- case 4:
- return READ_LE_UINT32(p);
- default:
- return 0;
- }
-}
-
-// **************************************************************************************************************************
-//
-// Flip a surface (Double Buffering)
-//
-// **************************************************************************************************************************
-
-void Surface::Flip(void) {
- Display->update();
-}
-
-// **************************************************************************************************************************
-//
-
-// Mirroring functions
-//
-// **************************************************************************************************************************
-
-void Surface::HorizontalMirror(int x1, int y1, int x2, int y2) {
- int x, y;
- uint32 c1, c2;
- SDL_Rect rc;
- SDL_Surface *s = (SDL_Surface *)sSurface;
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
- rc.w = rc.h = 1;
- for (y = y1; y <= y2; y++)
- for (x = 0; x < (x2 - x1) / 2; x++)
- {
- c1 = _GetPixel(s, x1 + x, y);
- c2 = _GetPixel(s, x2 - x, y);
-
- rc.x = x1 + x; rc.y = y;
-
-
- SDL_FillRect(s, &rc, c2);
- rc.x = x2 - x;
- SDL_FillRect(s, &rc, c1);
- }
-}
-
-void Surface::VerticalMirror(int x1, int y1, int x2, int y2) {
- int x, y;
- uint32 c1, c2;
- SDL_Rect rc;
- SDL_Surface *s = (SDL_Surface *)sSurface;
- if (x2 == 0) x2 = xSize - 1; // Default values for the bottom corner
- if (y2 == 0) y2 = ySize - 1;
- PointProcess(x1, y1);
- PointProcess(x2, y2);
- SortAndValidate(x1, y1, x2, y2); // Sort the 2 corners so they become left,top,right,bottom
-
- rc.w = rc.h = 1;
- for (x = x1; x <= x2; x++)
-
- for (y = 0; y < (y2 - y1) / 2; y++)
- {
- c1 = _GetPixel(s, x, y1 + y);
- c2 = _GetPixel(s, x, y2 - y);
- rc.x = x; rc.y = y1 + y;
- SDL_FillRect(s, &rc, c2);
- rc.y = y2 - y;
- SDL_FillRect(s, &rc, c1);
-
- }
-}
-
-
-// **************************************************************************************************************************
-//
-// Function returns system timer, game timer
-//
-// **************************************************************************************************************************
-
-int SDLWrapper::GameClock(void) {
- return g_system->getMillis() * GameSpeed / 100;
-}
-
-int SDLWrapper::SystemClock(void) {
- return g_system->getMillis();
-}
-
-
-// **************************************************************************************************************************
-//
-// Timer Class
-//
-// **************************************************************************************************************************
-
-Timer::Timer(int TimeOut) // Create it
-{
- StartClock = GameClock(); // When we started
- EventTime = TimeOut; // When the timer times out
- ResetTimer(); // Set the end time
-}
-
-void Timer::ResetTimer(int t) // Reset it. If default param (0) use same time as before
-{
- if (t != 0) EventTime = t;
- EndClock = GameClock() + EventTime;
-}
-
-unsigned int Timer::Elapsed(void) // Time elapsed since creation
-{
- return GameClock() - StartClock;
-}
-
-int Timer::TimedOut(void) // Has the timer timed out
-{
- int t = (GameClock() > EndClock);
- if (t) ResetTimer(0);
- return t;
-}
-
-void Timer::WaitTimer(void) // Wait for the timer to time out
-
-{
- while (!TimedOut()) {
- }
-}
-
-// **************************************************************************************************************************
-//
-// Read a joystick - if there is one - or emulate it from the keyboard
-//
-// **************************************************************************************************************************
-
-static int _Process(int Pos) // Converts an analogue position to a digital directional value
-{
- if (abs(Pos) < 1024) return 0;
- return (Pos < 0) ? -1 : 1;
-}
-
-int SDLWrapper::ReadStick(int &A, int &B, int &dx, int &dy) {
-#ifdef TODO
- SDL_Event e;
- int r;
- while (SDL_PollEvent(&e)) {
- } // Process the event queue
- if (Joystick && 0) // Joystick available ? (ID#0)
- {
- SDL_JoystickUpdate(); // Update everything
- dx = _Process(SDL_JoystickGetAxis(JoyPtr, 0));
- dy = _Process(SDL_JoystickGetAxis(JoyPtr, 1));
- A = r = (SDL_JoystickGetButton(JoyPtr, 0) != 0);
- B = (SDL_JoystickGetButton(JoyPtr, 1) != 0);
- } else // No joystick, use keyboard (arrow keys Z and X)
- {
- uint8 *Key = SDL_GetKeyState(NULL);
- dx = dy = 0; // ZXCF or Arrow keys
- if (Key[SDLK_LEFT]) dx = -1;
- if (Key[SDLK_RIGHT]) dx = 1;
- if (Key[SDLK_DOWN]) dy = 1;
- if (Key[SDLK_UP]) dy = -1;
- // A & B are G and H or 1 and 2 on the keypad
- A = r = (Key[SDLK_LCTRL] != 0);
- B = (Key[SDLK_LALT] != 0);
-
- }
- return r;
-#else
- error("TODO: Read joystick");
-#endif
-}
-
-// **************************************************************************************************************************
-//
-// Game Over Key Pressed ?
-//
-// **************************************************************************************************************************
-
-int SDLWrapper::ExitKey() {
- Common::Event e;
- bool escFlag = false;
-
- while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_KEYDOWN && e.kbd.keycode == Common::KEYCODE_ESCAPE)
- escFlag = true;
- }
-
- return escFlag;
-}
-
-int SDLWrapper::GetKey(void) {
- Common::Event e;
-
- while (!Engine::shouldQuit()) {
- while (g_system->getEventManager()->pollEvent(e)) {
- if (e.type == Common::EVENT_KEYDOWN)
- return e.kbd.keycode;
- }
- }
-
- return -1;
-}
-
-// **************************************************************************************************************************
-//
-// Display Pointer, Follow Mouse around, Wait for Click.
-//
-// **************************************************************************************************************************
-
-int SDLWrapper::MouseClick(int &x, int &y) {
- Common::Event e;
-
- g_system->showMouse(true);
-
- while (!Engine::shouldQuit()) {
- if (g_system->getEventManager()->pollEvent(e) &&
- e.type == Common::EVENT_LBUTTONUP)
- break;
- }
-
- g_system->showMouse(false);
- return true;
-}
-
-// **************************************************************************************************************************
-//
-// Mix data from an audio object into the Stream - used by callback function
-//
-// **************************************************************************************************************************
-
-void AudioObject::CopyStream(void *Stream, int Reqd) {
-#ifdef TODO
- int Qty = Reqd; // Bytes to copy
- if (SoundOn == 0) return;
- if (Qty > Length - Position) // Can't use more than are available
- {
- if (LoopSound)
- Position = 0;
- else
- Qty = Length - Position;
- }
- if (Qty != 0) // Some data ?
- {
- uint8 *Audio = (uint8 *)Data;
- Audio = Audio + Position;
- SDL_MixAudio((uint8 *)Stream, Audio, Qty, // If so, mix it in.
- SDL_MIX_MAXVOLUME);
- Position = Position + Qty;
- }
-#endif
-}
-
-// **************************************************************************************************************************
-//
-// Attach and Detach objects from the internal sound object list
-//
-// **************************************************************************************************************************
-
-void AudioObject::Attach(void) {
- int i = 0;
- for (i = 0; i < MAXSOUND; i++) // Look for empty slot
- if (SoundList[i] == NULL) // If found, copy reference in
- {
- SoundList[i] = this;
- return;
- }
-}
-
-void AudioObject::Detach(void) {
- for (int i = 0; i < MAXSOUND; i++) // Look for it and delete it.
-
- if (SoundList[i] == this) SoundList[i] = NULL;
-}
-
-// **************************************************************************************************************************
-//
-// Load a .WAV file
-//
-// **************************************************************************************************************************
-
-void AudioWave::Load(const char *File) {
- Common::File *f = new Common::File();
-
- if (f->open(File)) {
- _stream = Audio::makeWAVStream(f, DisposeAfterUse::YES);
- assert(_stream);
- } else {
- delete f;
- error("Failed to load %s", File);
- }
-}
-
-// **************************************************************************************************************************
-//
-// Create a beep.
-//
-// **************************************************************************************************************************
-
-void AudioBeep::CreateBeep(int sPitch, int sLength) {
-#ifdef TODO
- int Size = AudioFmt.freq * sLength / 1000;
- SDWASSERT(AudioFmt.format = AUDIO_S16); // We must be using 16 bit signed here ?
- Uint16 *Wave = (Uint16 *)malloc(Size * 2); // Allocate a buffer for it
- CreateWave(Wave, Size, sPitch); // Create the wave
- SDL_LockAudio(); // Copy data into structure
- Data = Wave;
- Length = Size * 2;
- Position = 0;
- SDL_UnlockAudio();
-#else
- error("TODO: CreateBeep");
-#endif
-}
-
-void AudioObject::Write(int Pos, int Dat) {
-#ifdef TODO
- if (Pos >= 0 && Pos < Length / 2)
- {
- Uint16 *Wave = (Uint16 *)Data;
- Wave[Pos] = Dat;
- }
-#else
- error("TODO: AudioObject::Write");
-#endif
-}
-
-// **************************************************************************************************************************
-//
-// Wave Creators for beeps and hisses - one square wave, one white noise
-//
-// **************************************************************************************************************************
-
-void AudioBeep::CreateWave(void *data, int Size, int sPitch) {
-#ifdef TODO
- Uint16 *Wave = (Uint16 *)data;
- int PCount = 0;
- int PValue = 32700;
- int PMax = 0;
- if (sPitch > 0) PMax = AudioFmt.freq / sPitch / 2;
- for (int i = 0; i < Size; i++)
- {
- Wave[i] = (sPitch == 0 ? rand() : PValue);
- if (++PCount == PMax)
- {
- PCount = 0; PValue = -PValue;
- }
- }
-#else
- error("TODO: AudioBeep::CreateWave");
-#endif
-}
-
-
-// **************************************************************************************************************************
-//
-// Mixing Callback function
-//
-// **************************************************************************************************************************
-
-
-static void SoundCallBack(void *Data, uint8 *Stream, int Length) {
-#ifdef TODO
- Data = Data; // Stops nagging :)
- for (int i = 0; i < MAXSOUND; i++) // Work through all the sounds
- {
- if (SoundList[i] != NULL) // Call the handler function to copy them.
- SoundList[i]->CopyStream(Stream, Length);
- }
-#endif
-}
-
-// **************************************************************************************************************************
-//
-// Initialise Sound System
-//
-// **************************************************************************************************************************
-
-static void SoundInitialise(void) {
-#ifdef TODO
- for (int i = 0; i < MAXSOUND; i++) // Erase all sound objects
- SoundList[i] = NULL;
- AudioFmt.freq = 22050; // Frequency of reproduction
- AudioFmt.format = AUDIO_S16; // 16 bit sound
- AudioFmt.channels = 1; // No of channels
- AudioFmt.samples = 1024; // Sample length
- AudioFmt.callback = SoundCallBack; // Callback function
- AudioFmt.userdata = NULL; // Don't use this :)
- if (SDL_OpenAudio(&AudioFmt, NULL) < 0) // Open the audio devices
- SDWERROR(); // ... or not.
- SDL_PauseAudio(0); // Turn the audio system on.
-#endif
-}
-
-// **************************************************************************************************************************
-//
-// Terminate sound systems
-//
-// **************************************************************************************************************************
-
-static void SoundTerminate(void) {
- //SDL_CloseAudio(); // Close the audio devices
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/sdw.h b/engines/ultima/ultima0/sdw.h
deleted file mode 100644
index d019d313bae..00000000000
--- a/engines/ultima/ultima0/sdw.h
+++ /dev/null
@@ -1,278 +0,0 @@
-/* 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 ULTIMA0_SDW_H
-#define ULTIMA0_SDW_H
-
-#include "audio/mixer.h"
-#include "audio/audiostream.h"
-#include "graphics/managed_surface.h"
-#include "graphics/screen.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-extern Graphics::Screen *Display; // The Display screen
-extern int GameSpeed; // Scales the system clock.
-
-// It's all nicely in a namespace SDLWrapper
-namespace SDLWrapper {
-
-#define DEFAULT_SCBPP (0)
-#define MAXSOUND (16) // Maximum number of sounds
-
-#define SDWASSERT(x) if (!(x)) SDWERROR() // ASSERT and ERROR macros
-#define SDWERROR() FatalError(__LINE__,__FILE__)
-
-extern void SetSpeed(int n);
-extern void FatalError(int line, const char *filename); // Prototyping
-
-extern int GameClock(void); // No point in wrapping this, it just goes to SDL_GetTicks()
-extern int SystemClock(void); // This one is unaffected by the game speed.
-
-extern int ReadStick(int &A, int &B, int &dx, int &dy); // Read a joystick
-extern int MouseClick(int &x, int &y); // Read a mouse select - and - click
-extern int ExitKey(void);
-extern int GetKey(void);
-
-struct SDL_Rect {
- int x = 0;
- int y = 0;
- int w = 0;
- int h = 0;
-
- operator const Common::Rect() const {
- return Common::Rect(x, y, x + w, y + h);
- }
-};
-
-typedef Graphics::ManagedSurface SDL_Surface;
-
-class Rect {
-public:
- Rect() {} // Constructors
- Rect(int x1, int y1, int x2, int y2) {
- Left = x1; Top = y1; Right = x2; Bottom = y2;
- }
- int Left, Top, Right, Bottom; // The rectangle
-};
-
-// A basic Surface
-class Surface {
-public:
- Surface(int x = 0, int y = 0, int Trans = 0, int UseDisplay = 0, const char *File = nullptr);
- ~Surface();
-
- void SetColour(int r, int g, int b);
- void SetColour() {
- SetColour(-1, -1, -1);
- }
- void SetColour(int Col) {
- Colour = Col;
- }
- unsigned int GetColour(void) {
- return Colour;
- }
- int Width(void) {
- return xSize;
- }
- int Height(void) {
- return ySize;
- }
- void SetOrigin(int x = 0, int y = 0) {
- xOrigin = x; yOrigin = y;
- }
- void SetScale(int x = 256, int y = 256) {
- xScale = x; yScale = y;
- }
-
- void Plot(int x1, int y1);
- void FillRect(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
- void FillRect(Rect &r) {
- FillRect(r.Left, r.Top, r.Right, r.Bottom);
- }
- void FrameRect(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
- void FrameRect(Rect &r) {
- FrameRect(r.Left, r.Top, r.Right, r.Bottom);
- }
- void FillEllipse(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
- void FillEllipse(Rect &r) {
- FillEllipse(r.Left, r.Top, r.Right, r.Bottom);
- }
- void FrameEllipse(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
- void FrameEllipse(Rect &r) {
- FrameEllipse(r.Left, r.Top, r.Right, r.Bottom);
- }
- void Line(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
-
- void Copy(Surface &Target, Rect &SrcRect, int x = 0, int y = 0);
- void Copy(Rect &SrcRect, int x = 0, int y = 0);
- void Copy(Surface &Target, int x = 0, int y = 0);
- void Copy(int x = 0, int y = 0);
-
- void HorizontalMirror(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
- void VerticalMirror(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0);
-
- void Char(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, char c = ' ');
- void Char(Rect &r, char c) {
- Char(r.Left, r.Top, r.Right, r.Bottom, c);
- }
- void String(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0, const char *s = "");
- void String(Rect &r, char *s) {
- String(r.Left, r.Top, r.Right, r.Bottom, s);
- }
-
- void Flip(void);
-
-
-protected:
- void SortAndValidate(int &x1, int &y1, int &x2, int &y2);
- void PointProcess(int &x1, int &y1);
-
-private:
- SDL_Surface *sSurface;
- int xSize, ySize; // Surface size (physical)
- unsigned int Colour; // Drawing colour
- int IsTransparent; // Set if transparent
- unsigned int TransColour; // Transparency drawing colour
- int IsDisplay; // Set if is the physical display object
- int xOrigin, yOrigin; // Mobile origin and scaling
- int xScale, yScale;
-};
-
-// A surface but with transparency
-class TransparentSurface : public Surface {
-public:
- TransparentSurface(int x = 0, int y = 0) : Surface(x, y, 1, 0, nullptr) {
- }
-};
-
-// A surface with a bitmap on it, one solid, one transparent
-class BitmapSurface : public Surface {
-public:
- BitmapSurface(const char *File) : Surface(0, 0, 0, 0, File) {
- }
-};
-
-class TransparentBitmapSurface : public Surface {
-public:
- TransparentBitmapSurface(const char *File) : Surface(0, 0, 1, 0, File) {
- }
-};
-
-// The actual physical display
-class DisplaySurface : public Surface {
-public:
- DisplaySurface(int x = 0, int y = 0) : Surface(0, 0, 0, 1, nullptr) {
- }
-};
-
-// A simple timer
-class Timer {
-public:
- Timer(int TimeOut = 0);
- void ResetTimer(int t = 0);
- unsigned int Elapsed(void);
- int TimedOut(void);
- void WaitTimer(void);
-
-private:
- int StartClock;
- int EndClock;
- int EventTime;
-};
-
-// An audio object
-class AudioObject {
-public:
- AudioObject() {
- Data = nullptr; Position = Length = 0; Attach(); SoundOn = 0; LoopSound = 0;
- }
- ~AudioObject() {
- Detach(); if (Data != nullptr) free(Data);
- }
- void CopyStream(void *Stream, int Reqd);
- void Play(void) {
- Position = 0; SoundOn = 1;
- }
- void PlayLoop(void) {
- Position = 0; SoundOn = 1; LoopSound = 1;
- }
- void Stop(void) {
- SoundOn = 0; LoopSound = 0;
- }
- int Size(void) {
- return Length / 2;
- }
- void Write(int Pos, int Dat);
-protected:
- void Attach(void);
- void Detach(void);
- void *Data;
- int Position;
- int Length;
- int SoundOn;
- int LoopSound;
-};
-
-class AudioWave : public AudioObject {
-private:
- Audio::SoundHandle _soundHandle;
- Audio::AudioStream *_stream;
-
-public:
- AudioWave(const char *File) : AudioObject() {
- Load(File);
- }
-protected:
- void Load(const char *File);
-};
-
-class AudioBeep : public AudioObject {
-public:
- AudioBeep(int p, int l) : AudioObject() {
- CreateBeep(p, l);
- }
-protected:
- void CreateWave(void *Data, int Size, int sPitch);
- void CreateBeep(int sPitch, int sLength);
-};
-
-class AudioNoise : public AudioBeep {
-public:
- AudioNoise(int l) : AudioBeep(0, l) {
- }
-};
-
-inline void SDL_FillRect(SDL_Surface *surf, const SDL_Rect *rect, uint Color) {
- surf->fillRect(*rect, Color);
-}
-
-inline void SDL_BlitSurface(SDL_Surface *srcSurf, const SDL_Rect *srcRect,
- SDL_Surface *destSurf, const SDL_Rect *destRect) {
- destSurf->blitFrom(*srcSurf, *srcRect, *destRect);
-}
-
-} // namespace SDLWrapper
-} // namespace Ultima0
-} // namespace Ultima
-
-#endif
diff --git a/engines/ultima/ultima0/struct.h b/engines/ultima/ultima0/struct.h
deleted file mode 100644
index 59a8706c0e2..00000000000
--- a/engines/ultima/ultima0/struct.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* 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 ULTIMA0_STRUCT_H
-#define ULTIMA0_STRUCT_H
-
-#include "ultima/ultima0/data/defines.h"
-#include "ultima/ultima0/data/data.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Data Structures */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-} // namespace Ultima0
-} // namespace Ultima
-
-#endif
diff --git a/engines/ultima/ultima0/town.cpp b/engines/ultima/ultima0/town.cpp
deleted file mode 100644
index a016c6c6d6f..00000000000
--- a/engines/ultima/ultima0/town.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/* 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 "ultima/ultima0/akalabeth.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* Enter town (shopkeeper code) */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-void TOWNEnter(WORLDMAP *w, PLAYER *p) {
- int Key, i, Cost, Incr, Item;
- DRAWText("Welcome to the\nAdventure shop.\n");
- do /* Keep Buying */
- {
- HWStatus(p->Object[OB_FOOD], /* Refresh the status bar */
- p->Attr[AT_HP], p->Attr[AT_GOLD]);
- DRAWText("\nWhat shalt thou buy?\n\n");
- for (i = 0; i < p->Objects; i++) /* Price list */
- {
- GLOGetInfo(i, nullptr, &Cost, nullptr);
- DRAWText("%s: %.0f (%d GP)\n", GLOObjName(i), floor(p->Object[i]), Cost);
- }
- Key = HWGetKey(); Item = -1; /* Get item to buy */
- for (i = 0; i < p->Objects; i++) /* Find which one it was */
- {
- GLOGetInfo(i, nullptr, nullptr, &Cost);
- if (Cost == Key) Item = i;
- }
- if (p->Class == 'M') /* Some things mages can't use */
- if (Item == OB_BOW || Item == OB_RAPIER)
- {
- DRAWText("\nI'm sorry, Mages\ncan't use that.\n");
- Item = -1;
- }
-
- if (Item >= 0) /* Something selected */
- {
- GLOGetInfo(Item, nullptr, &Cost, nullptr);
- if (Cost > p->Attr[AT_GOLD])
- DRAWText("\nM'Lord thou cannot\nafford that item.\n");
- else
- {
- p->Attr[AT_GOLD] -= Cost; /* Lose the money */
- HWStatus(p->Object[OB_FOOD],/* Refresh the status bar */
- p->Attr[AT_HP], p->Attr[AT_GOLD]);
- Incr = 1; if (Item == OB_FOOD) Incr = 10;
- p->Object[Item] += Incr; /* Add 1 or 10 on */
- }
- }
- } while (Key != 'Q');
- DRAWText("\nBye.\n\n");
-}
-
-} // namespace Ultima0
-} // namespace Ultima
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index f7c7bf434aa..b6e5cb2d9f8 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -19,13 +19,11 @@
*
*/
+#include "common/system.h"
#include "engines/util.h"
#include "graphics/paletteman.h"
-#include "ultima/ultima0/sdw.h"
#include "ultima/ultima0/ultima0.h"
#include "ultima/ultima0/console.h"
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/sdw.h"
namespace Ultima {
namespace Ultima0 {
diff --git a/engines/ultima/ultima0/world.cpp b/engines/ultima/ultima0/world.cpp
deleted file mode 100644
index 05da892efff..00000000000
--- a/engines/ultima/ultima0/world.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 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/>.
- *
- */
-
-/************************************************************************/
-/************************************************************************/
-/* */
-/* World Map Code */
-/* */
-/************************************************************************/
-/************************************************************************/
-
-#include "ultima/ultima0/akalabeth.h"
-#include "ultima/ultima0/ultima0.h"
-
-namespace Ultima {
-namespace Ultima0 {
-
-/************************************************************************/
-/* */
-/* Create the world map, set player start position */
-/* */
-/************************************************************************/
-
-void WORLDCreate(PLAYER *p, WORLDMAP *w) {
- w->init(*p);
-}
-
-/************************************************************************/
-/* */
-/* Read world map value */
-/* */
-/************************************************************************/
-
-int WORLDRead(WORLDMAP *w, int x, int y) {
- if (x < 0 || y < 0) return WT_MOUNTAIN;
- if (x >= WORLD_MAP_SIZE) return WT_MOUNTAIN;
- if (y >= WORLD_MAP_SIZE) return WT_MOUNTAIN;
- return w->Map[x][y];
-}
-
-/************************************************************************/
-/* */
-/* Draw world map */
-/* */
-/************************************************************************/
-
-void WORLDDraw(PLAYER *p, WORLDMAP *m, int ShowAsMap) {
- int x, y, x1, y1, w, h, Grid;
- RECT r;
- Grid = 7; /* Number of cells in grid */
- if (MAINSuper() == 0) Grid = 3; /* Standard Aklabeth */
- if (ShowAsMap) Grid = DUNGEON_MAP_SIZE; /* Displaying as a map ? */
- w = 1280 / Grid; h = 1024 / Grid; /* Get grid sizes */
- for (x = 0; x < Grid; x++) /* For all grid cells */
- for (y = 0; y < Grid; y++)
- {
- DRAWSetRect(&r, x * w, y * h, /* Work out the drawing rect */
- x * w + w - 1, y * h + h - 1);
- x1 = p->World.x - Grid / 2 + x; /* Which cell ? */
- y1 = p->World.y + Grid / 2 - y;
- if (ShowAsMap) /* If map, not centred around us */
- x1 = x, y1 = Grid - 1 - y;
- DRAWTile(&r, WORLDRead(m, x1, y1));
- if (x1 == p->World.x && /* Draw us if we're there */
- y1 == p->World.y)
- DRAWTile(&r, WT_PLAYER);
- }
-}
-
-} // namespace Ultima0
-} // namespace Ultima
Commit: bb5560ce62d8da85a1e25d95f17357f8dda8229e
https://github.com/scummvm/scummvm/commit/bb5560ce62d8da85a1e25d95f17357f8dda8229e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Overworld minimap
Changed paths:
engines/ultima/ultima0/data/defines.h
engines/ultima/ultima0/gfx/map.cpp
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/metaengine.h
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/create_character.cpp
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/ultima0/data/defines.h b/engines/ultima/ultima0/data/defines.h
index 0b15e9c402c..3fe3314874c 100644
--- a/engines/ultima/ultima0/data/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -27,27 +27,30 @@
namespace Ultima {
namespace Ultima0 {
-constexpr int DEFAULT_SCX = 640; // Default Screen Size and Depth
+constexpr int DEFAULT_SCX = 640; // Default Screen Size and Depth
constexpr int DEFAULT_SCY = 400;
+constexpr int WORLD_MAP_SIZE = 21; // Size of world map
+constexpr int DUNGEON_MAP_SIZE = 11; // Size of dungeon map
+constexpr int MAX_MONSTERS = 10; // Number of Monsters
+constexpr int MAX_ATTR = 6; // Attributes
+constexpr int MAX_OBJ = 6; // Objects
+constexpr int WORLD_GRID_SIZE = 3; // Visible part of map is axa
+constexpr int MAX_NAME = 8; // Max size player name
+constexpr int MAX_VIEW_DEPTH = 9; // Max viewing depth
+
+constexpr int WORLD_MINIMAP_TILE_SIZE = 5;
+constexpr int WORLD_MINIMAP_SIZE = WORLD_MAP_SIZE * WORLD_MINIMAP_TILE_SIZE;
+
#define RND_MAX 0x7fffffff
#define RND() (((double)g_engine->getRandomNumber())/RND_MAX)
#define urand() g_engine->getRandomNumber()
-#define AKVERSION (1.000) /* Version number */
-
-#define WORLD_MAP_SIZE (21) /* Size of world map */
-#define DUNGEON_MAP_SIZE (11) /* Size of dungeon map */
-#define MAX_MONSTERS (10) /* Number of Monsters */
-#define MAX_ATTR (6) /* Attributes */
-#define MAX_OBJ (6) /* Objects */
-#define WORLD_GRID_SIZE (3) /* Visible part of map is axa */
-#define MAX_NAME (8) /* Max size player name */
-#define MAX_VIEW_DEPTH (9) /* Max viewing depth */
-
- /* Convert RGB to Colour Code */
+#define AKVERSION (1.000) // Version number
+
+ // Convert RGB to Colour Code
#define RGB(r,g,b) ((r?4:0)+(g?2:0)+(b?1:0))
-#define C_BLACK RGB(0,0,0) /* Some Colours */
+#define C_BLACK RGB(0,0,0) // Some Colours
#define C_RED RGB(1,0,0)
#define C_GREEN RGB(0,1,0)
#define C_BLUE RGB(0,0,1)
@@ -61,15 +64,15 @@ constexpr int DEFAULT_SCY = 400;
#define C_TEXT_DEFAULT C_CYAN
-#define WT_SPACE (0) /* World Tiles */
+#define WT_SPACE (0) // World Tiles
#define WT_MOUNTAIN (1)
#define WT_TREE (2)
#define WT_TOWN (3)
#define WT_DUNGEON (4)
#define WT_BRITISH (5)
-#define WT_PLAYER (-1) /* Used for the player graphic */
+#define WT_PLAYER (-1) // Used for the player graphic
-#define DT_SPACE (0) /* Dungeon tiles */
+#define DT_SPACE (0) // Dungeon tiles
#define DT_SOLID (1)
#define DT_TRAP (2)
#define DT_HIDDENDOOR (3)
@@ -79,12 +82,12 @@ constexpr int DEFAULT_SCY = 400;
#define DT_LADDERUP (8)
#define DT_PIT (9)
-#define ISWALKTHRU(x) ((x) != DT_SOLID) /* Tests for them */
+#define ISWALKTHRU(x) ((x) != DT_SOLID) // Tests for them
#define ISDRAWWALL(x) ((x) == DT_SOLID || (x) == DT_HIDDENDOOR)
#define ISDRAWDOOR(x) ((x) == DT_DOOR)
#define ISDRAWOPEN(x) (ISDRAWWALL(x) == 0 && ISDRAWDOOR(x) == 0)
-#define COL_WALL (C_GREEN) /* Object Colours */
+#define COL_WALL (C_GREEN) // Object Colours
#define COL_LADDER (C_RED)
#define COL_DOOR (C_BLUE)
#define COL_HOLE (C_RED)
@@ -96,7 +99,7 @@ constexpr int DEFAULT_SCY = 400;
#define COL_BRITISH (C_WHITE)
#define COL_PLAYER (C_CYAN)
-#define MN_SKELETON (1) /* Monster types */
+#define MN_SKELETON (1) // Monster types
#define MN_THIEF (2)
#define MN_RAT (3)
#define MN_ORC (4)
@@ -107,14 +110,14 @@ constexpr int DEFAULT_SCY = 400;
#define MN_DAEMON (9)
#define MN_BALROG (10)
-#define AT_HP (0) /* Player attributes */
+#define AT_HP (0) // Player attributes
#define AT_STRENGTH (1)
#define AT_DEXTERITY (2)
#define AT_STAMINA (3)
#define AT_WISDOM (4)
#define AT_GOLD (5)
-#define OB_FOOD (0) /* Object Attributes */
+#define OB_FOOD (0) // Object Attributes
#define OB_RAPIER (1)
#define OB_AXE (2)
#define OB_SHIELD (3)
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
index 48bb75896c4..28dc76ef801 100644
--- a/engines/ultima/ultima0/gfx/map.cpp
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -43,9 +43,9 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
if (showAsMap) {
// If map, not centered around us
- x1 = x, y1 = Grid - 1 - y;
+ x1 = x, y1 = y;
} else {
- // Which cell ?
+ // Which cell?
x1 = player.World.x - Grid / 2 + x;
y1 = player.World.y - Grid / 2 + y;
}
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index 1f6e7876469..8850fdc9397 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -48,6 +48,7 @@ static const KeybindingRecord OVERWORLD_KEYS[] = {
{ KEYBIND_RIGHT, "RIGHT", _s("East"), "RIGHT", "JOY_RIGHT" },
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
+ { KEYBIND_MINIMAP, "MINIMAP", _s("Minimap"), "m", nullptr },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
@@ -59,6 +60,7 @@ static const KeybindingRecord DUNGEON_KEYS[] = {
{ KEYBIND_ATTACK, "ATTACK", _s("Attack"), "a", "JOY_A" },
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
+ { KEYBIND_MINIMAP, "MINIMAP", _s("Minimap"), "m", nullptr },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
diff --git a/engines/ultima/ultima0/metaengine.h b/engines/ultima/ultima0/metaengine.h
index 2f76249476b..c30af2c6016 100644
--- a/engines/ultima/ultima0/metaengine.h
+++ b/engines/ultima/ultima0/metaengine.h
@@ -30,7 +30,7 @@ namespace Ultima0 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
KEYBIND_SELECT, KEYBIND_ESCAPE, KEYBIND_ENTER, KEYBIND_INFO,
- KEYBIND_ATTACK,
+ KEYBIND_ATTACK, KEYBIND_MINIMAP,
KEYBIND_NONE
};
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 198d9bc9f0f..65524f058e3 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -49,6 +49,7 @@ public:
PLAYER _player;
WORLDMAP _worldMap;
DUNGEONMAP _dungeon;
+ bool _showMinimap = false;
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index 9ae56776942..49fcf3adcd7 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -273,7 +273,7 @@ void Attack::attackHitMonster(const COORD &c) {
// If no, or not dexterous
if (Monster < 0 || player.Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player.Level) {
// Then a miss.
- _message += "You missed !!\n";
+ _message += "\nMissed!";
_mode = DONE;
redraw();
delaySeconds(1);
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
index 91a0e0c775f..dec8c0b440a 100644
--- a/engines/ultima/ultima0/views/create_character.cpp
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -115,8 +115,6 @@ bool CreateCharacter::msgKeypress(const KeypressMessage &msg) {
}
bool CreateCharacter::msgAction(const ActionMessage &msg) {
- auto &player = g_engine->_player;
-
if (msg._action == KEYBIND_ESCAPE) {
replaceView("Title");
return true;
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index e73536c482e..1a0c4552935 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -94,6 +94,10 @@ bool Dungeon::msgAction(const ActionMessage &msg) {
_status.draw(); // Render the message before we switch views
addView("Attack");
break;
+ case KEYBIND_MINIMAP:
+ g_engine->_showMinimap = !g_engine->_showMinimap;
+ redraw();
+ break;
default:
showMessage("Huh???");
break;
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 6d117171d94..eb647de469c 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -52,6 +52,13 @@ void WorldMap::draw() {
// Allow the status area to draw
View::draw();
+
+ if (g_engine->_showMinimap) {
+ s.frameRect(Common::Rect(s.w - WORLD_MINIMAP_SIZE - 4, 0, s.w, WORLD_MINIMAP_SIZE + 4), C_GREY);
+ s.frameRect(Common::Rect(s.w - WORLD_MINIMAP_SIZE - 3, 1, s.w - 1, WORLD_MINIMAP_SIZE + 3), C_GREY);
+ Graphics::ManagedSurface minimapArea(s, Common::Rect(s.w - WORLD_MINIMAP_SIZE - 2, 2, s.w - 2, WORLD_MINIMAP_SIZE + 2));
+ Gfx::Map::draw(&minimapArea, true);
+ }
}
bool WorldMap::msgAction(const ActionMessage &msg) {
@@ -83,6 +90,10 @@ bool WorldMap::msgAction(const ActionMessage &msg) {
case KEYBIND_ENTER:
enter();
break;
+ case KEYBIND_MINIMAP:
+ g_engine->_showMinimap = !g_engine->_showMinimap;
+ redraw();
+ break;
default:
showMessage("");
break;
Commit: 97d1befc512d562a7b2952ff4f3d20673598cb8e
https://github.com/scummvm/scummvm/commit/97d1befc512d562a7b2952ff4f3d20673598cb8e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:29+11:00
Commit Message:
ULTIMA: ULTIMA0: Added dungeon minimap
Changed paths:
engines/ultima/ultima0/data/defines.h
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/dungeon.h
diff --git a/engines/ultima/ultima0/data/defines.h b/engines/ultima/ultima0/data/defines.h
index 3fe3314874c..ea855279e14 100644
--- a/engines/ultima/ultima0/data/defines.h
+++ b/engines/ultima/ultima0/data/defines.h
@@ -39,8 +39,9 @@ constexpr int WORLD_GRID_SIZE = 3; // Visible part of map is axa
constexpr int MAX_NAME = 8; // Max size player name
constexpr int MAX_VIEW_DEPTH = 9; // Max viewing depth
-constexpr int WORLD_MINIMAP_TILE_SIZE = 5;
-constexpr int WORLD_MINIMAP_SIZE = WORLD_MAP_SIZE * WORLD_MINIMAP_TILE_SIZE;
+constexpr int MINIMAP_TILE_SIZE = 5;
+constexpr int WORLD_MINIMAP_SIZE = WORLD_MAP_SIZE * MINIMAP_TILE_SIZE;
+constexpr int DUNGEON_MINIMAP_SIZE = DUNGEON_MAP_SIZE * MINIMAP_TILE_SIZE;
#define RND_MAX 0x7fffffff
#define RND() (((double)g_engine->getRandomNumber())/RND_MAX)
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 1a0c4552935..200c59540f3 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -55,6 +55,42 @@ void Dungeon::draw() {
// Allow the status area to draw
View::draw();
+
+ if (g_engine->_showMinimap) {
+ s.frameRect(Common::Rect(s.w - DUNGEON_MINIMAP_SIZE - 4, 0, s.w, DUNGEON_MINIMAP_SIZE + 4), C_GREY);
+ s.frameRect(Common::Rect(s.w - DUNGEON_MINIMAP_SIZE - 3, 1, s.w - 1, DUNGEON_MINIMAP_SIZE + 3), C_GREY);
+ Graphics::ManagedSurface minimapArea(s, Common::Rect(s.w - DUNGEON_MINIMAP_SIZE - 2, 2, s.w - 2, DUNGEON_MINIMAP_SIZE + 2));
+ drawMinimap(minimapArea);
+ }
+}
+
+void Dungeon::drawMinimap(Graphics::ManagedSurface &mapArea) {
+ const auto &player = g_engine->_player;
+ const auto &dungeon = g_engine->_dungeon;
+ int tile;
+
+ for (int y = 0; y < DUNGEON_MAP_SIZE; ++y) {
+ for (int x = 0; x < DUNGEON_MAP_SIZE; ++x) {
+ const Common::Rect r(x * MINIMAP_TILE_SIZE, y * MINIMAP_TILE_SIZE,
+ (x + 1) * MINIMAP_TILE_SIZE, (y + 1) * MINIMAP_TILE_SIZE);
+ if (x == player.Dungeon.x && y == player.Dungeon.y) {
+ mapArea.fillRect(r, C_CYAN);
+ } else if (dungeon.findMonster(COORD(x, y)) > 0) {
+ mapArea.fillRect(r, C_RED);
+ } else {
+ tile = dungeon.Map[x][y];
+
+ if (tile == DT_SPACE || tile == DT_DOOR || tile == DT_HIDDENDOOR)
+ mapArea.fillRect(r, C_BLACK);
+ else if (tile == DT_SOLID)
+ mapArea.fillRect(r, C_WHITE);
+ else if (tile == DT_LADDERUP || tile == DT_LADDERDN)
+ mapArea.fillRect(r, C_GREEN);
+ else
+ mapArea.fillRect(r, C_ROSE);
+ }
+ }
+ }
}
bool Dungeon::msgAction(const ActionMessage &msg) {
diff --git a/engines/ultima/ultima0/views/dungeon.h b/engines/ultima/ultima0/views/dungeon.h
index cbe745ada12..cd494eb9cb9 100644
--- a/engines/ultima/ultima0/views/dungeon.h
+++ b/engines/ultima/ultima0/views/dungeon.h
@@ -33,6 +33,7 @@ class Dungeon : public View {
private:
DungeonStatus _status = DungeonStatus(this);
+ void drawMinimap(Graphics::ManagedSurface &mapArea);
void moveForward();
void interact();
void endOfTurn();
Commit: 09cb65ce8a6bf0e29fcf4fb2d1b6580cefbf6f90
https://github.com/scummvm/scummvm/commit/09cb65ce8a6bf0e29fcf4fb2d1b6580cefbf6f90
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:30+11:00
Commit Message:
ULTIMA: ULTIMA0: Janitorial
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/data/monster_logic.cpp
engines/ultima/ultima0/data/monster_logic.h
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/dungeon.h
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/attack.h
engines/ultima/ultima0/views/dungeon.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 1f294da9619..42922b60a80 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -25,7 +25,7 @@
namespace Ultima {
namespace Ultima0 {
-const _OInfStruct OBJECT_INFO[] = {
+const ObjectInfo OBJECT_INFO[] = {
{ "Food", 1, 0, Common::KEYCODE_f },
{ "Rapier", 8, 10, Common::KEYCODE_r },
{ "Axe", 5, 5, Common::KEYCODE_a },
@@ -34,7 +34,7 @@ const _OInfStruct OBJECT_INFO[] = {
{ "Magic Amulet", 15, 0, Common::KEYCODE_m }
};
-const _MInfStruct MONSTER_INFO[] = {
+const MonsterInfo MONSTER_INFO[] = {
{ nullptr, 0 },
{ "Skeleton", 1 },
{ "Thief", 2 },
@@ -53,7 +53,7 @@ const char *const DIRECTION_NAMES[] = { "North", "East", "South", "West" };
/*-------------------------------------------------------------------*/
-void PLAYER::init() {
+void PlayerInfo::init() {
Common::fill(Name, Name + MAX_NAME + 1, '\0');
World.x = World.y = 0;
Dungeon.x = Dungeon.y = 0;
@@ -69,12 +69,12 @@ void PLAYER::init() {
Common::fill(Object, Object + MAX_OBJ, 0);
}
-void PLAYER::rollAttributes() {
+void PlayerInfo::rollAttributes() {
for (int i = 0; i < MAX_ATTR; ++i)
Attr[i] = g_engine->getRandomNumber(21) + 4;
}
-void PLAYER::synchronize(Common::Serializer &s) {
+void PlayerInfo::synchronize(Common::Serializer &s) {
s.syncBytes((byte *)Name, MAX_NAME + 1);
s.syncAsSint16LE(World.x);
s.syncAsSint16LE(World.y);
@@ -100,7 +100,7 @@ void PLAYER::synchronize(Common::Serializer &s) {
}
}
-Direction PLAYER::dungeonDir() const {
+Direction PlayerInfo::dungeonDir() const {
if (DungDir.y < 0)
return DIR_NORTH;
else if (DungDir.x > 0)
@@ -111,7 +111,7 @@ Direction PLAYER::dungeonDir() const {
return DIR_WEST;
}
-void PLAYER::setDungeonDir(Direction newDir) {
+void PlayerInfo::setDungeonDir(Direction newDir) {
DungDir.x = 0;
DungDir.y = 0;
switch (newDir) {
@@ -130,19 +130,19 @@ void PLAYER::setDungeonDir(Direction newDir) {
}
}
-void PLAYER::dungeonTurnLeft() {
+void PlayerInfo::dungeonTurnLeft() {
Direction dir = dungeonDir();
setDungeonDir((dir == DIR_NORTH) ? DIR_WEST : (Direction)((int)dir - 1));
}
-void PLAYER::dungeonTurnRight() {
+void PlayerInfo::dungeonTurnRight() {
Direction dir = dungeonDir();
setDungeonDir((dir == DIR_WEST) ? DIR_NORTH : (Direction)((int)dir + 1));
}
/*-------------------------------------------------------------------*/
-void WORLDMAP::init(PLAYER &p) {
+void WorldMapInfo::init(PlayerInfo &p) {
int c, x, y, Size;
g_engine->setRandomSeed(p.LuckyNumber);
@@ -181,7 +181,7 @@ void WORLDMAP::init(PLAYER &p) {
Map[x][y] = WT_BRITISH; // Put LBs castle there
}
-int WORLDMAP::read(int x, int y) const {
+int WorldMapInfo::read(int x, int y) const {
if (x < 0 || y < 0)
return WT_MOUNTAIN;
if (x >= WORLD_MAP_SIZE || y >= WORLD_MAP_SIZE)
@@ -189,7 +189,7 @@ int WORLDMAP::read(int x, int y) const {
return Map[x][y];
}
-void WORLDMAP::synchronize(Common::Serializer &s) {
+void WorldMapInfo::synchronize(Common::Serializer &s) {
for (int y = 0; y < WORLD_MAP_SIZE; ++y)
for (int x = 0; x < WORLD_MAP_SIZE; ++x)
s.syncAsByte(Map[x][y]);
@@ -197,7 +197,7 @@ void WORLDMAP::synchronize(Common::Serializer &s) {
/*-------------------------------------------------------------------*/
-void DUNGEONMAP::create(const PLAYER &player) {
+void DungeonMapInfo::create(const PlayerInfo &player) {
int i, x, y;
const int Size = DUNGEON_MAP_SIZE - 1;
@@ -256,7 +256,7 @@ void DUNGEONMAP::create(const PLAYER &player) {
addMonster(player, i);
}
-int DUNGEONMAP::generateContent(int c) {
+int DungeonMapInfo::generateContent(int c) {
if (RND() > .95) c = DT_TRAP;
if (RND() > .6) c = DT_HIDDENDOOR;
if (RND() > .6) c = DT_DOOR;
@@ -265,7 +265,7 @@ int DUNGEONMAP::generateContent(int c) {
return c;
}
-void DUNGEONMAP::addMonster(const PLAYER &player, int Type) {
+void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
int x, y;
int level = MONSTER_INFO[Type].Level;
@@ -277,12 +277,12 @@ void DUNGEONMAP::addMonster(const PLAYER &player, int Type) {
return;
// Get monster record
- MONSTER &m = Monster[MonstCount++];
+ MonsterEntry &m = Monster[MonstCount++];
// Fill in details */
- m.Type = Type;
- m.Strength = level + 3 + player.Level;
- m.Alive = 1;
+ m._type = Type;
+ m._strength = level + 3 + player.Level;
+ m._alive = true;
// Find a place for it. Must be empty, not player
do {
@@ -292,21 +292,20 @@ void DUNGEONMAP::addMonster(const PLAYER &player, int Type) {
(x == player.Dungeon.x && y == player.Dungeon.y));
// Record position
- m.Loc.x = x; m.Loc.y = y;
+ m._loc.x = x; m._loc.y = y;
}
-void DUNGEONMAP::synchronize(Common::Serializer &s) {
+void DungeonMapInfo::synchronize(Common::Serializer &s) {
for (int y = 0; y < DUNGEON_MAP_SIZE; ++y)
for (int x = 0; x < DUNGEON_MAP_SIZE; ++x)
s.syncAsByte(Map[x][y]);
}
-int DUNGEONMAP::findMonster(const COORD &c) const {
+int DungeonMapInfo::findMonster(const Common::Point &c) const {
int i, n = -1;
for (i = 0; i < MonstCount; i++)
- if (c.x == Monster[i].Loc.x &&
- c.y == Monster[i].Loc.y &&
- Monster[i].Alive != 0) n = i;
+ if (c.x == Monster[i]._loc.x && c.y == Monster[i]._loc.y && Monster[i]._alive)
+ n = i;
return n;
}
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 7c2613959da..49b149bf20e 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -32,68 +32,64 @@ namespace Ultima0 {
enum Direction { DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST };
-struct PLAYER;
+struct PlayerInfo;
-struct _OInfStruct {
+struct ObjectInfo {
const char *Name;
int Cost;
int MaxDamage;
Common::KeyCode keycode;
};
-struct _MInfStruct {
+struct MonsterInfo {
const char *Name; int Level;
};
-extern const _OInfStruct OBJECT_INFO[];
-extern const _MInfStruct MONSTER_INFO[];
+extern const ObjectInfo OBJECT_INFO[];
+extern const MonsterInfo MONSTER_INFO[];
extern const char *ATTRIB_NAMES[];
extern const char *const DIRECTION_NAMES[];
-// point/rect types
-typedef Common::Point COORD;
-typedef Common::Rect RECT;
-
/**
* Monster structure
*/
-struct MONSTER {
- COORD Loc; // Position
- int Type = 0; // Monster type
- int Strength = 0; // Strength
- int Alive = 0; // Alive flag
+struct MonsterEntry {
+ Common::Point _loc; // Position
+ int _type = 0; // Monster type
+ int _strength = 0; // Strength
+ bool _alive = false; // Alive flag
};
/**
* Dungeon Map Structure
*/
-struct DUNGEONMAP {
+struct DungeonMapInfo {
private:
- void addMonster(const PLAYER &player, int Type);
+ void addMonster(const PlayerInfo &player, int Type);
int generateContent(int c);
public:
const int MapSize = DUNGEON_MAP_SIZE - 1; // Size of Map
byte Map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
int MonstCount = 0; // Number of Monsters
- MONSTER Monster[MAX_MONSTERS]; // Monster records
+ MonsterEntry Monster[MAX_MONSTERS]; // Monster records
- void create(const PLAYER &player);
+ void create(const PlayerInfo &player);
void synchronize(Common::Serializer &s);
/**
* Find Monster ID at given location
*/
- int findMonster(const COORD &c) const;
+ int findMonster(const Common::Point &c) const;
};
/**
* Player structure
*/
-struct PLAYER {
+struct PlayerInfo {
char Name[MAX_NAME + 1] = {}; // Player Name
- COORD World; // World map position
- COORD Dungeon; // Dungeon map position
- COORD DungDir; // Dungeon direction facing
+ Common::Point World; // World map position
+ Common::Point Dungeon; // Dungeon map position
+ Common::Point DungDir; // Dungeon direction facing
byte Class = '?'; // Player class (F or M)
int HPGain = 0; // HPs gained in dungeon
int Level = 0; // Dungeon level, 0 = world map
@@ -134,10 +130,10 @@ struct PLAYER {
/**
* World Map structure
*/
-struct WORLDMAP {
+struct WorldMapInfo {
byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
- void init(PLAYER &p);
+ void init(PlayerInfo &p);
int read(int x, int y) const;
void synchronize(Common::Serializer &s);
};
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
index abcf00ebade..bb78918c54b 100644
--- a/engines/ultima/ultima0/data/monster_logic.cpp
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -25,19 +25,19 @@
namespace Ultima {
namespace Ultima0 {
-void MonsterLogic::checkForAttacks(PLAYER &p, DUNGEONMAP &d) {
+void MonsterLogic::checkForAttacks(PlayerInfo &p, DungeonMapInfo &d) {
int i, Attacked;
double Dist;
// Go through all monsters
for (i = 0; i < d.MonstCount; i++) {
- MONSTER &m = d.Monster[i]; // Pointer to MONSTER &/
- Dist = pow(m.Loc.x - p.Dungeon.x, 2); // Calculate Distance
- Dist = Dist + pow(m.Loc.y - p.Dungeon.y, 2);
+ MonsterEntry &m = d.Monster[i]; // Pointer to MONSTER &/
+ Dist = pow(m._loc.x - p.Dungeon.x, 2); // Calculate Distance
+ Dist = Dist + pow(m._loc.y - p.Dungeon.y, 2);
Dist = sqrt(Dist);
// If alive
- if (m.Alive != 0) {
+ if (m._alive) {
Attacked = 0;
// If within range
@@ -47,12 +47,12 @@ void MonsterLogic::checkForAttacks(PLAYER &p, DUNGEONMAP &d) {
// If didn't attack, then move
if (Attacked == 0) {
// Mimics only if near enough
- if (m.Type != MN_MIMIC || Dist >= 3.0)
+ if (m._type != MN_MIMIC || Dist >= 3.0)
move(m, p, d);
// Recovers if didn't attack
- if (m.Strength < p.Level * p.Skill)
- m.Strength = m.Strength + p.Level;
+ if (m._strength < p.Level * p.Skill)
+ m._strength = m._strength + p.Level;
}
}
}
@@ -62,27 +62,27 @@ void MonsterLogic::showLines(const Common::String &msg) {
g_events->send("DungeonStatus", GameMessage("LINES", msg));
}
-int MonsterLogic::attack(MONSTER &m, PLAYER &p) {
+int MonsterLogic::attack(MonsterEntry &m, PlayerInfo &p) {
int n;
- if (m.Type == MN_GREMLIN || // Special case for Gremlin/Thief
- m.Type == MN_THIEF)
+ if (m._type == MN_GREMLIN || // Special case for Gremlin/Thief
+ m._type == MN_THIEF)
if (RND() > 0.5) // Half the time
return steal(m, p);
Common::String msg = Common::String::format("You are being attacked by a %s !!!.\n",
- MONSTER_INFO[m.Type].Name);
+ MONSTER_INFO[m._type].Name);
n = urand() % 20; // Calculate hit chance
if (p.Object[OB_SHIELD] > 0) n--;
n = n - p.Attr[AT_STAMINA];
- n = n + m.Type + p.Level;
+ n = n + m._type + p.Level;
if (n < 0) {
// Missed !
msg += "Missed !\n";
} else {
// Hit !
- n = urand() % m.Type; // Calculate damage done.
+ n = urand() % m._type; // Calculate damage done.
n = n + p.Level;
p.Attr[AT_HP] -= n; // Adjust hit points
msg += "Hit !!!\n";
@@ -92,23 +92,23 @@ int MonsterLogic::attack(MONSTER &m, PLAYER &p) {
return 1;
}
-void MonsterLogic::move(MONSTER &m, PLAYER &p, DUNGEONMAP &d) {
+void MonsterLogic::move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d) {
int x, y, xi, yi;
// Calculate direction
xi = yi = 0;
- if (p.Dungeon.x != m.Loc.x)
- xi = (p.Dungeon.x > m.Loc.x) ? 1 : -1;
- if (p.Dungeon.y != m.Loc.y)
- yi = (p.Dungeon.y > m.Loc.y) ? 1 : -1;
+ if (p.Dungeon.x != m._loc.x)
+ xi = (p.Dungeon.x > m._loc.x) ? 1 : -1;
+ if (p.Dungeon.y != m._loc.y)
+ yi = (p.Dungeon.y > m._loc.y) ? 1 : -1;
// Running away
- if (m.Strength < p.Level * p.Skill) {
+ if (m._strength < p.Level * p.Skill) {
xi = -xi; yi = -yi;
}
// Get position
- x = m.Loc.x; y = m.Loc.y;
+ x = m._loc.x; y = m._loc.y;
// Check move okay
if (ABS(xi) > ABS(yi)) {
@@ -127,11 +127,11 @@ void MonsterLogic::move(MONSTER &m, PLAYER &p, DUNGEONMAP &d) {
return;
if (x == p.Dungeon.x && // Can't move onto us
y == p.Dungeon.y) return;
- m.Loc.x = x; m.Loc.y = y; // Move to new position
+ m._loc.x = x; m._loc.y = y; // Move to new position
}
-bool MonsterLogic::canMoveTo(DUNGEONMAP &d, int x, int y) {
- COORD c;
+bool MonsterLogic::canMoveTo(DungeonMapInfo &d, int x, int y) {
+ Common::Point c;
int t = d.Map[x][y]; // See what's there
if (!ISWALKTHRU(t)) return 0; // Can't walk through walls
c.x = x; c.y = y; // Set up coord structure
@@ -140,16 +140,16 @@ bool MonsterLogic::canMoveTo(DUNGEONMAP &d, int x, int y) {
return d.findMonster(c) < 0;
}
-int MonsterLogic::steal(MONSTER &m, PLAYER &p) {
+int MonsterLogic::steal(MonsterEntry &m, PlayerInfo &p) {
int n;
const char *s1, *s2;
- if (m.Type == MN_GREMLIN) {
+ if (m._type == MN_GREMLIN) {
// HALVES the food.... aargh
p.Object[OB_FOOD] = floor(p.Object[OB_FOOD]) / 2.0;
showLines("A Gremlin stole some food.\n");
- } else if (m.Type == MN_THIEF) {
+ } else if (m._type == MN_THIEF) {
// Figure out what stolen
do {
n = urand() % p.Objects;
diff --git a/engines/ultima/ultima0/data/monster_logic.h b/engines/ultima/ultima0/data/monster_logic.h
index 5560133c1ce..5b7a6f7f8bc 100644
--- a/engines/ultima/ultima0/data/monster_logic.h
+++ b/engines/ultima/ultima0/data/monster_logic.h
@@ -37,28 +37,28 @@ private:
/**
* Monster Attacks
*/
- static int attack(MONSTER &m, PLAYER &p);
+ static int attack(MonsterEntry &m, PlayerInfo &p);
/**
* Monster Moves
*/
- static void move(MONSTER &m, PLAYER &p, DUNGEONMAP &d);
+ static void move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d);
/**
* Can monster move to a square
*/
- static bool canMoveTo(DUNGEONMAP &d, int x, int y);
+ static bool canMoveTo(DungeonMapInfo &d, int x, int y);
/**
* Monster Stealing
*/
- static int steal(MONSTER &m, PLAYER &p);
+ static int steal(MonsterEntry &m, PlayerInfo &p);
public:
/**
* Check Monsters Attacking
*/
- static void checkForAttacks(PLAYER &p, DUNGEONMAP &d);
+ static void checkForAttacks(PlayerInfo &p, DungeonMapInfo &d);
};
} // namespace Ultima0
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index b0b88d0b5df..8c1335dfc6c 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -47,7 +47,7 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
double Level = 0;
Common::Rect rIn, rOut;
- COORD Dir, Pos, Next;
+ Common::Point Dir, Pos, Next;
int Monster, Front, Left, Right;
_DDRAWCalcRect(s, &rOut, 0);
Pos = player.Dungeon; // Get position
@@ -68,7 +68,7 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
// Check for monster present
Monster = dungeon.findMonster(Pos);
if (Monster >= 0)
- Monster = dungeon.Monster[Monster].Type;
+ Monster = dungeon.Monster[Monster]._type;
// Draw the dungeon
DRAWDungeon(s, &rOut, &rIn, Left, Front, Right,
@@ -91,7 +91,7 @@ void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, doubl
r->bottom = centerY + yWidth / 2;
}
-void Dungeon::MOVERotLeft(COORD *Dir) {
+void Dungeon::MOVERotLeft(Common::Point *Dir) {
int t;
if (Dir->y == 0) Dir->x = -Dir->x;
t = Dir->x;
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
index 2534dc80a9f..9c8c69b1d25 100644
--- a/engines/ultima/ultima0/gfx/dungeon.h
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -42,7 +42,7 @@ private:
/**
* Rotate a direction left
*/
- static void MOVERotLeft(COORD *Dir);
+ static void MOVERotLeft(Common::Point *Dir);
/**
* Draw part of dungeon
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 65524f058e3..999b1072977 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -46,9 +46,9 @@ protected:
public:
Graphics::Palette _palette;
- PLAYER _player;
- WORLDMAP _worldMap;
- DUNGEONMAP _dungeon;
+ PlayerInfo _player;
+ WorldMapInfo _worldMap;
+ DungeonMapInfo _dungeon;
bool _showMinimap = false;
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index 49fcf3adcd7..6156c4731d2 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -215,7 +215,7 @@ void Attack::selectMagic(int magicNum) {
void Attack::attackMissile() {
const auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
- COORD c1, c = player.Dungeon;
+ Common::Point c1, c = player.Dungeon;
int Dist = -1;
// A maximum distance of 5
@@ -244,22 +244,22 @@ void Attack::attackMissile() {
void Attack::attackWeapon() {
const auto &player = g_engine->_player;
- COORD c = player.Dungeon + player.DungDir;
+ Common::Point c = player.Dungeon + player.DungDir;
attackHitMonster(c);
}
-void Attack::attackHitMonster(const COORD &c) {
+void Attack::attackHitMonster(const Common::Point &c) {
auto &player = g_engine->_player;
auto &dungeon = g_engine->_dungeon;
int n = 0, Monster, Damage;
- MONSTER *m = nullptr;
+ MonsterEntry *m = nullptr;
// Is there a monster there ?
Monster = dungeon.findMonster(c);
if (Monster >= 0) {
// Set up a pointer
m = &dungeon.Monster[Monster];
- n = m->Type;
+ n = m->_type;
}
// Get weaponry info
@@ -288,23 +288,23 @@ void Attack::attackHitMonster(const COORD &c) {
if (Damage > 0)
n = (urand() % Damage);
n = n + player.Attr[AT_STRENGTH] / 5;
- m->Strength = m->Strength - n; // Lose them
+ m->_strength = m->_strength - n; // Lose them
- if (m->Strength < 0)
- m->Strength = 0;
+ if (m->_strength < 0)
+ m->_strength = 0;
_message += Common::String::format("%s's Hit\nPoints now %d.\n",
- MONSTER_INFO[m->Type].Name, m->Strength);
+ MONSTER_INFO[m->_type].Name, m->_strength);
// Killed it ?
- if (m->Strength == 0) {
- m->Alive = 0; // It has ceased to be
- int gold = (m->Type + player.Level); // Amount of gold
+ if (m->_strength == 0) {
+ m->_alive = false; // It has ceased to be
+ int gold = (m->_type + player.Level); // Amount of gold
_message += Common::String::format("You get %d pieces of eight.\n", gold);
player.Attr[AT_GOLD] += gold;
- player.HPGain += (m->Type * player.Level) / 2; // Calculate Gain
+ player.HPGain += (m->_type * player.Level) / 2; // Calculate Gain
- if (m->Type == player.Task) // Check done LB's task
+ if (m->_type == player.Task) // Check done LB's task
player.TaskCompleted = 1;
}
diff --git a/engines/ultima/ultima0/views/attack.h b/engines/ultima/ultima0/views/attack.h
index b57115fe442..fbc58851c8b 100644
--- a/engines/ultima/ultima0/views/attack.h
+++ b/engines/ultima/ultima0/views/attack.h
@@ -43,7 +43,7 @@ private:
void selectMagic(int magicNum);
void attackMissile();
void attackWeapon();
- void attackHitMonster(const COORD &c);
+ void attackHitMonster(const Common::Point &c);
void showMessage(const Common::String &msg);
public:
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 200c59540f3..bfdedb7ec74 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -75,7 +75,7 @@ void Dungeon::drawMinimap(Graphics::ManagedSurface &mapArea) {
(x + 1) * MINIMAP_TILE_SIZE, (y + 1) * MINIMAP_TILE_SIZE);
if (x == player.Dungeon.x && y == player.Dungeon.y) {
mapArea.fillRect(r, C_CYAN);
- } else if (dungeon.findMonster(COORD(x, y)) > 0) {
+ } else if (dungeon.findMonster(Common::Point(x, y)) > 0) {
mapArea.fillRect(r, C_RED);
} else {
tile = dungeon.Map[x][y];
@@ -187,7 +187,7 @@ void Dungeon::endOfTurn() {
void Dungeon::moveForward() {
auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
- COORD New = player.Dungeon + player.DungDir;
+ Common::Point New = player.Dungeon + player.DungDir;
if (!ISWALKTHRU(dungeon.Map[New.x][New.y]) || dungeon.findMonster(New) >= 0)
return;
Commit: 3e04f40bbb55b903d5b1629929a3ef52b444ecfa
https://github.com/scummvm/scummvm/commit/3e04f40bbb55b903d5b1629929a3ef52b444ecfa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:30+11:00
Commit Message:
ULTIMA: ULTIMA0: Janitorial
Changed paths:
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/dungeon.h
engines/ultima/ultima0/gfx/map.cpp
engines/ultima/ultima0/gfx/monster.cpp
engines/ultima/ultima0/gfx/monster.h
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 8c1335dfc6c..6489ad68a6a 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -27,11 +27,11 @@ namespace Ultima {
namespace Ultima0 {
namespace Gfx {
-int Dungeon::xLeft;
-int Dungeon::xRight;
-int Dungeon::yBottom;
-int Dungeon::yDiffLeft;
-int Dungeon::yDiffRight;
+int Dungeon::_xLeft;
+int Dungeon::_xRight;
+int Dungeon::_yBottom;
+int Dungeon::_yDiffLeft;
+int Dungeon::_yDiffRight;
#define HWColour(IDX) color = IDX
#define X(n) (x1 + w * (n)/10)
@@ -47,42 +47,42 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
double Level = 0;
Common::Rect rIn, rOut;
- Common::Point Dir, Pos, Next;
- int Monster, Front, Left, Right;
+ Common::Point dir, pos, next;
+ int monster, front, left, right;
_DDRAWCalcRect(s, &rOut, 0);
- Pos = player.Dungeon; // Get position
+ pos = player.Dungeon; // Get position
// Iterate through drawing successively distinct tiles in the facing direction
do {
Level++; // Next level
_DDRAWCalcRect(s, &rIn, Level);
- Next.x = Pos.x + player.DungDir.x; // Next position
- Next.y = Pos.y + player.DungDir.y;
+ next.x = pos.x + player.DungDir.x; // Next position
+ next.y = pos.y + player.DungDir.y;
- Dir = player.DungDir; MOVERotLeft(&Dir); // To the left
- Left = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
- MOVERotLeft(&Dir); MOVERotLeft(&Dir); // To the right
- Right = dungeon.Map[Pos.x + Dir.x][Pos.y + Dir.y];
- Front = dungeon.Map[Next.x][Next.y]; // What's in front ?
+ dir = player.DungDir; MOVERotLeft(&dir); // To the left
+ left = dungeon.Map[pos.x + dir.x][pos.y + dir.y];
+ MOVERotLeft(&dir); MOVERotLeft(&dir); // To the right
+ right = dungeon.Map[pos.x + dir.x][pos.y + dir.y];
+ front = dungeon.Map[next.x][next.y]; // What's in front ?
// Check for monster present
- Monster = dungeon.findMonster(Pos);
- if (Monster >= 0)
- Monster = dungeon.Monster[Monster]._type;
+ monster = dungeon.findMonster(pos);
+ if (monster >= 0)
+ monster = dungeon.Monster[monster]._type;
// Draw the dungeon
- DRAWDungeon(s, &rOut, &rIn, Left, Front, Right,
- dungeon.Map[Pos.x][Pos.y], Monster);
+ DRAWDungeon(s, &rOut, &rIn, left, front, right,
+ dungeon.Map[pos.x][pos.y], monster);
- Pos = Next; // Next position down
+ pos = next; // Next position down
rOut = rIn; // Last in is new out
- } while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(Front));
+ } while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(front));
}
-void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double Level) {
+void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double level) {
const int centerX = s->w / 2, centerY = s->h / 2;
- int xWidth = s->w / (Level + 1);
- int yWidth = s->h / (Level + 1);
+ int xWidth = s->w / (level + 1);
+ int yWidth = s->h / (level + 1);
// Set bounding box
r->left = centerX - xWidth / 2;
@@ -91,16 +91,16 @@ void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, doubl
r->bottom = centerY + yWidth / 2;
}
-void Dungeon::MOVERotLeft(Common::Point *Dir) {
+void Dungeon::MOVERotLeft(Common::Point *dir) {
int t;
- if (Dir->y == 0) Dir->x = -Dir->x;
- t = Dir->x;
- Dir->x = Dir->y;
- Dir->y = t;
+ if (dir->y == 0) dir->x = -dir->x;
+ t = dir->x;
+ dir->x = dir->y;
+ dir->y = t;
}
void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
- Common::Rect *rIn, int Left, int Centre, int Right, int Room, int Monster) {
+ Common::Rect *rIn, int left, int centre, int right, int room, int monster) {
int x1, y1, x, y, y2;
Common::Rect r;
double Scale;
@@ -109,7 +109,7 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
HWColour(COL_WALL); // Start on the walls
// Do we draw the left edge
- if (ISDRAWOPEN(Left)) {
+ if (ISDRAWOPEN(left)) {
HWLine(rOut->left, rIn->top, rIn->left, rIn->top);
HWLine(rOut->left, rIn->bottom, rIn->left, rIn->bottom);
HWLine(rOut->left, rOut->top, rOut->left, rOut->bottom);
@@ -120,7 +120,7 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
}
// Do we draw the right edge
- if (ISDRAWOPEN(Right)) {
+ if (ISDRAWOPEN(right)) {
HWLine(rOut->right, rIn->top, rIn->right, rIn->top);
HWLine(rOut->right, rIn->bottom, rIn->right, rIn->bottom);
HWLine(rOut->right, rOut->top, rOut->right, rOut->bottom);
@@ -131,12 +131,12 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
}
// Back wall ?
- if (!ISDRAWOPEN(Centre)) {
+ if (!ISDRAWOPEN(centre)) {
HWLine(rIn->left, rIn->top, rIn->right, rIn->top);
HWLine(rIn->left, rIn->bottom, rIn->right, rIn->bottom);
- if (!ISDRAWOPEN(Left)) // Corner if left,right closed
+ if (!ISDRAWOPEN(left)) // Corner if left,right closed
HWLine(rIn->left, rIn->top, rIn->left, rIn->bottom);
- if (!ISDRAWOPEN(Right))
+ if (!ISDRAWOPEN(right))
HWLine(rIn->right, rIn->top, rIn->right, rIn->bottom);
}
@@ -145,27 +145,27 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
rOut->bottom,
rOut->bottom - rOut->top,
rIn->bottom - rIn->top);
- _DRAWWall(s, Left);
+ _DRAWWall(s, left);
// Set up for right side
_DRAWSetRange(rIn->right, rOut->right,
rIn->bottom,
rIn->bottom - rIn->top,
rOut->bottom - rOut->top);
- _DRAWWall(s, Right);
+ _DRAWWall(s, right);
// Set up for centre
_DRAWSetRange(rIn->left, rIn->right,
rIn->bottom,
rIn->bottom - rIn->top,
rIn->bottom - rIn->top);
- _DRAWWall(s, Centre);
+ _DRAWWall(s, centre);
- if (Room == DT_LADDERUP) {
+ if (room == DT_LADDERUP) {
r = Common::Rect(rOut->left, rOut->top, rOut->right, rIn->top);
_DRAWPit(s, &r, 1);
}
- if (Room == DT_LADDERDN || Room == DT_PIT) {
+ if (room == DT_LADDERDN || room == DT_PIT) {
r = Common::Rect(rOut->left, rIn->bottom, rOut->right, rOut->bottom);
_DRAWPit(s, &r, -1);
}
@@ -178,7 +178,7 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
(rIn->bottom + rOut->bottom) / 2);
// Ladder here ?
- if (Room == DT_LADDERUP || Room == DT_LADDERDN) {
+ if (room == DT_LADDERUP || room == DT_LADDERDN) {
HWColour(COL_LADDER);
y1 = r.top; y2 = r.bottom;
x = (r.right - r.left) * 3 / 10;
@@ -197,22 +197,22 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
Scale = 0.35 / (r.right - r.left) * s->w;
// Monster here ?
- if (Monster > 0) {
+ if (monster > 0) {
HWColour(COL_MONSTER);
- Monster::draw(s, (r.left + r.right) / 2, r.bottom, Monster, Scale);
+ Monster::draw(s, (r.left + r.right) / 2, r.bottom, monster, Scale);
}
// Draw the gold (as a mimic)
- if (Room == DT_GOLD) {
+ if (room == DT_GOLD) {
HWColour(COL_MONSTER);
Monster::draw(s, (r.left + r.right) / 2, r.top, MN_MIMIC, Scale);
}
}
void Dungeon::_DRAWSetRange(int x1, int x2, int y, int yd1, int yd2) {
- xLeft = x1; xRight = x2; // Set x ranges
- yBottom = y; // Set lower left y value
- yDiffLeft = yd1; yDiffRight = yd2; // Set difference for either end
+ _xLeft = x1; _xRight = x2; // Set x ranges
+ _yBottom = y; // Set lower left y value
+ _yDiffLeft = yd1; _yDiffRight = yd2; // Set difference for either end
}
void Dungeon::_DRAWWall(Graphics::ManagedSurface *s, int n) {
@@ -234,13 +234,13 @@ void Dungeon::_DRAWWall(Graphics::ManagedSurface *s, int n) {
void Dungeon::_DRAWConvert(int *px, int *py) {
long x, y, yd; // Longs for overflow in 16 bit
- x = (xRight - xLeft); // Calculate width
- x = x * (*px) / 100 + xLeft; // Work out horiz value
- yd = (yDiffRight - yDiffLeft); // Work out height of vert for x
+ x = (_xRight - _xLeft); // Calculate width
+ x = x * (*px) / 100 + _xLeft; // Work out horiz value
+ yd = (_yDiffRight - _yDiffLeft); // Work out height of vert for x
yd = yd * (*px) / 100;
- y = yBottom + // Half of the distance
+ y = _yBottom + // Half of the distance
yd / 2 - // + Scaled total size
- (yd + yDiffLeft) * (*py) / 100;
+ (yd + _yDiffLeft) * (*py) / 100;
*px = (int)x; // Write back, casting to int
*py = (int)y;
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
index 9c8c69b1d25..c7770a4f5a4 100644
--- a/engines/ultima/ultima0/gfx/dungeon.h
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -32,7 +32,7 @@ namespace Gfx {
class Dungeon {
private:
// Slanted drawing constants
- static int xLeft, xRight, yBottom, yDiffLeft, yDiffRight;
+ static int _xLeft, _xRight, _yBottom, _yDiffLeft, _yDiffRight;
/**
* Calculate display rectangle
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
index 28dc76ef801..73f5faa0eef 100644
--- a/engines/ultima/ultima0/gfx/map.cpp
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -32,13 +32,13 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
s->clear();
- int x, y, x1, y1, w, h, Grid;
+ int x, y, x1, y1, w, h, grid;
Common::Rect r;
- Grid = showAsMap ? WORLD_MAP_SIZE : (g_engine->isEnhanced() ? 7 : 3);
- w = s->w / Grid; h = s->h / Grid; // Get grid sizes
+ grid = showAsMap ? WORLD_MAP_SIZE : (g_engine->isEnhanced() ? 7 : 3);
+ w = s->w / grid; h = s->h / grid; // Get grid sizes
- for (x = 0; x < Grid; x++) {
- for (y = 0; y < Grid; y++) {
+ for (x = 0; x < grid; x++) {
+ for (y = 0; y < grid; y++) {
r = Common::Rect(x * w, y * h, x * w + w - 1, y * h + h - 1);
if (showAsMap) {
@@ -46,8 +46,8 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
x1 = x, y1 = y;
} else {
// Which cell?
- x1 = player.World.x - Grid / 2 + x;
- y1 = player.World.y - Grid / 2 + y;
+ x1 = player.World.x - grid / 2 + x;
+ y1 = player.World.y - grid / 2 + y;
}
DRAWTile(s, r, map.read(x1, y1));
@@ -65,7 +65,7 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
-void Map::DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int Obj) {
+void Map::DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj) {
int x1 = r.left;
int y1 = r.top;
int w = r.width();
@@ -73,7 +73,7 @@ void Map::DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int Obj)
byte color = 0;
// Decide on the object
- switch (Obj) {
+ switch (obj) {
case WT_SPACE:
// Space does nothing at all
break;
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index 18bab460133..d6262ef33a1 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -27,11 +27,11 @@ namespace Ultima0 {
namespace Gfx {
Monster::DrawFn Monster::DRAW_FUNCTIONS[] = {
- nullptr, _DRAWSkeleton, _DRAWThief, _DRAWRat, _DRAWOrc, _DRAWViper,
- _DRAWCarrion, _DRAWGremlin, _DRAWMimic, _DRAWDaemon, _DRAWBalrog
+ nullptr, drawSkeleton, drawThief, drawRat, drawOrc, drawViper,
+ drawCarrion, drawGremlin, drawMimic, drawDaemon, drawBalrog
};
-int Monster::xPos = 640;
-int Monster::yPos = 512;
+int Monster::_xPos = 640;
+int Monster::_yPos = 512;
constexpr int color = COL_MONSTER;
#define END (-9999.99) /* End marker */
@@ -41,20 +41,19 @@ constexpr int color = COL_MONSTER;
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
-void Monster::draw(Graphics::ManagedSurface *s, int x, int y,
- int Monster, double Scale) {
+void Monster::draw(Graphics::ManagedSurface *s, int x, int y, int monster, double scale) {
// Save drawing pos
- xPos = x; yPos = y;
- if (Monster == MN_MIMIC)
+ _xPos = x; _yPos = y;
+ if (monster == MN_MIMIC)
// Fix for Mimic/Chest
- xPos = xPos - 90;
+ _xPos = _xPos - 90;
// Call appropriate function
- assert(Monster > 0 && Monster <= MN_BALROG);
- (*DRAW_FUNCTIONS[Monster])(s, 0, 0, Scale);
+ assert(monster > 0 && monster <= MN_BALROG);
+ (*DRAW_FUNCTIONS[monster])(s, 0, 0, scale);
}
-void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
+void Monster::hPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
va_list alist;
double y1, x1;
@@ -65,132 +64,132 @@ void Monster::_HPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
x1 = va_arg(alist, double); // Get the next two
y1 = va_arg(alist, double);
if (x1 != END && y1 != END) // If legit, draw the line
- HWLine(xPos + x, yPos + y, xPos + x1, yPos + y1);
+ HWLine(_xPos + x, _yPos + y, _xPos + x1, _yPos + y1);
x = x1; y = y1;
} while (x1 != END && y1 != END);
va_end(alist);
}
-void Monster::_DRAWSkeleton(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y - 23 / d, x, y - 15 / d, x, y - 15 / d, x - 15 / d, y - 8 / d, x - 30 / d, y + 8 / d, x - 30 / d, y + 15 / d, x - 15 / d, y + 15 / d, x, y + 23 / d, x, END, END);
- _HPlot(s, y, x - 26 / d, y, x - 65 / d, END, END);
- _HPlot(s, y - 2 / d + .5, x - 38 / d, y + 2 / d + .5, x - 38 / d, END, END);
- _HPlot(s, y - 3 / d + .5, x - 45 / d, y + 3 / d + .5, x - 45 / d, END, END);
- _HPlot(s, y - 5 / d + .5, x - 53 / d, y + 5 / d + .5, x - 53 / d, END, END);
- _HPlot(s, y - 23 / d, x - 56 / d, y - 30 / d, x - 53 / d, y - 23 / d, x - 45 / d, y - 23 / d, x - 53 / d, y - 8 / d, x - 38 / d, END, END);
- _HPlot(s, y - 15 / d, x - 45 / d, y - 8 / d, x - 60 / d, y + 8 / d, x - 60 / d, y + 15 / d, x - 45 / d, END, END);
- _HPlot(s, y + 15 / d, x - 42 / d, y + 15 / d, x - 57 / d, END, END);
- _HPlot(s, y + 12 / d, x - 45 / d, y + 20 / d, x - 45 / d, END, END);
- _HPlot(s, y, x - 75 / d, y - 5 / d + .5, x - 80 / d, y - 8 / d, x - 75 / d, y - 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 65 / d, END, END);
- _HPlot(s, y + 5 / d + .5, x - 65 / d, y + 8 / d, x - 75 / d, y + 5 / d + .5, x - 80 / d, y - 5 / d + .5, x - 80 / d, END, END);
- _HPlot(s, y - 5 / d + .5, x - 72 / d, END, END);
- _HPlot(s, y + 5 / d + .5, x - 72 / d, END, END);
+void Monster::drawSkeleton(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y - 23 / d, x, y - 15 / d, x, y - 15 / d, x - 15 / d, y - 8 / d, x - 30 / d, y + 8 / d, x - 30 / d, y + 15 / d, x - 15 / d, y + 15 / d, x, y + 23 / d, x, END, END);
+ hPlot(s, y, x - 26 / d, y, x - 65 / d, END, END);
+ hPlot(s, y - 2 / d + .5, x - 38 / d, y + 2 / d + .5, x - 38 / d, END, END);
+ hPlot(s, y - 3 / d + .5, x - 45 / d, y + 3 / d + .5, x - 45 / d, END, END);
+ hPlot(s, y - 5 / d + .5, x - 53 / d, y + 5 / d + .5, x - 53 / d, END, END);
+ hPlot(s, y - 23 / d, x - 56 / d, y - 30 / d, x - 53 / d, y - 23 / d, x - 45 / d, y - 23 / d, x - 53 / d, y - 8 / d, x - 38 / d, END, END);
+ hPlot(s, y - 15 / d, x - 45 / d, y - 8 / d, x - 60 / d, y + 8 / d, x - 60 / d, y + 15 / d, x - 45 / d, END, END);
+ hPlot(s, y + 15 / d, x - 42 / d, y + 15 / d, x - 57 / d, END, END);
+ hPlot(s, y + 12 / d, x - 45 / d, y + 20 / d, x - 45 / d, END, END);
+ hPlot(s, y, x - 75 / d, y - 5 / d + .5, x - 80 / d, y - 8 / d, x - 75 / d, y - 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 65 / d, END, END);
+ hPlot(s, y + 5 / d + .5, x - 65 / d, y + 8 / d, x - 75 / d, y + 5 / d + .5, x - 80 / d, y - 5 / d + .5, x - 80 / d, END, END);
+ hPlot(s, y - 5 / d + .5, x - 72 / d, END, END);
+ hPlot(s, y + 5 / d + .5, x - 72 / d, END, END);
}
-void Monster::_DRAWThief(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y, x - 56 / d, y, x - 8 / d, y + 10 / d, x, y + 30 / d, x, y + 30 / d, x - 45 / d, y + 10 / d, x - 64 / d, y, x - 56 / d, END, END);
- _HPlot(s, y - 10 / d, x - 64 / d, y - 30 / d, x - 45 / d, y - 30 / d, x, y - 10 / d, x, y, x - 8 / d, END, END);
- _HPlot(s, y - 10 / d, x - 64 / d, y - 10 / d, x - 75 / d, y, x - 83 / d, y + 10 / d, x - 75 / d, y, x - 79 / d, y - 10 / d, x - 75 / d, y, x - 60 / d, y + 10 / d, x - 75 / d, y + 10 / d, x - 64 / d, END, END);
+void Monster::drawThief(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y, x - 56 / d, y, x - 8 / d, y + 10 / d, x, y + 30 / d, x, y + 30 / d, x - 45 / d, y + 10 / d, x - 64 / d, y, x - 56 / d, END, END);
+ hPlot(s, y - 10 / d, x - 64 / d, y - 30 / d, x - 45 / d, y - 30 / d, x, y - 10 / d, x, y, x - 8 / d, END, END);
+ hPlot(s, y - 10 / d, x - 64 / d, y - 10 / d, x - 75 / d, y, x - 83 / d, y + 10 / d, x - 75 / d, y, x - 79 / d, y - 10 / d, x - 75 / d, y, x - 60 / d, y + 10 / d, x - 75 / d, y + 10 / d, x - 64 / d, END, END);
}
-void Monster::_DRAWRat(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y + 5 / d, x - 30 / d, y, x - 25 / d, y - 5 / d, x - 30 / d, y - 15 / d, x - 5 / d, y - 10 / d, x, y + 10 / d, x, y + 15 / d, x - 5 / d, END, END);
- _HPlot(s, y + 20 / d, x - 5 / d, y + 10 / d, x, y + 15 / d, x - 5 / d, y + 5 / d, x - 30 / d, y + 10 / d, x - 40 / d, y + 3 / d + .5, x - 35 / d, y - 3 / d + .5, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 30 / d, END, END);
- _HPlot(s, y - 5 / d, x - 33 / d, y - 3 / d + .5, x - 30 / d, END, END);
- _HPlot(s, y + 5 / d, x - 33 / d, y + 3 / d + .5, x - 30 / d, END, END);
- _HPlot(s, y - 5 / d, x - 20 / d, y - 5 / d, x - 15 / d, END, END);
- _HPlot(s, y + 5 / d, x - 20 / d, y + 5 / d, x - 15 / d, END, END);
- _HPlot(s, y - 7 / d, x - 20 / d, y - 7 / d, x - 15 / d, END, END);
- _HPlot(s, y + 7 / d, x - 20 / d, y + 7 / d, x - 15 / d, END, END);
+void Monster::drawRat(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y + 5 / d, x - 30 / d, y, x - 25 / d, y - 5 / d, x - 30 / d, y - 15 / d, x - 5 / d, y - 10 / d, x, y + 10 / d, x, y + 15 / d, x - 5 / d, END, END);
+ hPlot(s, y + 20 / d, x - 5 / d, y + 10 / d, x, y + 15 / d, x - 5 / d, y + 5 / d, x - 30 / d, y + 10 / d, x - 40 / d, y + 3 / d + .5, x - 35 / d, y - 3 / d + .5, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 30 / d, END, END);
+ hPlot(s, y - 5 / d, x - 33 / d, y - 3 / d + .5, x - 30 / d, END, END);
+ hPlot(s, y + 5 / d, x - 33 / d, y + 3 / d + .5, x - 30 / d, END, END);
+ hPlot(s, y - 5 / d, x - 20 / d, y - 5 / d, x - 15 / d, END, END);
+ hPlot(s, y + 5 / d, x - 20 / d, y + 5 / d, x - 15 / d, END, END);
+ hPlot(s, y - 7 / d, x - 20 / d, y - 7 / d, x - 15 / d, END, END);
+ hPlot(s, y + 7 / d, x - 20 / d, y + 7 / d, x - 15 / d, END, END);
}
-void Monster::_DRAWOrc(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y, x, y - 15 / d, x, y - 8 / d, x - 8 / d, y - 8 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 23 / d, END, END);
- _HPlot(s, y - 23 / d, x - 45 / d, y - 15 / d, x - 53 / d, y - 8 / d, x - 53 / d, y - 15 / d, x - 68 / d, y - 8 / d, x - 75 / d, y, x - 75 / d, END, END);
- _HPlot(s, y, x, y + 15 / d, x, y + 8 / d, x - 8 / d, y + 8 / d, x - 15 / d, y + 15 / d, x - 23 / d, y + 15 / d, x - 15 / d, y + 23 / d, x - 23 / d, END, END);
- _HPlot(s, y + 23 / d, x - 45 / d, y + 15 / d, x - 53 / d, y + 8 / d, x - 53 / d, y + 15 / d, x - 68 / d, y + 8 / d, x - 75 / d, y, x - 75 / d, END, END);
- _HPlot(s, y - 15 / d, x - 68 / d, y + 15 / d, x - 68 / d, END, END);
- _HPlot(s, y - 8 / d, x - 53 / d, y + 8 / d, x - 53 / d, END, END);
- _HPlot(s, y - 23 / d, x - 15 / d, y + 8 / d, x - 45 / d, END, END);
- _HPlot(s, y - 8 / d, x - 68 / d, y, x - 60 / d, y + 8 / d, x - 68 / d, y + 8 / d, x - 60 / d, y - 8 / d, x - 60 / d, y - 8 / d, x - 68 / d, END, END);
- _HPlot(s, y, x - 38 / d, y - 8 / d, x - 38 / d, y + 8 / d, x - 53 / d, y + 8 / d, x - 45 / d, y + 15 / d, x - 45 / d, y, x - 30 / d, y, x - 38 / d, END, END);
+void Monster::drawOrc(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y, x, y - 15 / d, x, y - 8 / d, x - 8 / d, y - 8 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 23 / d, END, END);
+ hPlot(s, y - 23 / d, x - 45 / d, y - 15 / d, x - 53 / d, y - 8 / d, x - 53 / d, y - 15 / d, x - 68 / d, y - 8 / d, x - 75 / d, y, x - 75 / d, END, END);
+ hPlot(s, y, x, y + 15 / d, x, y + 8 / d, x - 8 / d, y + 8 / d, x - 15 / d, y + 15 / d, x - 23 / d, y + 15 / d, x - 15 / d, y + 23 / d, x - 23 / d, END, END);
+ hPlot(s, y + 23 / d, x - 45 / d, y + 15 / d, x - 53 / d, y + 8 / d, x - 53 / d, y + 15 / d, x - 68 / d, y + 8 / d, x - 75 / d, y, x - 75 / d, END, END);
+ hPlot(s, y - 15 / d, x - 68 / d, y + 15 / d, x - 68 / d, END, END);
+ hPlot(s, y - 8 / d, x - 53 / d, y + 8 / d, x - 53 / d, END, END);
+ hPlot(s, y - 23 / d, x - 15 / d, y + 8 / d, x - 45 / d, END, END);
+ hPlot(s, y - 8 / d, x - 68 / d, y, x - 60 / d, y + 8 / d, x - 68 / d, y + 8 / d, x - 60 / d, y - 8 / d, x - 60 / d, y - 8 / d, x - 68 / d, END, END);
+ hPlot(s, y, x - 38 / d, y - 8 / d, x - 38 / d, y + 8 / d, x - 53 / d, y + 8 / d, x - 45 / d, y + 15 / d, x - 45 / d, y, x - 30 / d, y, x - 38 / d, END, END);
}
-void Monster::_DRAWViper(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y - 10 / d, x - 15 / d, y - 10 / d, x - 30 / d, y - 15 / d, x - 20 / d, y - 15 / d, x - 15 / d, y - 15 / d, x, y + 15 / d, x, y + 15 / d, x - 15 / d, y - 15 / d, x - 15 / d, END, END);
- _HPlot(s, y - 15 / d, x - 10 / d, y + 15 / d, x - 10 / d, END, END);
- _HPlot(s, y - 15 / d, x - 5 / d, y + 15 / d, x - 5 / d, END, END);
- _HPlot(s, y, x - 15 / d, y - 5 / d, x - 20 / d, y - 5 / d, x - 35 / d, y + 5 / d, x - 35 / d, y + 5 / d, x - 20 / d, y + 10 / d, x - 15 / d, END, END);
- _HPlot(s, y - 5 / d, x - 20 / d, y + 5 / d, x - 20 / d, END, END);
- _HPlot(s, y - 5 / d, x - 25 / d, y + 5 / d, x - 25 / d, END, END);
- _HPlot(s, y - 5 / d, x - 30 / d, y + 5 / d, x - 30 / d, END, END);
- _HPlot(s, y - 10 / d, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 45 / d, y + 5 / d, x - 45 / d, y + 10 / d, x - 40 / d, y + 10 / d, x - 35 / d, END, END);
- _HPlot(s, y - 10 / d, x - 40 / d, y, x - 45 / d, y + 10 / d, x - 40 / d, END, END);
- _HPlot(s, y - 5 / d, x - 40 / d, y + 5 / d, x - 40 / d, y + 15 / d, x - 30 / d, y, x - 40 / d, y - 15 / d, x - 30 / d, y - 5 / d + .5, x - 40 / d, END, END);
+void Monster::drawViper(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y - 10 / d, x - 15 / d, y - 10 / d, x - 30 / d, y - 15 / d, x - 20 / d, y - 15 / d, x - 15 / d, y - 15 / d, x, y + 15 / d, x, y + 15 / d, x - 15 / d, y - 15 / d, x - 15 / d, END, END);
+ hPlot(s, y - 15 / d, x - 10 / d, y + 15 / d, x - 10 / d, END, END);
+ hPlot(s, y - 15 / d, x - 5 / d, y + 15 / d, x - 5 / d, END, END);
+ hPlot(s, y, x - 15 / d, y - 5 / d, x - 20 / d, y - 5 / d, x - 35 / d, y + 5 / d, x - 35 / d, y + 5 / d, x - 20 / d, y + 10 / d, x - 15 / d, END, END);
+ hPlot(s, y - 5 / d, x - 20 / d, y + 5 / d, x - 20 / d, END, END);
+ hPlot(s, y - 5 / d, x - 25 / d, y + 5 / d, x - 25 / d, END, END);
+ hPlot(s, y - 5 / d, x - 30 / d, y + 5 / d, x - 30 / d, END, END);
+ hPlot(s, y - 10 / d, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 45 / d, y + 5 / d, x - 45 / d, y + 10 / d, x - 40 / d, y + 10 / d, x - 35 / d, END, END);
+ hPlot(s, y - 10 / d, x - 40 / d, y, x - 45 / d, y + 10 / d, x - 40 / d, END, END);
+ hPlot(s, y - 5 / d, x - 40 / d, y + 5 / d, x - 40 / d, y + 15 / d, x - 30 / d, y, x - 40 / d, y - 15 / d, x - 30 / d, y - 5 / d + .5, x - 40 / d, END, END);
}
-void Monster::_DRAWCarrion(Graphics::ManagedSurface *s, double x, double y, double d) {
+void Monster::drawCarrion(Graphics::ManagedSurface *s, double x, double y, double d) {
/* 79-dst.recty(d) line here */
- _HPlot(s, y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
- _HPlot(s, y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
- _HPlot(s, y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
- _HPlot(s, y - 15 / d, x - 86 / d, y - 20 / d, x - 83 / d, y - 20 / d, x - 78 / d, y - 30 / d, x - 73 / d, y - 30 / d, x - 68 / d, y - 20 / d, x - 63 / d, END, END);
- _HPlot(s, y - 10 / d, x - 83 / d, y - 10 / d, x - 58 / d, y, x - 50 / d, END, END);
- _HPlot(s, y + 10 / d, x - 83 / d, y + 10 / d, x - 78 / d, y + 20 / d, x - 73 / d, y + 20 / d, x - 40 / d, END, END);
- _HPlot(s, y + 15 / d, x - 85 / d, y + 20 / d, x - 78 / d, y + 30 / d, x - 76 / d, y + 30 / d, x - 60 / d, END, END);
- _HPlot(s, y, x - 83 / d, y, x - 73 / d, y + 10 / d, x - 68 / d, y + 10 / d, x - 63 / d, y, x - 58 / d, END, END);
+ hPlot(s, y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
+ hPlot(s, y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
+ hPlot(s, y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
+ hPlot(s, y - 15 / d, x - 86 / d, y - 20 / d, x - 83 / d, y - 20 / d, x - 78 / d, y - 30 / d, x - 73 / d, y - 30 / d, x - 68 / d, y - 20 / d, x - 63 / d, END, END);
+ hPlot(s, y - 10 / d, x - 83 / d, y - 10 / d, x - 58 / d, y, x - 50 / d, END, END);
+ hPlot(s, y + 10 / d, x - 83 / d, y + 10 / d, x - 78 / d, y + 20 / d, x - 73 / d, y + 20 / d, x - 40 / d, END, END);
+ hPlot(s, y + 15 / d, x - 85 / d, y + 20 / d, x - 78 / d, y + 30 / d, x - 76 / d, y + 30 / d, x - 60 / d, END, END);
+ hPlot(s, y, x - 83 / d, y, x - 73 / d, y + 10 / d, x - 68 / d, y + 10 / d, x - 63 / d, y, x - 58 / d, END, END);
}
-void Monster::_DRAWGremlin(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y + 5 / d + .5, x - 10 / d, y - 5 / d + .5, x - 10 / d, y, x - 15 / d, y + 10 / d, x - 20 / d, y + 5 / d + .5, x - 15 / d, y + 5 / d + .5, x - 10 / d, END, END);
- _HPlot(s, y + 7 / d + .5, x - 6 / d, y + 5 / d + .5, x - 3 / d, y - 5 / d + .5, x - 3 / d, y - 7 / d + .5, x - 6 / d, y - 5 / d + .5, x - 10 / d, END, END);
- _HPlot(s, y + 2 / d + .5, x - 3 / d, y + 5 / d + .5, x, y + 8 / d, x, END, END);
- _HPlot(s, y - 2 / d + .5, x - 3 / d, y - 5 / d + .5, x, y - 8 / d, x, END, END);
- _HPlot(s, y + 3 / d + .5, x - 8 / d, END, END);
- _HPlot(s, y - 3 / d + .5, x - 8 / d, END, END);
- _HPlot(s, y + 3 / d + .5, x - 5 / d, y - 3 / d + .5, x - 5 / d, END, END);
+void Monster::drawGremlin(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y + 5 / d + .5, x - 10 / d, y - 5 / d + .5, x - 10 / d, y, x - 15 / d, y + 10 / d, x - 20 / d, y + 5 / d + .5, x - 15 / d, y + 5 / d + .5, x - 10 / d, END, END);
+ hPlot(s, y + 7 / d + .5, x - 6 / d, y + 5 / d + .5, x - 3 / d, y - 5 / d + .5, x - 3 / d, y - 7 / d + .5, x - 6 / d, y - 5 / d + .5, x - 10 / d, END, END);
+ hPlot(s, y + 2 / d + .5, x - 3 / d, y + 5 / d + .5, x, y + 8 / d, x, END, END);
+ hPlot(s, y - 2 / d + .5, x - 3 / d, y - 5 / d + .5, x, y - 8 / d, x, END, END);
+ hPlot(s, y + 3 / d + .5, x - 8 / d, END, END);
+ hPlot(s, y - 3 / d + .5, x - 8 / d, END, END);
+ hPlot(s, y + 3 / d + .5, x - 5 / d, y - 3 / d + .5, x - 5 / d, END, END);
}
-void Monster::_DRAWMimic(Graphics::ManagedSurface *s, double x, double y, double d) {
+void Monster::drawMimic(Graphics::ManagedSurface *s, double x, double y, double d) {
double xx = x;
- _HPlot(s, 139 - 10 / d, xx, 139 - 10 / d, xx - 10 / d, 139 + 10 / d, xx - 10 / d, 139 + 10 / d, xx, 139 - 10 / d, xx, END, END);
- _HPlot(s, 139 - 10 / d, xx - 10 / d, 139 - 5 / d, xx - 15 / d, 139 + 15 / d, xx - 15 / d, 139 + 15 / d, xx - 5 / d, 139 + 10 / d, xx, END, END);
- _HPlot(s, 139 + 10 / d, xx - 10 / d, 139 + 15 / d, xx - 15 / d, END, END);
+ hPlot(s, 139 - 10 / d, xx, 139 - 10 / d, xx - 10 / d, 139 + 10 / d, xx - 10 / d, 139 + 10 / d, xx, 139 - 10 / d, xx, END, END);
+ hPlot(s, 139 - 10 / d, xx - 10 / d, 139 - 5 / d, xx - 15 / d, 139 + 15 / d, xx - 15 / d, 139 + 15 / d, xx - 5 / d, 139 + 10 / d, xx, END, END);
+ hPlot(s, 139 + 10 / d, xx - 10 / d, 139 + 15 / d, xx - 15 / d, END, END);
}
-void Monster::_DRAWDaemon(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y - 14 / d, x - 46 / d, y - 12 / d, x - 37 / d, y - 20 / d, x - 32 / d, y - 30 / d, x - 32 / d, y - 22 / d, x - 24 / d, y - 40 / d, x - 17 / d, y - 40 / d, x - 7 / d, y - 38 / d, x - 5 / d, y - 40 / d, x - 3 / d, y - 40 / d, x, END, END);
- _HPlot(s, y - 36 / d, x, y - 34 / d, x - 2 / d, y - 32 / d, x, y - 28 / d, x, y - 28 / d, x - 3 / d, y - 30 / d, x - 5 / d, y - 28 / d, x - 7 / d, y - 28 / d, x - 15 / d, y, x - 27 / d, END, END);
- _HPlot(s, y + 14 / d, x - 46 / d, y + 12 / d, x - 37 / d, y + 20 / d, x - 32 / d, y + 30 / d, x - 32 / d, y + 22 / d, x - 24 / d, y + 40 / d, x - 17 / d, y + 40 / d, x - 7 / d, y + 38 / d, x - 5 / d, y + 40 / d, x - 3 / d, y + 40 / d, x, END, END);
- _HPlot(s, y + 36 / d, x, y + 34 / d, x - 2 / d, y + 32 / d, x, y + 28 / d, x, y + 28 / d, x - 3 / d, y + 30 / d, x - 5 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 15 / d, y, x - 27 / d, END, END);
- _HPlot(s, y + 6 / d, x - 48 / d, y + 38 / d, x - 41 / d, y + 40 / d, x - 42 / d, y + 18 / d, x - 56 / d, y + 12 / d, x - 56 / d, y + 10 / d, x - 57 / d, y + 8 / d, x - 56 / d, y - 8 / d, x - 56 / d, y - 10 / d, x - 58 / d, y + 14 / d, x - 58 / d, y + 16 / d, x - 59 / d, END, END);
- _HPlot(s, y + 8 / d, x - 63 / d, y + 6 / d, x - 63 / d, y + 2 / d + .5, x - 70 / d, y + 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 70 / d, y - 6 / d, x - 63 / d, y - 8 / d, x - 63 / d, y - 16 / d, x - 59 / d, y - 14 / d, x - 58 / d, END, END);
- _HPlot(s, y - 10 / d, x - 57 / d, y - 12 / d, x - 56 / d, y - 18 / d, x - 56 / d, y - 36 / d, x - 47 / d, y - 36 / d, x - 39 / d, y - 28 / d, x - 41 / d, y - 28 / d, x - 46 / d, y - 20 / d, x - 50 / d, y - 18 / d, x - 50 / d, y - 14 / d, x - 46 / d, END, END);
- _HPlot(s, y - 28 / d, x - 41 / d, y + 30 / d, x - 55 / d, END, END);
- _HPlot(s, y + 28 / d, x - 58 / d, y + 22 / d, x - 56 / d, y + 22 / d, x - 53 / d, y + 28 / d, x - 52 / d, y + 34 / d, x - 54 / d, END, END);
- _HPlot(s, y + 20 / d, x - 50 / d, y + 26 / d, x - 47 / d, END, END);
- _HPlot(s, y + 10 / d, x - 58 / d, y + 10 / d, x - 61 / d, y + 4 / d, x - 58 / d, END, END);
- _HPlot(s, y - 10 / d, x - 58 / d, y - 10 / d, x - 61 / d, y - 4 / d, x - 58 / d, END, END);
- _HPlot(s, y + 40 / d, x - 9 / d, y + 50 / d, x - 12 / d, y + 40 / d, x - 7 / d, END, END);
- _HPlot(s, y - 8 / d, x - 25 / d, y + 6 / d, x - 7 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 9 / d, y + 20 / d, x - 9 / d, y + 6 / d, x - 25 / d, END, END);
+void Monster::drawDaemon(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y - 14 / d, x - 46 / d, y - 12 / d, x - 37 / d, y - 20 / d, x - 32 / d, y - 30 / d, x - 32 / d, y - 22 / d, x - 24 / d, y - 40 / d, x - 17 / d, y - 40 / d, x - 7 / d, y - 38 / d, x - 5 / d, y - 40 / d, x - 3 / d, y - 40 / d, x, END, END);
+ hPlot(s, y - 36 / d, x, y - 34 / d, x - 2 / d, y - 32 / d, x, y - 28 / d, x, y - 28 / d, x - 3 / d, y - 30 / d, x - 5 / d, y - 28 / d, x - 7 / d, y - 28 / d, x - 15 / d, y, x - 27 / d, END, END);
+ hPlot(s, y + 14 / d, x - 46 / d, y + 12 / d, x - 37 / d, y + 20 / d, x - 32 / d, y + 30 / d, x - 32 / d, y + 22 / d, x - 24 / d, y + 40 / d, x - 17 / d, y + 40 / d, x - 7 / d, y + 38 / d, x - 5 / d, y + 40 / d, x - 3 / d, y + 40 / d, x, END, END);
+ hPlot(s, y + 36 / d, x, y + 34 / d, x - 2 / d, y + 32 / d, x, y + 28 / d, x, y + 28 / d, x - 3 / d, y + 30 / d, x - 5 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 15 / d, y, x - 27 / d, END, END);
+ hPlot(s, y + 6 / d, x - 48 / d, y + 38 / d, x - 41 / d, y + 40 / d, x - 42 / d, y + 18 / d, x - 56 / d, y + 12 / d, x - 56 / d, y + 10 / d, x - 57 / d, y + 8 / d, x - 56 / d, y - 8 / d, x - 56 / d, y - 10 / d, x - 58 / d, y + 14 / d, x - 58 / d, y + 16 / d, x - 59 / d, END, END);
+ hPlot(s, y + 8 / d, x - 63 / d, y + 6 / d, x - 63 / d, y + 2 / d + .5, x - 70 / d, y + 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 70 / d, y - 6 / d, x - 63 / d, y - 8 / d, x - 63 / d, y - 16 / d, x - 59 / d, y - 14 / d, x - 58 / d, END, END);
+ hPlot(s, y - 10 / d, x - 57 / d, y - 12 / d, x - 56 / d, y - 18 / d, x - 56 / d, y - 36 / d, x - 47 / d, y - 36 / d, x - 39 / d, y - 28 / d, x - 41 / d, y - 28 / d, x - 46 / d, y - 20 / d, x - 50 / d, y - 18 / d, x - 50 / d, y - 14 / d, x - 46 / d, END, END);
+ hPlot(s, y - 28 / d, x - 41 / d, y + 30 / d, x - 55 / d, END, END);
+ hPlot(s, y + 28 / d, x - 58 / d, y + 22 / d, x - 56 / d, y + 22 / d, x - 53 / d, y + 28 / d, x - 52 / d, y + 34 / d, x - 54 / d, END, END);
+ hPlot(s, y + 20 / d, x - 50 / d, y + 26 / d, x - 47 / d, END, END);
+ hPlot(s, y + 10 / d, x - 58 / d, y + 10 / d, x - 61 / d, y + 4 / d, x - 58 / d, END, END);
+ hPlot(s, y - 10 / d, x - 58 / d, y - 10 / d, x - 61 / d, y - 4 / d, x - 58 / d, END, END);
+ hPlot(s, y + 40 / d, x - 9 / d, y + 50 / d, x - 12 / d, y + 40 / d, x - 7 / d, END, END);
+ hPlot(s, y - 8 / d, x - 25 / d, y + 6 / d, x - 7 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 9 / d, y + 20 / d, x - 9 / d, y + 6 / d, x - 25 / d, END, END);
}
-void Monster::_DRAWBalrog(Graphics::ManagedSurface *s, double x, double y, double d) {
- _HPlot(s, y + 6 / d, x - 60 / d, y + 30 / d, x - 90 / d, y + 60 / d, x - 30 / d, y + 60 / d, x - 10 / d, y + 30 / d, x - 40 / d, y + 15 / d, x - 40 / d, END, END);
- _HPlot(s, y - 6 / d, x - 60 / d, y - 30 / d, x - 90 / d, y - 60 / d, x - 30 / d, y - 60 / d, x - 10 / d, y - 30 / d, x - 40 / d, y - 15 / d, x - 40 / d, END, END);
- _HPlot(s, y, x - 25 / d, y + 6 / d, x - 25 / d, y + 10 / d, x - 20 / d, y + 12 / d, x - 10 / d, y + 10 / d, x - 6 / d, y + 10 / d, x, y + 14 / d, x, y + 15 / d, x - 5 / d, y + 16 / d, x, y + 20 / d, x, END, END);
- _HPlot(s, y + 20 / d, x - 6 / d, y + 18 / d, x - 10 / d, y + 18 / d, x - 20 / d, y + 15 / d, x - 30 / d, y + 15 / d, x - 45 / d, y + 40 / d, x - 60 / d, y + 40 / d, x - 70 / d, END, END);
- _HPlot(s, y + 10 / d, x - 55 / d, y + 6 / d, x - 60 / d, y + 10 / d, x - 74 / d, y + 6 / d, x - 80 / d, y + 4 / d + .5, x - 80 / d, y + 3 / d + .5, x - 82 / d, y + 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
- _HPlot(s, y, x - 25 / d, y - 6 / d, x - 25 / d, y - 10 / d, x - 20 / d, y - 12 / d, x - 10 / d, y - 10 / d, x - 6 / d, y - 10 / d, x, y - 14 / d, x, y - 15 / d, x - 5 / d, y - 16 / d, x, y - 20 / d, x, END, END);
- _HPlot(s, y - 20 / d, x - 6 / d, y - 18 / d, x - 10 / d, y - 18 / d, x - 20 / d, y - 15 / d, x - 30 / d, y - 15 / d, x - 45 / d, y - 40 / d, x - 60 / d, y - 40 / d, x - 70 / d, END, END);
- _HPlot(s, y - 10 / d, x - 55 / d, y - 6 / d, x - 60 / d, y - 10 / d, x - 74 / d, y - 6 / d, x - 80 / d, y - 4 / d + .5, x - 80 / d, y - 3 / d + .5, x - 82 / d, y - 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
- _HPlot(s, y - 6 / d, x - 25 / d, y, x - 6 / d, y + 10 / d, x, y + 4 / d + .5, x - 8 / d, y + 6 / d, x - 25 / d, END, END);
- _HPlot(s, y - 40 / d, x - 64 / d, y - 40 / d, x - 90 / d, y - 52 / d, x - 80 / d, y - 52 / d, x - 40 / d, END, END);
- _HPlot(s, y + 40 / d, x - 86 / d, y + 38 / d, x - 92 / d, y + 42 / d, x - 92 / d, y + 40 / d, x - 86 / d, y + 40 / d, x - 50 / d, END, END);
- _HPlot(s, y + 4 / d + .5, x - 70 / d, y + 6 / d, x - 74 / d, END, END);
- _HPlot(s, y - 4 / d + .5, x - 70 / d, y - 6 / d, x - 74 / d, END, END);
- _HPlot(s, y, x - 64 / d, y, x - 60 / d, END, END);
+void Monster::drawBalrog(Graphics::ManagedSurface *s, double x, double y, double d) {
+ hPlot(s, y + 6 / d, x - 60 / d, y + 30 / d, x - 90 / d, y + 60 / d, x - 30 / d, y + 60 / d, x - 10 / d, y + 30 / d, x - 40 / d, y + 15 / d, x - 40 / d, END, END);
+ hPlot(s, y - 6 / d, x - 60 / d, y - 30 / d, x - 90 / d, y - 60 / d, x - 30 / d, y - 60 / d, x - 10 / d, y - 30 / d, x - 40 / d, y - 15 / d, x - 40 / d, END, END);
+ hPlot(s, y, x - 25 / d, y + 6 / d, x - 25 / d, y + 10 / d, x - 20 / d, y + 12 / d, x - 10 / d, y + 10 / d, x - 6 / d, y + 10 / d, x, y + 14 / d, x, y + 15 / d, x - 5 / d, y + 16 / d, x, y + 20 / d, x, END, END);
+ hPlot(s, y + 20 / d, x - 6 / d, y + 18 / d, x - 10 / d, y + 18 / d, x - 20 / d, y + 15 / d, x - 30 / d, y + 15 / d, x - 45 / d, y + 40 / d, x - 60 / d, y + 40 / d, x - 70 / d, END, END);
+ hPlot(s, y + 10 / d, x - 55 / d, y + 6 / d, x - 60 / d, y + 10 / d, x - 74 / d, y + 6 / d, x - 80 / d, y + 4 / d + .5, x - 80 / d, y + 3 / d + .5, x - 82 / d, y + 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
+ hPlot(s, y, x - 25 / d, y - 6 / d, x - 25 / d, y - 10 / d, x - 20 / d, y - 12 / d, x - 10 / d, y - 10 / d, x - 6 / d, y - 10 / d, x, y - 14 / d, x, y - 15 / d, x - 5 / d, y - 16 / d, x, y - 20 / d, x, END, END);
+ hPlot(s, y - 20 / d, x - 6 / d, y - 18 / d, x - 10 / d, y - 18 / d, x - 20 / d, y - 15 / d, x - 30 / d, y - 15 / d, x - 45 / d, y - 40 / d, x - 60 / d, y - 40 / d, x - 70 / d, END, END);
+ hPlot(s, y - 10 / d, x - 55 / d, y - 6 / d, x - 60 / d, y - 10 / d, x - 74 / d, y - 6 / d, x - 80 / d, y - 4 / d + .5, x - 80 / d, y - 3 / d + .5, x - 82 / d, y - 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
+ hPlot(s, y - 6 / d, x - 25 / d, y, x - 6 / d, y + 10 / d, x, y + 4 / d + .5, x - 8 / d, y + 6 / d, x - 25 / d, END, END);
+ hPlot(s, y - 40 / d, x - 64 / d, y - 40 / d, x - 90 / d, y - 52 / d, x - 80 / d, y - 52 / d, x - 40 / d, END, END);
+ hPlot(s, y + 40 / d, x - 86 / d, y + 38 / d, x - 92 / d, y + 42 / d, x - 92 / d, y + 40 / d, x - 86 / d, y + 40 / d, x - 50 / d, END, END);
+ hPlot(s, y + 4 / d + .5, x - 70 / d, y + 6 / d, x - 74 / d, END, END);
+ hPlot(s, y - 4 / d + .5, x - 70 / d, y - 6 / d, x - 74 / d, END, END);
+ hPlot(s, y, x - 64 / d, y, x - 60 / d, END, END);
}
} // namespace Views
diff --git a/engines/ultima/ultima0/gfx/monster.h b/engines/ultima/ultima0/gfx/monster.h
index 47add736c4d..1fdde65d338 100644
--- a/engines/ultima/ultima0/gfx/monster.h
+++ b/engines/ultima/ultima0/gfx/monster.h
@@ -32,32 +32,32 @@ namespace Gfx {
class Monster {
private:
// Drawing position
- static int xPos, yPos;
+ static int _xPos, _yPos;
/**
* Emulate the Apple ][ HPLOT function
*/
- static void _HPlot(Graphics::ManagedSurface *s, double x, double y, ...);
+ static void hPlot(Graphics::ManagedSurface *s, double x, double y, ...);
/**
* Monster drawing functions
*/
typedef void(*DrawFn)(Graphics::ManagedSurface *s, double x, double y, double d);
- static void _DRAWSkeleton(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWThief(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWRat(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWOrc(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWViper(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWCarrion(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWGremlin(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWMimic(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWDaemon(Graphics::ManagedSurface *s, double x,double y,double d);
- static void _DRAWBalrog(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawSkeleton(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawThief(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawRat(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawOrc(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawViper(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawCarrion(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawGremlin(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawMimic(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawDaemon(Graphics::ManagedSurface *s, double x,double y,double d);
+ static void drawBalrog(Graphics::ManagedSurface *s, double x,double y,double d);
static DrawFn DRAW_FUNCTIONS[];
public:
static void draw(Graphics::ManagedSurface *s, int x, int y,
- int Monster, double Scale);
+ int monster, double scale);
};
} // namespace Gfx
Commit: 679c39ec130b83663c7fb0253659874492e6d0f5
https://github.com/scummvm/scummvm/commit/679c39ec130b83663c7fb0253659874492e6d0f5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:30+11:00
Commit Message:
ULTIMA: ULTIMA0: Change monster list to use Common::Array
Changed paths:
engines/ultima/ultima0/console.cpp
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/data/monster_logic.cpp
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/map.h
engines/ultima/ultima0/views/attack.cpp
diff --git a/engines/ultima/ultima0/console.cpp b/engines/ultima/ultima0/console.cpp
index a74ace877d7..991ddba615c 100644
--- a/engines/ultima/ultima0/console.cpp
+++ b/engines/ultima/ultima0/console.cpp
@@ -94,7 +94,7 @@ bool Console::cmdDemo(int argc, const char **argv) {
p.Attr[AT_HP] = 18;
p.Attr[AT_GOLD] = 99;
- for (int i = 0; i < p.Objects; i++) // Lots of nice objects
+ for (int i = 0; i < MAX_OBJ; i++) // Lots of nice objects
p.Object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
p.Level = 0;
@@ -118,7 +118,7 @@ bool Console::cmdDebug(int argc, const char **argv) {
p.Attr[i] = 99;
p.Attr[AT_HP] = 999;
p.Attr[AT_GOLD] = 9999;
- for (i = 0; i < p.Objects; i++) // Lots of nice objects
+ for (i = 0; i < MAX_OBJ; i++) // Lots of nice objects
p.Object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
p.Level = 0;
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 42922b60a80..201bb71a709 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -251,7 +251,7 @@ void DungeonMapInfo::create(const PlayerInfo &player) {
}
// Add monsters
- MonstCount = 0;
+ _monsters.clear();
for (i = 1; i <= MAX_MONSTERS; ++i)
addMonster(player, i);
}
@@ -276,10 +276,8 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
if (RND() > 0.4)
return;
- // Get monster record
- MonsterEntry &m = Monster[MonstCount++];
-
// Fill in details */
+ MonsterEntry m;
m._type = Type;
m._strength = level + 3 + player.Level;
m._alive = true;
@@ -293,6 +291,8 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
// Record position
m._loc.x = x; m._loc.y = y;
+
+ _monsters.push_back(m);
}
void DungeonMapInfo::synchronize(Common::Serializer &s) {
@@ -302,10 +302,13 @@ void DungeonMapInfo::synchronize(Common::Serializer &s) {
}
int DungeonMapInfo::findMonster(const Common::Point &c) const {
- int i, n = -1;
- for (i = 0; i < MonstCount; i++)
- if (c.x == Monster[i]._loc.x && c.y == Monster[i]._loc.y && Monster[i]._alive)
+ int n = -1;
+
+ for (uint i = 0; i < _monsters.size(); i++) {
+ const auto &m = _monsters[i];
+ if (m._loc == c && m._alive)
n = i;
+ }
return n;
}
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 49b149bf20e..b96cecf8c4a 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_DATA_H
#define ULTIMA0_DATA_H
+#include "common/array.h"
#include "common/keyboard.h"
#include "common/rect.h"
#include "common/serializer.h"
@@ -68,10 +69,8 @@ private:
int generateContent(int c);
public:
- const int MapSize = DUNGEON_MAP_SIZE - 1; // Size of Map
byte Map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
- int MonstCount = 0; // Number of Monsters
- MonsterEntry Monster[MAX_MONSTERS]; // Monster records
+ Common::Array<MonsterEntry> _monsters; // Monster records
void create(const PlayerInfo &player);
void synchronize(Common::Serializer &s);
@@ -86,7 +85,7 @@ public:
* Player structure
*/
struct PlayerInfo {
- char Name[MAX_NAME + 1] = {}; // Player Name
+ char Name[MAX_NAME + 1] = {}; // Player Name
Common::Point World; // World map position
Common::Point Dungeon; // Dungeon map position
Common::Point DungDir; // Dungeon direction facing
@@ -97,8 +96,6 @@ struct PlayerInfo {
int Task = 0; // Task set (-1 = none)
int TaskCompleted = 0; // Task completed
uint32 LuckyNumber = 0; // Value used for seeding
- const int Attributes = MAX_ATTR; // Number of attributes
- const int Objects = MAX_OBJ; // Number of objects
int Attr[MAX_ATTR] = {}; // Attribute values
double Object[MAX_OBJ] = {}; // Object counts
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
index bb78918c54b..236fa82bfa8 100644
--- a/engines/ultima/ultima0/data/monster_logic.cpp
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -30,8 +30,7 @@ void MonsterLogic::checkForAttacks(PlayerInfo &p, DungeonMapInfo &d) {
double Dist;
// Go through all monsters
- for (i = 0; i < d.MonstCount; i++) {
- MonsterEntry &m = d.Monster[i]; // Pointer to MONSTER &/
+ for (MonsterEntry &m : d._monsters) {
Dist = pow(m._loc.x - p.Dungeon.x, 2); // Calculate Distance
Dist = Dist + pow(m._loc.y - p.Dungeon.y, 2);
Dist = sqrt(Dist);
@@ -152,7 +151,7 @@ int MonsterLogic::steal(MonsterEntry &m, PlayerInfo &p) {
} else if (m._type == MN_THIEF) {
// Figure out what stolen
do {
- n = urand() % p.Objects;
+ n = urand() % MAX_OBJ;
} while (p.Object[n] == 0);
p.Object[n]--; // Stole one
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 6489ad68a6a..c2ad9a63cc6 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -68,7 +68,7 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
// Check for monster present
monster = dungeon.findMonster(pos);
if (monster >= 0)
- monster = dungeon.Monster[monster]._type;
+ monster = dungeon._monsters[monster]._type;
// Draw the dungeon
DRAWDungeon(s, &rOut, &rIn, left, front, right,
diff --git a/engines/ultima/ultima0/gfx/map.h b/engines/ultima/ultima0/gfx/map.h
index 89b77981835..3c19d06c8f5 100644
--- a/engines/ultima/ultima0/gfx/map.h
+++ b/engines/ultima/ultima0/gfx/map.h
@@ -30,7 +30,7 @@ namespace Gfx {
class Map {
private:
- static void DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int Obj);
+ static void DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj);
public:
static void draw(Graphics::ManagedSurface *s, bool showAsMap = false);
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index 6156c4731d2..ed6f59ddcd4 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -251,27 +251,27 @@ void Attack::attackWeapon() {
void Attack::attackHitMonster(const Common::Point &c) {
auto &player = g_engine->_player;
auto &dungeon = g_engine->_dungeon;
- int n = 0, Monster, Damage;
+ int n = 0, monNum, damage;
MonsterEntry *m = nullptr;
// Is there a monster there ?
- Monster = dungeon.findMonster(c);
- if (Monster >= 0) {
+ monNum = dungeon.findMonster(c);
+ if (monNum >= 0) {
// Set up a pointer
- m = &dungeon.Monster[Monster];
+ m = &dungeon._monsters[monNum];
n = m->_type;
}
// Get weaponry info
- Damage = 0;
+ damage = 0;
if (_weapon >= 0 && _weapon != OB_AMULET)
- Damage = OBJECT_INFO[_weapon].MaxDamage;
+ damage = OBJECT_INFO[_weapon].MaxDamage;
if (_weapon == OB_AMULET)
// Amulet Special Case
- Damage = 10 + player.Level;
+ damage = 10 + player.Level;
// If no, or not dexterous
- if (Monster < 0 || player.Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player.Level) {
+ if (monNum < 0 || player.Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player.Level) {
// Then a miss.
_message += "\nMissed!";
_mode = DONE;
@@ -285,8 +285,8 @@ void Attack::attackHitMonster(const Common::Point &c) {
// Calculate HPs lost
n = 0;
- if (Damage > 0)
- n = (urand() % Damage);
+ if (damage > 0)
+ n = (urand() % damage);
n = n + player.Attr[AT_STRENGTH] / 5;
m->_strength = m->_strength - n; // Lose them
Commit: 7067bf938e2ba79e72c3727716b53b5e53d22ffd
https://github.com/scummvm/scummvm/commit/7067bf938e2ba79e72c3727716b53b5e53d22ffd
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:30+11:00
Commit Message:
ULTIMA: ULTIMA0: Further janitorial
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/views/dungeon.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 201bb71a709..856b7ec973b 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -143,22 +143,22 @@ void PlayerInfo::dungeonTurnRight() {
/*-------------------------------------------------------------------*/
void WorldMapInfo::init(PlayerInfo &p) {
- int c, x, y, Size;
+ int c, x, y, size;
g_engine->setRandomSeed(p.LuckyNumber);
- Size = WORLD_MAP_SIZE - 1;
+ size = WORLD_MAP_SIZE - 1;
// Set the boundaries
- for (x = 0; x <= Size; x++) {
- Map[Size][x] = WT_MOUNTAIN;
+ for (x = 0; x <= size; x++) {
+ Map[size][x] = WT_MOUNTAIN;
Map[0][x] = WT_MOUNTAIN;
- Map[x][Size] = WT_MOUNTAIN;
+ Map[x][size] = WT_MOUNTAIN;
Map[x][0] = WT_MOUNTAIN;
}
// Set up the map contents
- for (x = 1; x < Size; x++) {
- for (y = 1; y < Size; y++) {
+ for (x = 1; x < size; x++) {
+ for (y = 1; y < size; y++) {
c = (int)(pow(RND(), 5.0) * 4.5); // Calculate what's there
if (c == WT_TOWN && RND() > .5) // Remove half the towns
c = WT_SPACE;
@@ -167,15 +167,15 @@ void WorldMapInfo::init(PlayerInfo &p) {
}
// Calculate player start
- x = g_engine->getRandomNumber(1, Size - 1);
- y = g_engine->getRandomNumber(1, Size - 1);
+ x = g_engine->getRandomNumber(1, size - 1);
+ y = g_engine->getRandomNumber(1, size - 1);
p.World.x = x; p.World.y = y; // Save it
Map[x][y] = WT_TOWN; // Make it a town
// Find place for castle
do {
- x = g_engine->getRandomNumber(1, Size - 1);
- y = g_engine->getRandomNumber(1, Size - 1);
+ x = g_engine->getRandomNumber(1, size - 1);
+ y = g_engine->getRandomNumber(1, size - 1);
} while (Map[x][y] != WT_SPACE);
Map[x][y] = WT_BRITISH; // Put LBs castle there
@@ -199,7 +199,7 @@ void WorldMapInfo::synchronize(Common::Serializer &s) {
void DungeonMapInfo::create(const PlayerInfo &player) {
int i, x, y;
- const int Size = DUNGEON_MAP_SIZE - 1;
+ const int SIZE = DUNGEON_MAP_SIZE - 1;
// Seed the random number
g_engine->setRandomSeed(player.LuckyNumber - player.World.x * 40 -
@@ -209,24 +209,24 @@ void DungeonMapInfo::create(const PlayerInfo &player) {
Common::fill((byte *)Map, (byte *)Map + DUNGEON_MAP_SIZE * DUNGEON_MAP_SIZE, DT_SPACE);
// Draw the boundaries
- for (x = 0; x <= Size; x++) {
- Map[Size][x] = DT_SOLID;
+ for (x = 0; x <= SIZE; x++) {
+ Map[SIZE][x] = DT_SOLID;
Map[0][x] = DT_SOLID;
- Map[x][Size] = DT_SOLID;
+ Map[x][SIZE] = DT_SOLID;
Map[x][0] = DT_SOLID;
}
// Fill with checkerboard
- for (x = 2; x < Size; x = x + 2) {
- for (y = 1; y < Size; y++) {
+ for (x = 2; x < SIZE; x = x + 2) {
+ for (y = 1; y < SIZE; y++) {
Map[x][y] = DT_SOLID;
Map[y][x] = DT_SOLID;
}
}
// Fill with stuff
- for (x = 2; x < Size; x = x + 2) {
- for (y = 1; y < Size; y = y + 2) {
+ for (x = 2; x < SIZE; x = x + 2) {
+ for (y = 1; y < SIZE; y = y + 2) {
Map[x][y] = generateContent(Map[x][y]);
Map[y][x] = generateContent(Map[y][x]);
}
@@ -237,17 +237,17 @@ void DungeonMapInfo::create(const PlayerInfo &player) {
// Different ends each level
if (player.Level % 2 == 0) {
- Map[Size - 3][3] = DT_LADDERDN;
- Map[3][Size - 3] = DT_LADDERUP;
+ Map[SIZE - 3][3] = DT_LADDERDN;
+ Map[3][SIZE - 3] = DT_LADDERUP;
} else {
- Map[Size - 3][3] = DT_LADDERUP;
- Map[3][Size - 3] = DT_LADDERDN;
+ Map[SIZE - 3][3] = DT_LADDERUP;
+ Map[3][SIZE - 3] = DT_LADDERDN;
}
// On first floor
if (player.Level == 1) {
Map[1][1] = DT_LADDERUP; // Ladder at top left
- Map[Size - 3][3] = DT_SPACE; // No other ladder up
+ Map[SIZE - 3][3] = DT_SPACE; // No other ladder up
}
// Add monsters
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index bfdedb7ec74..ef0aed6a23b 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -187,13 +187,13 @@ void Dungeon::endOfTurn() {
void Dungeon::moveForward() {
auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
- Common::Point New = player.Dungeon + player.DungDir;
+ Common::Point newPos = player.Dungeon + player.DungDir;
- if (!ISWALKTHRU(dungeon.Map[New.x][New.y]) || dungeon.findMonster(New) >= 0)
+ if (!ISWALKTHRU(dungeon.Map[newPos.x][newPos.y]) || dungeon.findMonster(newPos) >= 0)
return;
// Set new position
- player.Dungeon = New;
+ player.Dungeon = newPos;
// What's here ?
int n = dungeon.Map[player.Dungeon.x][player.Dungeon.y];
Commit: 80813edddf6dfa34611d5e2b3b70482e50931fe5
https://github.com/scummvm/scummvm/commit/80813edddf6dfa34611d5e2b3b70482e50931fe5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:30+11:00
Commit Message:
ULTIMA: ULTIMA0: Renaming structure fields
Changed paths:
engines/ultima/ultima0/console.cpp
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/data/monster_logic.cpp
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/dungeon.h
engines/ultima/ultima0/gfx/map.cpp
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/castle.cpp
engines/ultima/ultima0/views/create_character.cpp
engines/ultima/ultima0/views/dead.cpp
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/info.cpp
engines/ultima/ultima0/views/info.h
engines/ultima/ultima0/views/status.cpp
engines/ultima/ultima0/views/town.cpp
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/ultima0/console.cpp b/engines/ultima/ultima0/console.cpp
index 991ddba615c..6f8603df794 100644
--- a/engines/ultima/ultima0/console.cpp
+++ b/engines/ultima/ultima0/console.cpp
@@ -52,7 +52,7 @@ bool Console::cmdFood(int argc, const char **argv) {
debugPrintf("food <amount>\n");
return true;
} else {
- g_engine->_player.Object[OB_FOOD] = atoi(argv[1]);
+ g_engine->_player._object[OB_FOOD] = atoi(argv[1]);
g_engine->focusedView()->redraw();
return false;
}
@@ -63,7 +63,7 @@ bool Console::cmdGold(int argc, const char **argv) {
debugPrintf("gold <amount>\n");
return true;
} else {
- g_engine->_player.Attr[AT_GOLD] = atoi(argv[1]);
+ g_engine->_player._attr[AT_GOLD] = atoi(argv[1]);
g_engine->focusedView()->redraw();
return false;
}
@@ -74,7 +74,7 @@ bool Console::cmdHP(int argc, const char **argv) {
debugPrintf("hp <amount>\n");
return true;
} else {
- g_engine->_player.Attr[AT_HP] = atoi(argv[1]);
+ g_engine->_player._attr[AT_HP] = atoi(argv[1]);
g_engine->focusedView()->redraw();
return false;
}
@@ -84,20 +84,20 @@ bool Console::cmdDemo(int argc, const char **argv) {
auto &p = g_engine->_player;
auto &map = g_engine->_worldMap;
- Common::strcpy_s(p.Name, "Demo"); // Characters Name
- p.Class = 'F'; // Fighter
- p.LuckyNumber = 42; // Always the same.....
- p.Skill = 1; // Skill level 1
+ Common::strcpy_s(p._name, "Demo"); // Characters Name
+ p._class = 'F'; // Fighter
+ p._luckyNumber = 42; // Always the same.....
+ p._skill = 1; // Skill level 1
// Nice high attributes
- Common::fill(p.Attr, p.Attr + MAX_ATTR, 15);
- p.Attr[AT_HP] = 18;
- p.Attr[AT_GOLD] = 99;
+ Common::fill(p._attr, p._attr + MAX_ATTR, 15);
+ p._attr[AT_HP] = 18;
+ p._attr[AT_GOLD] = 99;
for (int i = 0; i < MAX_OBJ; i++) // Lots of nice objects
- p.Object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
+ p._object[i] = (i == OB_FOOD || i == OB_BOW) ? 999 : 4.0;
- p.Level = 0;
+ p._level = 0;
map.init(p);
g_engine->replaceView("WorldMap");
@@ -110,18 +110,18 @@ bool Console::cmdDebug(int argc, const char **argv) {
auto &map = g_engine->_worldMap;
int i;
- Common::strcpy_s(p.Name, "Debuggo"); // Characters Name
- p.Class = 'F'; // Fighter
- p.LuckyNumber = 42; // Always the same.....
- p.Skill = 1; // Skill level 1
+ Common::strcpy_s(p._name, "Debuggo"); // Characters Name
+ p._class = 'F'; // Fighter
+ p._luckyNumber = 42; // Always the same.....
+ p._skill = 1; // Skill level 1
for (i = 0; i < MAX_ATTR; i++) // Nice high attributes
- p.Attr[i] = 99;
- p.Attr[AT_HP] = 999;
- p.Attr[AT_GOLD] = 9999;
+ p._attr[i] = 99;
+ p._attr[AT_HP] = 999;
+ p._attr[AT_GOLD] = 9999;
for (i = 0; i < MAX_OBJ; i++) // Lots of nice objects
- p.Object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
+ p._object[i] = (i == OB_FOOD || i == OB_BOW) ? 9999.9 : 99.0;
- p.Level = 0;
+ p._level = 0;
map.init(p);
g_engine->replaceView("WorldMap");
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 856b7ec973b..ffc1ed1d58f 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -54,78 +54,78 @@ const char *const DIRECTION_NAMES[] = { "North", "East", "South", "West" };
/*-------------------------------------------------------------------*/
void PlayerInfo::init() {
- Common::fill(Name, Name + MAX_NAME + 1, '\0');
- World.x = World.y = 0;
- Dungeon.x = Dungeon.y = 0;
- DungDir.x = DungDir.y = 0;
- Class = '?';
- HPGain = 0;
- LuckyNumber = 0;
- Level = 0;
- Skill = 0;
- Task = 0;
- TaskCompleted = 0;
- Common::fill(Attr, Attr + MAX_ATTR, 0);
- Common::fill(Object, Object + MAX_OBJ, 0);
+ Common::fill(_name, _name + MAX_NAME + 1, '\0');
+ _worldPos.x = _worldPos.y = 0;
+ _dungeonPos.x = _dungeonPos.y = 0;
+ _dungeonDir.x = _dungeonDir.y = 0;
+ _class = '?';
+ _hpGain = 0;
+ _luckyNumber = 0;
+ _level = 0;
+ _skill = 0;
+ _task = 0;
+ _taskCompleted = false;
+ Common::fill(_attr, _attr + MAX_ATTR, 0);
+ Common::fill(_object, _object + MAX_OBJ, 0);
}
void PlayerInfo::rollAttributes() {
for (int i = 0; i < MAX_ATTR; ++i)
- Attr[i] = g_engine->getRandomNumber(21) + 4;
+ _attr[i] = g_engine->getRandomNumber(21) + 4;
}
void PlayerInfo::synchronize(Common::Serializer &s) {
- s.syncBytes((byte *)Name, MAX_NAME + 1);
- s.syncAsSint16LE(World.x);
- s.syncAsSint16LE(World.y);
- s.syncAsSint16LE(Dungeon.x);
- s.syncAsSint16LE(Dungeon.y);
- s.syncAsSint16LE(DungDir.x);
- s.syncAsSint16LE(DungDir.y);
- s.syncAsByte(Class);
- s.syncAsSint32LE(HPGain);
- s.syncAsSint32LE(Level);
- s.syncAsSint32LE(Skill);
- s.syncAsSint32LE(Task);
- s.syncAsSint32LE(TaskCompleted);
- s.syncAsUint32LE(LuckyNumber);
+ s.syncBytes((byte *)_name, MAX_NAME + 1);
+ s.syncAsSint16LE(_worldPos.x);
+ s.syncAsSint16LE(_worldPos.y);
+ s.syncAsSint16LE(_dungeonPos.x);
+ s.syncAsSint16LE(_dungeonPos.y);
+ s.syncAsSint16LE(_dungeonDir.x);
+ s.syncAsSint16LE(_dungeonDir.y);
+ s.syncAsByte(_class);
+ s.syncAsSint32LE(_hpGain);
+ s.syncAsSint32LE(_level);
+ s.syncAsSint32LE(_skill);
+ s.syncAsSint32LE(_task);
+ s.syncAsSint32LE(_taskCompleted);
+ s.syncAsUint32LE(_luckyNumber);
for (int i = 0; i < MAX_ATTR; ++i)
- s.syncAsUint32LE(Attr[i]);
+ s.syncAsUint32LE(_attr[i]);
for (int i = 0; i < MAX_OBJ; ++i) {
- uint32 val = (uint32)Object[i];
+ uint32 val = (uint32)_object[i];
s.syncAsUint32LE(val);
if (s.isLoading())
- Object[i] = (double)val;
+ _object[i] = (double)val;
}
}
Direction PlayerInfo::dungeonDir() const {
- if (DungDir.y < 0)
+ if (_dungeonDir.y < 0)
return DIR_NORTH;
- else if (DungDir.x > 0)
+ else if (_dungeonDir.x > 0)
return DIR_EAST;
- else if (DungDir.y > 0)
+ else if (_dungeonDir.y > 0)
return DIR_SOUTH;
else
return DIR_WEST;
}
void PlayerInfo::setDungeonDir(Direction newDir) {
- DungDir.x = 0;
- DungDir.y = 0;
+ _dungeonDir.x = 0;
+ _dungeonDir.y = 0;
switch (newDir) {
case DIR_NORTH:
- DungDir.y = -1;
+ _dungeonDir.y = -1;
break;
case DIR_EAST:
- DungDir.x = 1;
+ _dungeonDir.x = 1;
break;
case DIR_SOUTH:
- DungDir.y = 1;
+ _dungeonDir.y = 1;
break;
case DIR_WEST:
- DungDir.x = -1;
+ _dungeonDir.x = -1;
break;
}
}
@@ -145,15 +145,15 @@ void PlayerInfo::dungeonTurnRight() {
void WorldMapInfo::init(PlayerInfo &p) {
int c, x, y, size;
- g_engine->setRandomSeed(p.LuckyNumber);
+ g_engine->setRandomSeed(p._luckyNumber);
size = WORLD_MAP_SIZE - 1;
// Set the boundaries
for (x = 0; x <= size; x++) {
- Map[size][x] = WT_MOUNTAIN;
- Map[0][x] = WT_MOUNTAIN;
- Map[x][size] = WT_MOUNTAIN;
- Map[x][0] = WT_MOUNTAIN;
+ _map[size][x] = WT_MOUNTAIN;
+ _map[0][x] = WT_MOUNTAIN;
+ _map[x][size] = WT_MOUNTAIN;
+ _map[x][0] = WT_MOUNTAIN;
}
// Set up the map contents
@@ -162,23 +162,23 @@ void WorldMapInfo::init(PlayerInfo &p) {
c = (int)(pow(RND(), 5.0) * 4.5); // Calculate what's there
if (c == WT_TOWN && RND() > .5) // Remove half the towns
c = WT_SPACE;
- Map[x][y] = c;
+ _map[x][y] = c;
}
}
// Calculate player start
x = g_engine->getRandomNumber(1, size - 1);
y = g_engine->getRandomNumber(1, size - 1);
- p.World.x = x; p.World.y = y; // Save it
- Map[x][y] = WT_TOWN; // Make it a town
+ p._worldPos.x = x; p._worldPos.y = y; // Save it
+ _map[x][y] = WT_TOWN; // Make it a town
// Find place for castle
do {
x = g_engine->getRandomNumber(1, size - 1);
y = g_engine->getRandomNumber(1, size - 1);
- } while (Map[x][y] != WT_SPACE);
+ } while (_map[x][y] != WT_SPACE);
- Map[x][y] = WT_BRITISH; // Put LBs castle there
+ _map[x][y] = WT_BRITISH; // Put LBs castle there
}
int WorldMapInfo::read(int x, int y) const {
@@ -186,13 +186,13 @@ int WorldMapInfo::read(int x, int y) const {
return WT_MOUNTAIN;
if (x >= WORLD_MAP_SIZE || y >= WORLD_MAP_SIZE)
return WT_MOUNTAIN;
- return Map[x][y];
+ return _map[x][y];
}
void WorldMapInfo::synchronize(Common::Serializer &s) {
for (int y = 0; y < WORLD_MAP_SIZE; ++y)
for (int x = 0; x < WORLD_MAP_SIZE; ++x)
- s.syncAsByte(Map[x][y]);
+ s.syncAsByte(_map[x][y]);
}
/*-------------------------------------------------------------------*/
@@ -202,52 +202,52 @@ void DungeonMapInfo::create(const PlayerInfo &player) {
const int SIZE = DUNGEON_MAP_SIZE - 1;
// Seed the random number
- g_engine->setRandomSeed(player.LuckyNumber - player.World.x * 40 -
- player.World.y * 1000 - player.Level);
+ g_engine->setRandomSeed(player._luckyNumber - player._worldPos.x * 40 -
+ player._worldPos.y * 1000 - player._level);
// Clear the dungeon
- Common::fill((byte *)Map, (byte *)Map + DUNGEON_MAP_SIZE * DUNGEON_MAP_SIZE, DT_SPACE);
+ Common::fill((byte *)_map, (byte *)_map + DUNGEON_MAP_SIZE * DUNGEON_MAP_SIZE, DT_SPACE);
// Draw the boundaries
for (x = 0; x <= SIZE; x++) {
- Map[SIZE][x] = DT_SOLID;
- Map[0][x] = DT_SOLID;
- Map[x][SIZE] = DT_SOLID;
- Map[x][0] = DT_SOLID;
+ _map[SIZE][x] = DT_SOLID;
+ _map[0][x] = DT_SOLID;
+ _map[x][SIZE] = DT_SOLID;
+ _map[x][0] = DT_SOLID;
}
// Fill with checkerboard
for (x = 2; x < SIZE; x = x + 2) {
for (y = 1; y < SIZE; y++) {
- Map[x][y] = DT_SOLID;
- Map[y][x] = DT_SOLID;
+ _map[x][y] = DT_SOLID;
+ _map[y][x] = DT_SOLID;
}
}
// Fill with stuff
for (x = 2; x < SIZE; x = x + 2) {
for (y = 1; y < SIZE; y = y + 2) {
- Map[x][y] = generateContent(Map[x][y]);
- Map[y][x] = generateContent(Map[y][x]);
+ _map[x][y] = generateContent(_map[x][y]);
+ _map[y][x] = generateContent(_map[y][x]);
}
}
// Put stairs in
- Map[2][1] = DT_SPACE;
+ _map[2][1] = DT_SPACE;
// Different ends each level
- if (player.Level % 2 == 0) {
- Map[SIZE - 3][3] = DT_LADDERDN;
- Map[3][SIZE - 3] = DT_LADDERUP;
+ if (player._level % 2 == 0) {
+ _map[SIZE - 3][3] = DT_LADDERDN;
+ _map[3][SIZE - 3] = DT_LADDERUP;
} else {
- Map[SIZE - 3][3] = DT_LADDERUP;
- Map[3][SIZE - 3] = DT_LADDERDN;
+ _map[SIZE - 3][3] = DT_LADDERUP;
+ _map[3][SIZE - 3] = DT_LADDERDN;
}
// On first floor
- if (player.Level == 1) {
- Map[1][1] = DT_LADDERUP; // Ladder at top left
- Map[SIZE - 3][3] = DT_SPACE; // No other ladder up
+ if (player._level == 1) {
+ _map[1][1] = DT_LADDERUP; // Ladder at top left
+ _map[SIZE - 3][3] = DT_SPACE; // No other ladder up
}
// Add monsters
@@ -267,10 +267,10 @@ int DungeonMapInfo::generateContent(int c) {
void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
int x, y;
- int level = MONSTER_INFO[Type].Level;
+ int level = MONSTER_INFO[Type]._level;
// Limit monsters to levels
- if (level - 2 > player.Level)
+ if (level - 2 > player._level)
return;
// Not always there anyway
if (RND() > 0.4)
@@ -279,15 +279,15 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
// Fill in details */
MonsterEntry m;
m._type = Type;
- m._strength = level + 3 + player.Level;
+ m._strength = level + 3 + player._level;
m._alive = true;
// Find a place for it. Must be empty, not player
do {
x = urand() % DUNGEON_MAP_SIZE;
y = urand() % DUNGEON_MAP_SIZE;
- } while (Map[x][y] != DT_SPACE ||
- (x == player.Dungeon.x && y == player.Dungeon.y));
+ } while (_map[x][y] != DT_SPACE ||
+ (x == player._dungeonPos.x && y == player._dungeonPos.y));
// Record position
m._loc.x = x; m._loc.y = y;
@@ -298,7 +298,7 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
void DungeonMapInfo::synchronize(Common::Serializer &s) {
for (int y = 0; y < DUNGEON_MAP_SIZE; ++y)
for (int x = 0; x < DUNGEON_MAP_SIZE; ++x)
- s.syncAsByte(Map[x][y]);
+ s.syncAsByte(_map[x][y]);
}
int DungeonMapInfo::findMonster(const Common::Point &c) const {
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index b96cecf8c4a..761165ec063 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -36,13 +36,13 @@ enum Direction { DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST };
struct PlayerInfo;
struct ObjectInfo {
- const char *Name;
- int Cost;
- int MaxDamage;
- Common::KeyCode keycode;
+ const char *_name;
+ int _cost;
+ int _maxDamage;
+ Common::KeyCode _keycode;
};
struct MonsterInfo {
- const char *Name; int Level;
+ const char *Name; int _level;
};
extern const ObjectInfo OBJECT_INFO[];
@@ -69,7 +69,7 @@ private:
int generateContent(int c);
public:
- byte Map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
+ byte _map[DUNGEON_MAP_SIZE][DUNGEON_MAP_SIZE] = {}; // Map information
Common::Array<MonsterEntry> _monsters; // Monster records
void create(const PlayerInfo &player);
@@ -85,19 +85,19 @@ public:
* Player structure
*/
struct PlayerInfo {
- char Name[MAX_NAME + 1] = {}; // Player Name
- Common::Point World; // World map position
- Common::Point Dungeon; // Dungeon map position
- Common::Point DungDir; // Dungeon direction facing
- byte Class = '?'; // Player class (F or M)
- int HPGain = 0; // HPs gained in dungeon
- int Level = 0; // Dungeon level, 0 = world map
- int Skill = 0; // Skill level
- int Task = 0; // Task set (-1 = none)
- int TaskCompleted = 0; // Task completed
- uint32 LuckyNumber = 0; // Value used for seeding
- int Attr[MAX_ATTR] = {}; // Attribute values
- double Object[MAX_OBJ] = {}; // Object counts
+ char _name[MAX_NAME + 1] = {}; // Player Name
+ Common::Point _worldPos; // World map position
+ Common::Point _dungeonPos; // Dungeon map position
+ Common::Point _dungeonDir; // Dungeon direction facing
+ byte _class = '?'; // Player class (F or M)
+ int _hpGain = 0; // HPs gained in dungeon
+ int _level = 0; // Dungeon level, 0 = world map
+ int _skill = 0; // Skill level
+ int _task = 0; // Task set (-1 = none)
+ bool _taskCompleted = 0; // Task completed
+ uint32 _luckyNumber = 0; // Value used for seeding
+ int _attr[MAX_ATTR] = {}; // Attribute values
+ double _object[MAX_OBJ] = {}; // Object counts
void init();
void rollAttributes();
@@ -128,7 +128,7 @@ struct PlayerInfo {
* World Map structure
*/
struct WorldMapInfo {
- byte Map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
+ byte _map[WORLD_MAP_SIZE][WORLD_MAP_SIZE] = {}; // Map information
void init(PlayerInfo &p);
int read(int x, int y) const;
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
index 236fa82bfa8..2214d3ccee6 100644
--- a/engines/ultima/ultima0/data/monster_logic.cpp
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -26,32 +26,32 @@ namespace Ultima {
namespace Ultima0 {
void MonsterLogic::checkForAttacks(PlayerInfo &p, DungeonMapInfo &d) {
- int i, Attacked;
- double Dist;
+ int attacked;
+ double dist;
// Go through all monsters
for (MonsterEntry &m : d._monsters) {
- Dist = pow(m._loc.x - p.Dungeon.x, 2); // Calculate Distance
- Dist = Dist + pow(m._loc.y - p.Dungeon.y, 2);
- Dist = sqrt(Dist);
+ dist = pow(m._loc.x - p._dungeonPos.x, 2); // Calculate Distance
+ dist = dist + pow(m._loc.y - p._dungeonPos.y, 2);
+ dist = sqrt(dist);
// If alive
if (m._alive) {
- Attacked = 0;
+ attacked = 0;
// If within range
- if (Dist < 1.3)
- Attacked = attack(m, p);
+ if (dist < 1.3)
+ attacked = attack(m, p);
// If didn't attack, then move
- if (Attacked == 0) {
+ if (attacked == 0) {
// Mimics only if near enough
- if (m._type != MN_MIMIC || Dist >= 3.0)
+ if (m._type != MN_MIMIC || dist >= 3.0)
move(m, p, d);
// Recovers if didn't attack
- if (m._strength < p.Level * p.Skill)
- m._strength = m._strength + p.Level;
+ if (m._strength < p._level * p._skill)
+ m._strength = m._strength + p._level;
}
}
}
@@ -73,17 +73,17 @@ int MonsterLogic::attack(MonsterEntry &m, PlayerInfo &p) {
MONSTER_INFO[m._type].Name);
n = urand() % 20; // Calculate hit chance
- if (p.Object[OB_SHIELD] > 0) n--;
- n = n - p.Attr[AT_STAMINA];
- n = n + m._type + p.Level;
+ if (p._object[OB_SHIELD] > 0) n--;
+ n = n - p._attr[AT_STAMINA];
+ n = n + m._type + p._level;
if (n < 0) {
// Missed !
msg += "Missed !\n";
} else {
// Hit !
n = urand() % m._type; // Calculate damage done.
- n = n + p.Level;
- p.Attr[AT_HP] -= n; // Adjust hit points
+ n = n + p._level;
+ p._attr[AT_HP] -= n; // Adjust hit points
msg += "Hit !!!\n";
}
@@ -96,13 +96,13 @@ void MonsterLogic::move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d) {
// Calculate direction
xi = yi = 0;
- if (p.Dungeon.x != m._loc.x)
- xi = (p.Dungeon.x > m._loc.x) ? 1 : -1;
- if (p.Dungeon.y != m._loc.y)
- yi = (p.Dungeon.y > m._loc.y) ? 1 : -1;
+ if (p._dungeonPos.x != m._loc.x)
+ xi = (p._dungeonPos.x > m._loc.x) ? 1 : -1;
+ if (p._dungeonPos.y != m._loc.y)
+ yi = (p._dungeonPos.y > m._loc.y) ? 1 : -1;
// Running away
- if (m._strength < p.Level * p.Skill) {
+ if (m._strength < p._level * p._skill) {
xi = -xi; yi = -yi;
}
@@ -124,14 +124,14 @@ void MonsterLogic::move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d) {
x = x + xi; y = y + yi; // Work out new position
if (!canMoveTo(d, x, y)) // Fail if can't move there
return;
- if (x == p.Dungeon.x && // Can't move onto us
- y == p.Dungeon.y) return;
+ if (x == p._dungeonPos.x && // Can't move onto us
+ y == p._dungeonPos.y) return;
m._loc.x = x; m._loc.y = y; // Move to new position
}
bool MonsterLogic::canMoveTo(DungeonMapInfo &d, int x, int y) {
Common::Point c;
- int t = d.Map[x][y]; // See what's there
+ int t = d._map[x][y]; // See what's there
if (!ISWALKTHRU(t)) return 0; // Can't walk through walls
c.x = x; c.y = y; // Set up coord structure
@@ -145,17 +145,17 @@ int MonsterLogic::steal(MonsterEntry &m, PlayerInfo &p) {
if (m._type == MN_GREMLIN) {
// HALVES the food.... aargh
- p.Object[OB_FOOD] = floor(p.Object[OB_FOOD]) / 2.0;
+ p._object[OB_FOOD] = floor(p._object[OB_FOOD]) / 2.0;
showLines("A Gremlin stole some food.\n");
} else if (m._type == MN_THIEF) {
// Figure out what stolen
do {
n = urand() % MAX_OBJ;
- } while (p.Object[n] == 0);
+ } while (p._object[n] == 0);
- p.Object[n]--; // Stole one
- s2 = OBJECT_INFO[n].Name; s1 = "a";
+ p._object[n]--; // Stole one
+ s2 = OBJECT_INFO[n]._name; s1 = "a";
if (strchr("aeiou", tolower(*s2))) s1 = "an";
if (n == 0) s1 = "some";
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index c2ad9a63cc6..971f671c3d9 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -45,25 +45,25 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
s->clear();
- double Level = 0;
+ double level = 0;
Common::Rect rIn, rOut;
Common::Point dir, pos, next;
int monster, front, left, right;
_DDRAWCalcRect(s, &rOut, 0);
- pos = player.Dungeon; // Get position
+ pos = player._dungeonPos; // Get position
// Iterate through drawing successively distinct tiles in the facing direction
do {
- Level++; // Next level
- _DDRAWCalcRect(s, &rIn, Level);
- next.x = pos.x + player.DungDir.x; // Next position
- next.y = pos.y + player.DungDir.y;
+ level++; // Next level
+ _DDRAWCalcRect(s, &rIn, level);
+ next.x = pos.x + player._dungeonDir.x; // Next position
+ next.y = pos.y + player._dungeonDir.y;
- dir = player.DungDir; MOVERotLeft(&dir); // To the left
- left = dungeon.Map[pos.x + dir.x][pos.y + dir.y];
+ dir = player._dungeonDir; MOVERotLeft(&dir); // To the left
+ left = dungeon._map[pos.x + dir.x][pos.y + dir.y];
MOVERotLeft(&dir); MOVERotLeft(&dir); // To the right
- right = dungeon.Map[pos.x + dir.x][pos.y + dir.y];
- front = dungeon.Map[next.x][next.y]; // What's in front ?
+ right = dungeon._map[pos.x + dir.x][pos.y + dir.y];
+ front = dungeon._map[next.x][next.y]; // What's in front ?
// Check for monster present
monster = dungeon.findMonster(pos);
@@ -72,11 +72,11 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
// Draw the dungeon
DRAWDungeon(s, &rOut, &rIn, left, front, right,
- dungeon.Map[pos.x][pos.y], monster);
+ dungeon._map[pos.x][pos.y], monster);
pos = next; // Next position down
rOut = rIn; // Last in is new out
- } while (Level < MAX_VIEW_DEPTH && ISDRAWOPEN(front));
+ } while (level < MAX_VIEW_DEPTH && ISDRAWOPEN(front));
}
void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double level) {
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
index c7770a4f5a4..1bf6446787f 100644
--- a/engines/ultima/ultima0/gfx/dungeon.h
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -37,7 +37,7 @@ private:
/**
* Calculate display rectangle
*/
- static void _DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double Level);
+ static void _DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double _level);
/**
* Rotate a direction left
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
index 73f5faa0eef..d176315ac2a 100644
--- a/engines/ultima/ultima0/gfx/map.cpp
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -46,14 +46,14 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
x1 = x, y1 = y;
} else {
// Which cell?
- x1 = player.World.x - grid / 2 + x;
- y1 = player.World.y - grid / 2 + y;
+ x1 = player._worldPos.x - grid / 2 + x;
+ y1 = player._worldPos.y - grid / 2 + y;
}
DRAWTile(s, r, map.read(x1, y1));
// Draw us if we're there
- if (x1 == player.World.x && y1 == player.World.y)
+ if (x1 == player._worldPos.x && y1 == player._worldPos.y)
DRAWTile(s, r, WT_PLAYER);
}
}
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index b6e5cb2d9f8..0ce5122137a 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -90,7 +90,7 @@ Common::Error Ultima0Engine::loadGameStream(Common::SeekableReadStream *stream)
Common::Serializer s(stream, nullptr);
syncSavegame(s);
- replaceView(_player.Level == 0 ? "WorldMap" : "Dungeon");
+ replaceView(_player._level == 0 ? "WorldMap" : "Dungeon");
return Common::kNoError;
}
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index ed6f59ddcd4..9e1b596a73d 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -57,7 +57,7 @@ void Attack::draw() {
s.writeString(Common::Point(1, 1), "Which Weapon? ");
if (_mode != WHICH_WEAPON)
- s.writeString(_weapon <= 0 ? "Hands" : OBJECT_INFO[_weapon].Name);
+ s.writeString(_weapon <= 0 ? "Hands" : OBJECT_INFO[_weapon]._name);
if (!_message.empty())
s.writeString(Common::Point(1, 2), _message);
@@ -71,7 +71,7 @@ bool Attack::msgKeypress(const KeypressMessage &msg) {
// Check for object selection, anything but food
objNum = -1;
for (uint i = OB_RAPIER; i < MAX_OBJ; ++i) {
- if (msg.keycode == OBJECT_INFO[i].keycode) {
+ if (msg.keycode == OBJECT_INFO[i]._keycode) {
objNum = i;
break;
}
@@ -116,23 +116,23 @@ void Attack::selectObject(int objNum) {
auto &player = g_engine->_player;
_weapon = objNum;
- _damage = (objNum <= 0) ? 0 : OBJECT_INFO[objNum].MaxDamage;
+ _damage = (objNum <= 0) ? 0 : OBJECT_INFO[objNum]._maxDamage;
// Must own an object
- if (player.Object[_weapon] == 0) {
+ if (player._object[_weapon] == 0) {
showMessage("Not owned.");
return;
}
// Mages are limited
- if (player.Class == 'M' && (objNum == OB_BOW || objNum == OB_RAPIER)) {
+ if (player._class == 'M' && (objNum == OB_BOW || objNum == OB_RAPIER)) {
showMessage("Mages can't use that.");
return;
}
// Use an amulet
if (objNum == OB_AMULET) {
- if (player.Class == 'M') {
+ if (player._class == 'M') {
// Mages can properly select the magic to use
_mode = AMULET;
@@ -167,17 +167,17 @@ void Attack::selectMagic(int magicNum) {
Common::String msg;
if (urand() % 5 == 0) {
msg = "Last charge on this Amulet.\n";
- player.Object[OB_AMULET]--;
+ player._object[OB_AMULET]--;
}
switch (magicNum) {
case 0:
// Ladder up
- dungeon.Map[player.Dungeon.x][player.Dungeon.y] = DT_LADDERUP;
+ dungeon._map[player._dungeonPos.x][player._dungeonPos.y] = DT_LADDERUP;
break;
case 1:
// Ladder down
- dungeon.Map[player.Dungeon.x][player.Dungeon.y] = DT_LADDERDN;
+ dungeon._map[player._dungeonPos.x][player._dungeonPos.y] = DT_LADDERDN;
break;
case 2:
// Amulet Attack
@@ -189,16 +189,16 @@ void Attack::selectMagic(int magicNum) {
case 0:
msg += "You have been turned into a Toad.\n";
for (i = AT_STRENGTH; i <= AT_WISDOM; i++)
- player.Attr[i] = 3;
+ player._attr[i] = 3;
break;
case 1:
msg += "You have been turned into a Lizard Man.\n";
for (i = AT_HP; i <= AT_WISDOM; i++)
- player.Attr[i] = floor(player.Attr[i] * 5 / 2);
+ player._attr[i] = floor(player._attr[i] * 5 / 2);
break;
case 2:
msg += "Backfire !!\n";
- player.Attr[AT_HP] = floor(player.Attr[AT_HP]) / 2;
+ player._attr[AT_HP] = floor(player._attr[AT_HP]) / 2;
break;
}
break;
@@ -215,12 +215,12 @@ void Attack::selectMagic(int magicNum) {
void Attack::attackMissile() {
const auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
- Common::Point c1, c = player.Dungeon;
+ Common::Point c1, c = player._dungeonPos;
int Dist = -1;
// A maximum distance of 5
for (int y = 0; y < 5; y++) {
- c += player.DungDir;
+ c += player._dungeonDir;
int n = dungeon.findMonster(c); // Monster there ?
if (n >= 0) {
c1 = c;
@@ -228,7 +228,7 @@ void Attack::attackMissile() {
}
// If wall, or door, stop
- if (!ISDRAWOPEN(dungeon.Map[c.x][c.y]))
+ if (!ISDRAWOPEN(dungeon._map[c.x][c.y]))
break;
}
@@ -244,7 +244,7 @@ void Attack::attackMissile() {
void Attack::attackWeapon() {
const auto &player = g_engine->_player;
- Common::Point c = player.Dungeon + player.DungDir;
+ Common::Point c = player._dungeonPos + player._dungeonDir;
attackHitMonster(c);
}
@@ -265,13 +265,13 @@ void Attack::attackHitMonster(const Common::Point &c) {
// Get weaponry info
damage = 0;
if (_weapon >= 0 && _weapon != OB_AMULET)
- damage = OBJECT_INFO[_weapon].MaxDamage;
+ damage = OBJECT_INFO[_weapon]._maxDamage;
if (_weapon == OB_AMULET)
// Amulet Special Case
- damage = 10 + player.Level;
+ damage = 10 + player._level;
// If no, or not dexterous
- if (monNum < 0 || player.Attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player.Level) {
+ if (monNum < 0 || player._attr[AT_DEXTERITY] - ((int)urand() % 25) < n + player._level) {
// Then a miss.
_message += "\nMissed!";
_mode = DONE;
@@ -287,7 +287,7 @@ void Attack::attackHitMonster(const Common::Point &c) {
n = 0;
if (damage > 0)
n = (urand() % damage);
- n = n + player.Attr[AT_STRENGTH] / 5;
+ n = n + player._attr[AT_STRENGTH] / 5;
m->_strength = m->_strength - n; // Lose them
if (m->_strength < 0)
@@ -298,14 +298,14 @@ void Attack::attackHitMonster(const Common::Point &c) {
// Killed it ?
if (m->_strength == 0) {
m->_alive = false; // It has ceased to be
- int gold = (m->_type + player.Level); // Amount of gold
+ int gold = (m->_type + player._level); // Amount of gold
_message += Common::String::format("You get %d pieces of eight.\n", gold);
- player.Attr[AT_GOLD] += gold;
+ player._attr[AT_GOLD] += gold;
- player.HPGain += (m->_type * player.Level) / 2; // Calculate Gain
+ player._hpGain += (m->_type * player._level) / 2; // Calculate Gain
- if (m->_type == player.Task) // Check done LB's task
- player.TaskCompleted = 1;
+ if (m->_type == player._task) // Check done LB's task
+ player._taskCompleted = true;
}
_mode = DONE;
diff --git a/engines/ultima/ultima0/views/castle.cpp b/engines/ultima/ultima0/views/castle.cpp
index 9afe36791af..651c9450adf 100644
--- a/engines/ultima/ultima0/views/castle.cpp
+++ b/engines/ultima/ultima0/views/castle.cpp
@@ -34,9 +34,9 @@ static const char *GO_FORTH = " Go now upon this quest, and may\n"
bool Castle::msgFocus(const FocusMessage &msg) {
const auto &player = g_engine->_player;
- if (Common::String(player.Name).empty())
+ if (Common::String(player._name).empty())
_mode = NAMING;
- else if (player.TaskCompleted) {
+ else if (player._taskCompleted) {
_mode = TASK_COMPLETE;
} else {
_mode = TASK_INCOMPLETE;
@@ -95,17 +95,17 @@ void Castle::taskCompleted() {
auto s = getSurface();
s.writeString(Common::Point(0, 3), "Aaaahhhh.... ");
- s.writeString(player.Name);
+ s.writeString(player._name);
s.writeString("\n\nThou has accomplished\nthy quest.\n\n");
- if (player.Task == MAX_MONSTERS) {
+ if (player._task == MAX_MONSTERS) {
s.writeString("Thou hast proved thyself worthy of\n"
"Knighthood, continue if thou doth wish\n"
"but thou hast accomplished the\n"
"main objective of the game.\n\n"
"Now, maybe thou art foolhardy enough to\n"
"try difficulty level ");
- s.writeString(Common::String::format("%s.", player.Skill + 1));
+ s.writeString(Common::String::format("%s.", player._skill + 1));
} else {
nextTask();
@@ -131,7 +131,7 @@ void Castle::taskIncomplete() {
"Why hast thou returned ?\n"
"Thou must kill ");
s.setColor(C_VIOLET);
- s.writeString(getTaskName(player.Task));
+ s.writeString(getTaskName(player._task));
s.setColor(C_TEXT_DEFAULT);
s.writeString("\n\nGo now and complete thy quest");
@@ -151,7 +151,7 @@ bool Castle::msgKeypress(const KeypressMessage &msg) {
if (msg.keycode == Common::KEYCODE_BACKSPACE && !_playerName.empty()) {
_playerName.deleteLastChar();
} else if (msg.keycode == Common::KEYCODE_RETURN && !_playerName.empty()) {
- Common::strcpy_s(player.Name, _playerName.c_str());
+ Common::strcpy_s(player._name, _playerName.c_str());
_mode = GRAND_ADVENTURE;
} else if (Common::isAlpha(msg.ascii) && _playerName.size() < MAX_NAME) {
_playerName += msg.ascii;
@@ -189,12 +189,12 @@ bool Castle::msgAction(const ActionMessage &msg) {
void Castle::nextTask() {
auto &player = g_engine->_player;
- player.Task++;
- player.TaskCompleted = 0;
+ player._task++;
+ player._taskCompleted = false;
// LB gives you extra attributes
for (int i = 0; i < MAX_ATTR; i++)
- player.Attr[i]++;
+ player._attr[i]++;
}
Common::String Castle::getTaskName(int taskNum) const {
diff --git a/engines/ultima/ultima0/views/create_character.cpp b/engines/ultima/ultima0/views/create_character.cpp
index dec8c0b440a..e51fd95c9f2 100644
--- a/engines/ultima/ultima0/views/create_character.cpp
+++ b/engines/ultima/ultima0/views/create_character.cpp
@@ -43,7 +43,7 @@ void CreateCharacter::draw() {
if (_mode == LUCKY_NUMBER)
s.writeString(_input);
else
- s.writeString(Common::String::format("%d", player.LuckyNumber));
+ s.writeString(Common::String::format("%d", player._luckyNumber));
// Level of play
if (_mode >= LEVEL) {
@@ -51,7 +51,7 @@ void CreateCharacter::draw() {
if (_mode == LEVEL)
s.writeString(_input);
else
- s.writeString(Common::String::format("%d", player.Skill));
+ s.writeString(Common::String::format("%d", player._skill));
}
// Stats
@@ -60,7 +60,7 @@ void CreateCharacter::draw() {
Common::String line = ATTRIB_NAMES[i];
while (line.size() < 15)
line += ".";
- line += Common::String::format("%d", player.Attr[i]);
+ line += Common::String::format("%d", player._attr[i]);
s.writeString(Common::Point(1, 9 + i), line);
}
@@ -85,13 +85,13 @@ bool CreateCharacter::msgKeypress(const KeypressMessage &msg) {
redraw();
} else if (msg.keycode == Common::KEYCODE_RETURN && !_input.empty()) {
if (_mode == LUCKY_NUMBER) {
- player.LuckyNumber = atoi(_input.c_str());
+ player._luckyNumber = atoi(_input.c_str());
_input.clear();
_mode = LEVEL;
redraw();
} else {
- player.Skill = atoi(_input.c_str());
- if (player.Skill >= 1 && player.Skill <= 10) {
+ player._skill = atoi(_input.c_str());
+ if (player._skill >= 1 && player._skill <= 10) {
_input.clear();
_mode = STATS;
player.rollAttributes();
@@ -107,7 +107,7 @@ bool CreateCharacter::msgKeypress(const KeypressMessage &msg) {
redraw();
} else if (_mode == CLASS && (msg.keycode == Common::KEYCODE_f ||
msg.keycode == Common::KEYCODE_m)) {
- player.Class = toupper(msg.ascii);
+ player._class = toupper(msg.ascii);
characterDone();
}
diff --git a/engines/ultima/ultima0/views/dead.cpp b/engines/ultima/ultima0/views/dead.cpp
index 181167dfaea..06fd830639f 100644
--- a/engines/ultima/ultima0/views/dead.cpp
+++ b/engines/ultima/ultima0/views/dead.cpp
@@ -36,7 +36,7 @@ void Dead::draw() {
auto s = getSurface();
s.clear();
- const char *name = player.Name;
+ const char *name = player._name;
if (*name == '\0')
name = "the peasant";
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index ef0aed6a23b..01cbf5837e5 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -73,12 +73,12 @@ void Dungeon::drawMinimap(Graphics::ManagedSurface &mapArea) {
for (int x = 0; x < DUNGEON_MAP_SIZE; ++x) {
const Common::Rect r(x * MINIMAP_TILE_SIZE, y * MINIMAP_TILE_SIZE,
(x + 1) * MINIMAP_TILE_SIZE, (y + 1) * MINIMAP_TILE_SIZE);
- if (x == player.Dungeon.x && y == player.Dungeon.y) {
+ if (x == player._dungeonPos.x && y == player._dungeonPos.y) {
mapArea.fillRect(r, C_CYAN);
} else if (dungeon.findMonster(Common::Point(x, y)) > 0) {
mapArea.fillRect(r, C_RED);
} else {
- tile = dungeon.Map[x][y];
+ tile = dungeon._map[x][y];
if (tile == DT_SPACE || tile == DT_DOOR || tile == DT_HIDDENDOOR)
mapArea.fillRect(r, C_BLACK);
@@ -167,7 +167,7 @@ void Dungeon::endOfTurn() {
auto &player = g_engine->_player;
auto &dungeon = g_engine->_dungeon;
- if (player.Attr[AT_HP] <= 0) {
+ if (player._attr[AT_HP] <= 0) {
replaceView("Dead");
return;
}
@@ -175,8 +175,8 @@ void Dungeon::endOfTurn() {
// Check for monster attacks
MonsterLogic::checkForAttacks(player, dungeon);
- player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 0.1, 0.0);
- if (player.Object[OB_FOOD] == 0) {
+ player._object[OB_FOOD] = MAX(player._object[OB_FOOD] - 0.1, 0.0);
+ if (player._object[OB_FOOD] == 0) {
showMessage("You have starved...");
delaySeconds(1);
}
@@ -187,38 +187,38 @@ void Dungeon::endOfTurn() {
void Dungeon::moveForward() {
auto &dungeon = g_engine->_dungeon;
auto &player = g_engine->_player;
- Common::Point newPos = player.Dungeon + player.DungDir;
+ Common::Point newPos = player._dungeonPos + player._dungeonDir;
- if (!ISWALKTHRU(dungeon.Map[newPos.x][newPos.y]) || dungeon.findMonster(newPos) >= 0)
+ if (!ISWALKTHRU(dungeon._map[newPos.x][newPos.y]) || dungeon.findMonster(newPos) >= 0)
return;
// Set new position
- player.Dungeon = newPos;
+ player._dungeonPos = newPos;
// What's here ?
- int n = dungeon.Map[player.Dungeon.x][player.Dungeon.y];
+ int n = dungeon._map[player._dungeonPos.x][player._dungeonPos.y];
if (n == DT_PIT) {
// Fell in a pit
- player.Level++; // Down a level
+ player._level++; // Down a level
showMessage("Aaarrrgghhh! A Trap !");
- showLines(Common::String::format("Falling to Level %d.", player.Level));
+ showLines(Common::String::format("Falling to Level %d.", player._level));
- player.Attr[AT_HP] -= (3 + urand() % (3 * player.Level));
+ player._attr[AT_HP] -= (3 + urand() % (3 * player._level));
dungeon.create(player); // Create the new level
} else if (n == DT_GOLD) {
// Gold here
// Remove the gold
- dungeon.Map[player.Dungeon.x][player.Dungeon.y] = DT_SPACE;
- int gold = (urand() % (5 * player.Level)) + player.Level; // Calculate amount
+ dungeon._map[player._dungeonPos.x][player._dungeonPos.y] = DT_SPACE;
+ int gold = (urand() % (5 * player._level)) + player._level; // Calculate amount
showMessage("Gold !!!!!");
Common::String msg = Common::String::format("%d pieces of eight ", gold);
- player.Attr[AT_GOLD] = MIN<int>(player.Attr[AT_GOLD] + gold, 9999); // Add to total
+ player._attr[AT_GOLD] = MIN<int>(player._attr[AT_GOLD] + gold, 9999); // Add to total
if (gold > 0) {
int objNum = urand() % MAX_OBJ; // Decide which object
- const char *name = OBJECT_INFO[objNum].Name;
+ const char *name = OBJECT_INFO[objNum]._name;
const char *prefix = "a"; // Decide a,an or some
if (strchr("aeiou", tolower(*name)))
prefix = "an";
@@ -226,7 +226,7 @@ void Dungeon::moveForward() {
prefix = "some";
msg += Common::String::format("\nand %s %s.", prefix, name);
- player.Object[objNum] = MIN<int>(player.Object[objNum] + 1, 9999); // Bump the total
+ player._object[objNum] = MIN<int>(player._object[objNum] + 1, 9999); // Bump the total
}
showLines(msg);
@@ -238,37 +238,37 @@ void Dungeon::interact() {
auto &player = g_engine->_player;
// Identify what's there
- int t = dungeon.Map[player.Dungeon.x][player.Dungeon.y];
+ int t = dungeon._map[player._dungeonPos.x][player._dungeonPos.y];
bool done = false;
if (t == DT_LADDERUP) {
// Climbing up a ladder
- player.Level--;
+ player._level--;
done = true;
- if (player.Level == 0) {
+ if (player._level == 0) {
showMessage("Leave Dungeon.");
- if (player.HPGain > 0)
- showLines(Common::String::format("Thou has gained %d HP", player.HPGain));
- player.Attr[AT_HP] += player.HPGain;
- player.HPGain = 0;
+ if (player._hpGain > 0)
+ showLines(Common::String::format("Thou has gained %d HP", player._hpGain));
+ player._attr[AT_HP] += player._hpGain;
+ player._hpGain = 0;
delaySeconds(1); // Brief delay to show text before leaving dungeon
} else {
showMessage("Use Ladder");
- showLines(Common::String::format("Go up to Level %d.", player.Level));
+ showLines(Common::String::format("Go up to Level %d.", player._level));
}
} else if (t == DT_LADDERDN) {
// Climbing down a ladder
- player.Level++;
+ player._level++;
done = true;
showMessage("Use Ladder");
- showLines(Common::String::format("Go down to Level %d.\n", player.Level));
+ showLines(Common::String::format("Go down to Level %d.\n", player._level));
}
if (done) {
- if (player.Level > 0)
+ if (player._level > 0)
// New Dungeon Map Required
dungeon.create(player);
} else {
@@ -279,7 +279,7 @@ void Dungeon::interact() {
void Dungeon::timeout() {
const auto &player = g_engine->_player;
- replaceView((player.Level == 0) ? "WorldMap" : "Dead");
+ replaceView((player._level == 0) ? "WorldMap" : "Dead");
}
} // namespace Views
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
index aba80eebf1e..9a25f2b6532 100644
--- a/engines/ultima/ultima0/views/info.cpp
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -48,7 +48,7 @@ void Info::draw() {
// Price/Damage/Item
for (i = 0; i < MAX_OBJ; ++i) {
s.writeString(Common::Point(5, 18 + i),
- Common::String::format("%d", OBJECT_INFO[i].Cost));
+ Common::String::format("%d", OBJECT_INFO[i]._cost));
if (i == 0) {
s.writeString(" For 10");
@@ -57,10 +57,10 @@ void Info::draw() {
s.writeString(Common::Point(15, 18 + i), "?????");
} else {
s.writeString(Common::Point(15, 18 + i),
- Common::String::format("1-%d", OBJECT_INFO[i].MaxDamage));
+ Common::String::format("1-%d", OBJECT_INFO[i]._maxDamage));
}
- s.writeString(Common::Point(25, 18 + i), OBJECT_INFO[i].Name);
+ s.writeString(Common::Point(25, 18 + i), OBJECT_INFO[i]._name);
}
// Headers
@@ -73,10 +73,10 @@ void Info::draw() {
s.setColor(C_VIOLET);
for (i = 0; i < MAX_ATTR; ++i)
s.writeString(Common::Point(15, 4 + i),
- Common::String::format("%d", player.Attr[i]));
+ Common::String::format("%d", player._attr[i]));
for (i = 0; i < MAX_OBJ; ++i)
s.writeString(Common::Point(21, 4 + i),
- Common::String::format("%4d-", (int)player.Object[i]));
+ Common::String::format("%4d-", (int)player._object[i]));
s.writeString(Common::Point(18, 10), "Q-Quit");
}
@@ -85,8 +85,8 @@ bool Info::msgKeypress(const KeypressMessage &msg) {
return false;
for (int i = 0; i < MAX_OBJ; ++i) {
- if (msg.keycode == OBJECT_INFO[i].keycode ||
- (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i].Cost)) {
+ if (msg.keycode == OBJECT_INFO[i]._keycode ||
+ (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i]._cost)) {
selectObject(i);
return true;
}
@@ -102,7 +102,7 @@ bool Info::msgKeypress(const KeypressMessage &msg) {
void Info::leave() {
const auto &player = g_engine->_player;
- replaceView(player.Level == 0 ? "WorldMap" : "DungeonMap");
+ replaceView(player._level == 0 ? "WorldMap" : "DungeonMap");
}
bool Info::msgAction(const ActionMessage &msg) {
diff --git a/engines/ultima/ultima0/views/info.h b/engines/ultima/ultima0/views/info.h
index 72b7411c89a..abeae91492a 100644
--- a/engines/ultima/ultima0/views/info.h
+++ b/engines/ultima/ultima0/views/info.h
@@ -42,12 +42,12 @@ class Info : public View {
private:
InfoObject _options[6] = {
- InfoObject(this, Common::Point(26, 4), 0, OBJECT_INFO[0].Name),
- InfoObject(this, Common::Point(26, 5), 1, OBJECT_INFO[1].Name),
- InfoObject(this, Common::Point(26, 6), 2, OBJECT_INFO[2].Name),
- InfoObject(this, Common::Point(26, 7), 3, OBJECT_INFO[3].Name),
- InfoObject(this, Common::Point(26, 8), 4, OBJECT_INFO[4].Name),
- InfoObject(this, Common::Point(26, 9), 5, OBJECT_INFO[5].Name)
+ InfoObject(this, Common::Point(26, 4), 0, OBJECT_INFO[0]._name),
+ InfoObject(this, Common::Point(26, 5), 1, OBJECT_INFO[1]._name),
+ InfoObject(this, Common::Point(26, 6), 2, OBJECT_INFO[2]._name),
+ InfoObject(this, Common::Point(26, 7), 3, OBJECT_INFO[3]._name),
+ InfoObject(this, Common::Point(26, 8), 4, OBJECT_INFO[4]._name),
+ InfoObject(this, Common::Point(26, 9), 5, OBJECT_INFO[5]._name)
};
protected:
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index 3d22c5c9c60..46702c84e58 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -47,9 +47,9 @@ void Status::draw() {
s.writeString(Common::Point(28, 2), "H.P.=");
s.writeString(Common::Point(28, 3), "Gold=");
s.setColor(C_VIOLET);
- s.writeString(Common::Point(33, 1), Common::String::format("%d", (int)player.Object[OB_FOOD]));
- s.writeString(Common::Point(33, 2), Common::String::format("%d", player.Attr[AT_HP]));
- s.writeString(Common::Point(33, 3), Common::String::format("%d", player.Attr[AT_GOLD]));
+ s.writeString(Common::Point(33, 1), Common::String::format("%d", (int)player._object[OB_FOOD]));
+ s.writeString(Common::Point(33, 2), Common::String::format("%d", player._attr[AT_HP]));
+ s.writeString(Common::Point(33, 3), Common::String::format("%d", player._attr[AT_GOLD]));
}
bool Status::msgGame(const GameMessage &msg) {
@@ -76,7 +76,7 @@ void DungeonStatus::draw() {
auto s = getSurface();
// Display the current direction
- if (player.Level > 0)
+ if (player._level > 0)
s.writeString(Common::Point(15, 0), DIRECTION_NAMES[player.dungeonDir()]);
// Draw any extra lines
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
index 2aa54c189d1..57fe20417c1 100644
--- a/engines/ultima/ultima0/views/town.cpp
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -56,7 +56,7 @@ void Town::selectObject(int item) {
const auto &obj = OBJECT_INFO[item];
// Some things mages can't use
- if (player.Class == 'M') {
+ if (player._class == 'M') {
if (item == OB_BOW || item == OB_RAPIER) {
_message = MAGES_CANT_USE;
redraw();
@@ -64,12 +64,12 @@ void Town::selectObject(int item) {
}
}
- if (obj.Cost > player.Attr[AT_GOLD]) {
+ if (obj._cost > player._attr[AT_GOLD]) {
_message = NOT_ENOUGH;
} else {
- player.Attr[AT_GOLD] -= obj.Cost; // Lose the money
- player.Object[item] = MIN<int>(player.Object[item] + (item == OB_FOOD ? 10 : 1), 999);
+ player._attr[AT_GOLD] -= obj._cost; // Lose the money
+ player._object[item] = MIN<int>(player._object[item] + (item == OB_FOOD ? 10 : 1), 999);
_message = THANK_YOU;
}
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index eb647de469c..c57dd1a44de 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -125,12 +125,12 @@ bool WorldMap::msgKeypress(const KeypressMessage &msg) {
void WorldMap::endOfTurn() {
auto &player = g_engine->_player;
- if (player.Attr[AT_HP] <= 0) {
+ if (player._attr[AT_HP] <= 0) {
replaceView("Dead");
} else {
- player.Object[OB_FOOD] = MAX(player.Object[OB_FOOD] - 1.0, 0.0);
- if (player.Object[OB_FOOD] == 0) {
+ player._object[OB_FOOD] = MAX(player._object[OB_FOOD] - 1.0, 0.0);
+ if (player._object[OB_FOOD] == 0) {
showMessage("You have starved...");
delaySeconds(1);
}
@@ -142,22 +142,22 @@ void WorldMap::timeout() {
auto &player = g_engine->_player;
auto &dungeon = g_engine->_dungeon;
- if (player.Attr[AT_HP] <= 0 || player.Object[OB_FOOD] <= 0) {
+ if (player._attr[AT_HP] <= 0 || player._object[OB_FOOD] <= 0) {
// Timeout from displaying player was killed
replaceView("Dead");
} else {
// Otherwise a timeout from entering a location
- int t = map.read(player.World.x, player.World.y);
+ int t = map.read(player._worldPos.x, player._worldPos.y);
switch (t) {
case WT_TOWN:
replaceView("Town");
break;
case WT_DUNGEON:
- player.Level = 1; // Go to level 1
- player.Dungeon.x = 1; // Set initial position
- player.Dungeon.y = 1;
- player.DungDir.x = 1; // And direction
- player.DungDir.y = 0;
+ player._level = 1; // Go to level 1
+ player._dungeonPos.x = 1; // Set initial position
+ player._dungeonPos.y = 1;
+ player._dungeonDir.x = 1; // And direction
+ player._dungeonDir.y = 0;
dungeon.create(player);
replaceView("Dungeon");
@@ -176,15 +176,15 @@ void WorldMap::move(int xi, int yi) {
auto &map = g_engine->_worldMap;
// Calculate new position
- int x1 = player.World.x + xi;
- int y1 = player.World.y + yi;
+ int x1 = player._worldPos.x + xi;
+ int y1 = player._worldPos.y + yi;
if (map.read(x1, y1) == WT_MOUNTAIN) {
showMessage("You can't pass the mountains.");
} else {
// Move
- player.World.x = x1;
- player.World.y = y1;
+ player._worldPos.x = x1;
+ player._worldPos.y = y1;
redraw();
}
}
@@ -193,7 +193,7 @@ void WorldMap::enter() {
const auto &player = g_engine->_player;
const auto &map = g_engine->_worldMap;
- int t = map.read(player.World.x, player.World.y);
+ int t = map.read(player._worldPos.x, player._worldPos.y);
switch (t) {
case WT_TOWN:
showMessage("Enter Town.");
Commit: 40efc19b9b693cfaa9a88048f9952608a8c86184
https://github.com/scummvm/scummvm/commit/40efc19b9b693cfaa9a88048f9952608a8c86184
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:30+11:00
Commit Message:
ULTIMA: ULTIMA0: Add missing monster data from savegames
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/data/monster_logic.cpp
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/castle.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index ffc1ed1d58f..02fb59477ae 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -296,9 +296,19 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
}
void DungeonMapInfo::synchronize(Common::Serializer &s) {
+ // Map data
for (int y = 0; y < DUNGEON_MAP_SIZE; ++y)
for (int x = 0; x < DUNGEON_MAP_SIZE; ++x)
s.syncAsByte(_map[x][y]);
+
+ // Monsters
+ uint count = _monsters.size();
+ s.syncAsByte(count);
+ if (s.isLoading())
+ _monsters.resize(count);
+
+ for (auto &m : _monsters)
+ m.synchronize(s);
}
int DungeonMapInfo::findMonster(const Common::Point &c) const {
@@ -312,5 +322,15 @@ int DungeonMapInfo::findMonster(const Common::Point &c) const {
return n;
}
+/*-------------------------------------------------------------------*/
+
+void MonsterEntry::synchronize(Common::Serializer &s) {
+ s.syncAsByte(_loc.x);
+ s.syncAsByte(_loc.y);
+ s.syncAsByte(_type);
+ s.syncAsByte(_strength);
+ s.syncAsByte(_alive);
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 761165ec063..5b222bf5b7b 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -42,7 +42,8 @@ struct ObjectInfo {
Common::KeyCode _keycode;
};
struct MonsterInfo {
- const char *Name; int _level;
+ const char *_name;
+ int _level;
};
extern const ObjectInfo OBJECT_INFO[];
@@ -58,6 +59,8 @@ struct MonsterEntry {
int _type = 0; // Monster type
int _strength = 0; // Strength
bool _alive = false; // Alive flag
+
+ void synchronize(Common::Serializer &s);
};
/**
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
index 2214d3ccee6..c16d74f7a43 100644
--- a/engines/ultima/ultima0/data/monster_logic.cpp
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -70,7 +70,7 @@ int MonsterLogic::attack(MonsterEntry &m, PlayerInfo &p) {
return steal(m, p);
Common::String msg = Common::String::format("You are being attacked by a %s !!!.\n",
- MONSTER_INFO[m._type].Name);
+ MONSTER_INFO[m._type]._name);
n = urand() % 20; // Calculate hit chance
if (p._object[OB_SHIELD] > 0) n--;
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index 9e1b596a73d..7f6f290c491 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -293,7 +293,7 @@ void Attack::attackHitMonster(const Common::Point &c) {
if (m->_strength < 0)
m->_strength = 0;
_message += Common::String::format("%s's Hit\nPoints now %d.\n",
- MONSTER_INFO[m->_type].Name, m->_strength);
+ MONSTER_INFO[m->_type]._name, m->_strength);
// Killed it ?
if (m->_strength == 0) {
diff --git a/engines/ultima/ultima0/views/castle.cpp b/engines/ultima/ultima0/views/castle.cpp
index 651c9450adf..02720b11da9 100644
--- a/engines/ultima/ultima0/views/castle.cpp
+++ b/engines/ultima/ultima0/views/castle.cpp
@@ -198,7 +198,7 @@ void Castle::nextTask() {
}
Common::String Castle::getTaskName(int taskNum) const {
- Common::String mons = MONSTER_INFO[taskNum].Name;
+ Common::String mons = MONSTER_INFO[taskNum]._name;
return Common::String::format("%s %s",
strchr("aeiou", tolower(mons.firstChar())) != nullptr ? "an" : "a",
Commit: 77da654dd67276beeb0be8622904eb42ea5dd276
https://github.com/scummvm/scummvm/commit/77da654dd67276beeb0be8622904eb42ea5dd276
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Method renaming janitorial
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/dungeon.h
engines/ultima/ultima0/gfx/map.cpp
engines/ultima/ultima0/gfx/map.h
engines/ultima/ultima0/gfx/monster.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 02fb59477ae..d974b3281b4 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -276,7 +276,7 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
if (RND() > 0.4)
return;
- // Fill in details */
+ // Fill in details
MonsterEntry m;
m._type = Type;
m._strength = level + 3 + player._level;
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 971f671c3d9..5105fd29902 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -49,19 +49,20 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
Common::Rect rIn, rOut;
Common::Point dir, pos, next;
int monster, front, left, right;
- _DDRAWCalcRect(s, &rOut, 0);
+ calcRect(s, &rOut, 0);
pos = player._dungeonPos; // Get position
// Iterate through drawing successively distinct tiles in the facing direction
do {
- level++; // Next level
- _DDRAWCalcRect(s, &rIn, level);
+ level++; // Next level
+ calcRect(s, &rIn, level);
+
next.x = pos.x + player._dungeonDir.x; // Next position
next.y = pos.y + player._dungeonDir.y;
- dir = player._dungeonDir; MOVERotLeft(&dir); // To the left
+ dir = player._dungeonDir; rotateLeft(&dir); // To the left
left = dungeon._map[pos.x + dir.x][pos.y + dir.y];
- MOVERotLeft(&dir); MOVERotLeft(&dir); // To the right
+ rotateLeft(&dir); rotateLeft(&dir); // To the right
right = dungeon._map[pos.x + dir.x][pos.y + dir.y];
front = dungeon._map[next.x][next.y]; // What's in front ?
@@ -71,7 +72,7 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
monster = dungeon._monsters[monster]._type;
// Draw the dungeon
- DRAWDungeon(s, &rOut, &rIn, left, front, right,
+ drawDungeon(s, &rOut, &rIn, left, front, right,
dungeon._map[pos.x][pos.y], monster);
pos = next; // Next position down
@@ -79,7 +80,7 @@ void Dungeon::draw(Graphics::ManagedSurface *s) {
} while (level < MAX_VIEW_DEPTH && ISDRAWOPEN(front));
}
-void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double level) {
+void Dungeon::calcRect(Graphics::ManagedSurface *s, Common::Rect *r, double level) {
const int centerX = s->w / 2, centerY = s->h / 2;
int xWidth = s->w / (level + 1);
int yWidth = s->h / (level + 1);
@@ -91,7 +92,7 @@ void Dungeon::_DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, doubl
r->bottom = centerY + yWidth / 2;
}
-void Dungeon::MOVERotLeft(Common::Point *dir) {
+void Dungeon::rotateLeft(Common::Point *dir) {
int t;
if (dir->y == 0) dir->x = -dir->x;
t = dir->x;
@@ -99,7 +100,7 @@ void Dungeon::MOVERotLeft(Common::Point *dir) {
dir->y = t;
}
-void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
+void Dungeon::drawDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
Common::Rect *rIn, int left, int centre, int right, int room, int monster) {
int x1, y1, x, y, y2;
Common::Rect r;
@@ -141,25 +142,25 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
}
// Set up for left side
- _DRAWSetRange(rOut->left, rIn->left,
+ setRange(rOut->left, rIn->left,
rOut->bottom,
rOut->bottom - rOut->top,
rIn->bottom - rIn->top);
- _DRAWWall(s, left);
+ drawWall(s, left);
// Set up for right side
- _DRAWSetRange(rIn->right, rOut->right,
+ setRange(rIn->right, rOut->right,
rIn->bottom,
rIn->bottom - rIn->top,
rOut->bottom - rOut->top);
- _DRAWWall(s, right);
+ drawWall(s, right);
// Set up for centre
- _DRAWSetRange(rIn->left, rIn->right,
+ setRange(rIn->left, rIn->right,
rIn->bottom,
rIn->bottom - rIn->top,
rIn->bottom - rIn->top);
- _DRAWWall(s, centre);
+ drawWall(s, centre);
if (room == DT_LADDERUP) {
r = Common::Rect(rOut->left, rOut->top, rOut->right, rIn->top);
@@ -205,34 +206,34 @@ void Dungeon::DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
// Draw the gold (as a mimic)
if (room == DT_GOLD) {
HWColour(COL_MONSTER);
- Monster::draw(s, (r.left + r.right) / 2, r.top, MN_MIMIC, Scale);
+ Monster::draw(s, (r.left + r.right) / 2, r.bottom, MN_MIMIC, Scale);
}
}
-void Dungeon::_DRAWSetRange(int x1, int x2, int y, int yd1, int yd2) {
+void Dungeon::setRange(int x1, int x2, int y, int yd1, int yd2) {
_xLeft = x1; _xRight = x2; // Set x ranges
_yBottom = y; // Set lower left y value
_yDiffLeft = yd1; _yDiffRight = yd2; // Set difference for either end
}
-void Dungeon::_DRAWWall(Graphics::ManagedSurface *s, int n) {
+void Dungeon::drawWall(Graphics::ManagedSurface *s, int n) {
int x1, y1, x2, y2;
int color = 0;
if (n == DT_DOOR) {
HWColour(COL_DOOR);
x1 = 35; y1 = 0; x2 = 35; y2 = 60;
- _DRAWConvert(&x1, &y1);
- _DRAWConvert(&x2, &y2);
+ drawConvert(&x1, &y1);
+ drawConvert(&x2, &y2);
HWLine(x1, y1, x2, y2);
- x1 = 65; y1 = 60; _DRAWConvert(&x1, &y1);
+ x1 = 65; y1 = 60; drawConvert(&x1, &y1);
HWLine(x1, y1, x2, y2);
- x2 = 65; y2 = 0; _DRAWConvert(&x2, &y2);
+ x2 = 65; y2 = 0; drawConvert(&x2, &y2);
HWLine(x1, y1, x2, y2);
}
}
-void Dungeon::_DRAWConvert(int *px, int *py) {
+void Dungeon::drawConvert(int *px, int *py) {
long x, y, yd; // Longs for overflow in 16 bit
x = (_xRight - _xLeft); // Calculate width
x = x * (*px) / 100 + _xLeft; // Work out horiz value
diff --git a/engines/ultima/ultima0/gfx/dungeon.h b/engines/ultima/ultima0/gfx/dungeon.h
index 1bf6446787f..1890d6c907f 100644
--- a/engines/ultima/ultima0/gfx/dungeon.h
+++ b/engines/ultima/ultima0/gfx/dungeon.h
@@ -37,33 +37,33 @@ private:
/**
* Calculate display rectangle
*/
- static void _DDRAWCalcRect(Graphics::ManagedSurface *s, Common::Rect *r, double _level);
+ static void calcRect(Graphics::ManagedSurface *s, Common::Rect *r, double _level);
/**
* Rotate a direction left
*/
- static void MOVERotLeft(Common::Point *Dir);
+ static void rotateLeft(Common::Point *Dir);
/**
* Draw part of dungeon
*/
- static void DRAWDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
+ static void drawDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
Common::Rect *rIn, int Left, int Centre, int Right, int Room, int Monster);
/**
* Set the oblique drawing routine
*/
- static void _DRAWSetRange(int x1, int x2, int y, int yd1, int yd2);
+ static void setRange(int x1, int x2, int y, int yd1, int yd2);
/**
* Draw wall object using current setting
*/
- static void _DRAWWall(Graphics::ManagedSurface *s, int n);
+ static void drawWall(Graphics::ManagedSurface *s, int n);
/**
* Convert coordinates from oblique to logical
*/
- static void _DRAWConvert(int *px, int *py);
+ static void drawConvert(int *px, int *py);
/**
* Draw the pits/ladder hole
diff --git a/engines/ultima/ultima0/gfx/map.cpp b/engines/ultima/ultima0/gfx/map.cpp
index d176315ac2a..14c445ea192 100644
--- a/engines/ultima/ultima0/gfx/map.cpp
+++ b/engines/ultima/ultima0/gfx/map.cpp
@@ -50,11 +50,11 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
y1 = player._worldPos.y - grid / 2 + y;
}
- DRAWTile(s, r, map.read(x1, y1));
+ drawTile(s, r, map.read(x1, y1));
// Draw us if we're there
if (x1 == player._worldPos.x && y1 == player._worldPos.y)
- DRAWTile(s, r, WT_PLAYER);
+ drawTile(s, r, WT_PLAYER);
}
}
}
@@ -65,7 +65,7 @@ void Map::draw(Graphics::ManagedSurface *s, bool showAsMap) {
#define HWLine(X1, Y1, X2, Y2) s->drawLine(X1, Y1, X2, Y2, color)
#define BOX(x1,y1,x2,y2) { HWLine(X(x1),Y(y1),X(x2),Y(y1));HWLine(X(x1),Y(y1),X(x1),Y(y2));HWLine(X(x2),Y(y2),X(x2),Y(y1));HWLine(X(x2),Y(y2),X(x1),Y(y2)); }
-void Map::DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj) {
+void Map::drawTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj) {
int x1 = r.left;
int y1 = r.top;
int w = r.width();
diff --git a/engines/ultima/ultima0/gfx/map.h b/engines/ultima/ultima0/gfx/map.h
index 3c19d06c8f5..21c2c7f9d3c 100644
--- a/engines/ultima/ultima0/gfx/map.h
+++ b/engines/ultima/ultima0/gfx/map.h
@@ -30,7 +30,7 @@ namespace Gfx {
class Map {
private:
- static void DRAWTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj);
+ static void drawTile(Graphics::ManagedSurface *s, const Common::Rect &r, int obj);
public:
static void draw(Graphics::ManagedSurface *s, bool showAsMap = false);
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index d6262ef33a1..79852a6b838 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -46,7 +46,7 @@ void Monster::draw(Graphics::ManagedSurface *s, int x, int y, int monster, doubl
_xPos = x; _yPos = y;
if (monster == MN_MIMIC)
// Fix for Mimic/Chest
- _xPos = _xPos - 90;
+ _xPos -= 90;
// Call appropriate function
assert(monster > 0 && monster <= MN_BALROG);
Commit: 4fd2c21ca7a6e6d0f37dfe89eae075010935ac77
https://github.com/scummvm/scummvm/commit/4fd2c21ca7a6e6d0f37dfe89eae075010935ac77
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Comments cleanup
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/monster_logic.cpp
engines/ultima/ultima0/gfx/dungeon.cpp
engines/ultima/ultima0/gfx/monster.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index d974b3281b4..cfbf70dc292 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -169,8 +169,8 @@ void WorldMapInfo::init(PlayerInfo &p) {
// Calculate player start
x = g_engine->getRandomNumber(1, size - 1);
y = g_engine->getRandomNumber(1, size - 1);
- p._worldPos.x = x; p._worldPos.y = y; // Save it
- _map[x][y] = WT_TOWN; // Make it a town
+ p._worldPos.x = x; p._worldPos.y = y; // Save it
+ _map[x][y] = WT_TOWN; // Make it a town
// Find place for castle
do {
@@ -178,7 +178,7 @@ void WorldMapInfo::init(PlayerInfo &p) {
y = g_engine->getRandomNumber(1, size - 1);
} while (_map[x][y] != WT_SPACE);
- _map[x][y] = WT_BRITISH; // Put LBs castle there
+ _map[x][y] = WT_BRITISH; // Put LBs castle there
}
int WorldMapInfo::read(int x, int y) const {
@@ -265,9 +265,9 @@ int DungeonMapInfo::generateContent(int c) {
return c;
}
-void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
+void DungeonMapInfo::addMonster(const PlayerInfo &player, int type) {
int x, y;
- int level = MONSTER_INFO[Type]._level;
+ int level = MONSTER_INFO[type]._level;
// Limit monsters to levels
if (level - 2 > player._level)
@@ -278,7 +278,7 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int Type) {
// Fill in details
MonsterEntry m;
- m._type = Type;
+ m._type = type;
m._strength = level + 3 + player._level;
m._alive = true;
diff --git a/engines/ultima/ultima0/data/monster_logic.cpp b/engines/ultima/ultima0/data/monster_logic.cpp
index c16d74f7a43..3343e3e5ef6 100644
--- a/engines/ultima/ultima0/data/monster_logic.cpp
+++ b/engines/ultima/ultima0/data/monster_logic.cpp
@@ -66,7 +66,7 @@ int MonsterLogic::attack(MonsterEntry &m, PlayerInfo &p) {
if (m._type == MN_GREMLIN || // Special case for Gremlin/Thief
m._type == MN_THIEF)
- if (RND() > 0.5) // Half the time
+ if (RND() > 0.5) // Half the time
return steal(m, p);
Common::String msg = Common::String::format("You are being attacked by a %s !!!.\n",
@@ -81,7 +81,7 @@ int MonsterLogic::attack(MonsterEntry &m, PlayerInfo &p) {
msg += "Missed !\n";
} else {
// Hit !
- n = urand() % m._type; // Calculate damage done.
+ n = urand() % m._type; // Calculate damage done.
n = n + p._level;
p._attr[AT_HP] -= n; // Adjust hit points
msg += "Hit !!!\n";
@@ -122,7 +122,7 @@ void MonsterLogic::move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d) {
return; // No move
x = x + xi; y = y + yi; // Work out new position
- if (!canMoveTo(d, x, y)) // Fail if can't move there
+ if (!canMoveTo(d, x, y)) // Fail if can't move there
return;
if (x == p._dungeonPos.x && // Can't move onto us
y == p._dungeonPos.y) return;
@@ -132,7 +132,8 @@ void MonsterLogic::move(MonsterEntry &m, PlayerInfo &p, DungeonMapInfo &d) {
bool MonsterLogic::canMoveTo(DungeonMapInfo &d, int x, int y) {
Common::Point c;
int t = d._map[x][y]; // See what's there
- if (!ISWALKTHRU(t)) return 0; // Can't walk through walls
+ if (!ISWALKTHRU(t))
+ return 0; // Can't walk through walls
c.x = x; c.y = y; // Set up coord structure
// True if no monster here
diff --git a/engines/ultima/ultima0/gfx/dungeon.cpp b/engines/ultima/ultima0/gfx/dungeon.cpp
index 5105fd29902..8bdb0e269a6 100644
--- a/engines/ultima/ultima0/gfx/dungeon.cpp
+++ b/engines/ultima/ultima0/gfx/dungeon.cpp
@@ -213,7 +213,7 @@ void Dungeon::drawDungeon(Graphics::ManagedSurface *s, Common::Rect *rOut,
void Dungeon::setRange(int x1, int x2, int y, int yd1, int yd2) {
_xLeft = x1; _xRight = x2; // Set x ranges
_yBottom = y; // Set lower left y value
- _yDiffLeft = yd1; _yDiffRight = yd2; // Set difference for either end
+ _yDiffLeft = yd1; _yDiffRight = yd2; // Set difference for either end
}
void Dungeon::drawWall(Graphics::ManagedSurface *s, int n) {
@@ -237,7 +237,7 @@ void Dungeon::drawConvert(int *px, int *py) {
long x, y, yd; // Longs for overflow in 16 bit
x = (_xRight - _xLeft); // Calculate width
x = x * (*px) / 100 + _xLeft; // Work out horiz value
- yd = (_yDiffRight - _yDiffLeft); // Work out height of vert for x
+ yd = (_yDiffRight - _yDiffLeft); // Work out height of vert for x
yd = yd * (*px) / 100;
y = _yBottom + // Half of the distance
yd / 2 - // + Scaled total size
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index 79852a6b838..cee7e993c41 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -34,7 +34,8 @@ int Monster::_xPos = 640;
int Monster::_yPos = 512;
constexpr int color = COL_MONSTER;
-#define END (-9999.99) /* End marker */
+// End marker
+#define END (-9999.99)
#define X(n) (x1 + w * (n)/10)
#define Y(n) (y1 + h * (n)/10)
@@ -130,7 +131,7 @@ void Monster::drawViper(Graphics::ManagedSurface *s, double x, double y, double
}
void Monster::drawCarrion(Graphics::ManagedSurface *s, double x, double y, double d) {
- /* 79-dst.recty(d) line here */
+ // 79-dst.recty(d) line here
hPlot(s, y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
hPlot(s, y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
hPlot(s, y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
Commit: b70459b351e406ae89d6743cd534117d0d8322b9
https://github.com/scummvm/scummvm/commit/b70459b351e406ae89d6743cd534117d0d8322b9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Fix monster appearance probability
Changed paths:
engines/ultima/ultima0/data/data.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index cfbf70dc292..98fbc8536c8 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -272,8 +272,9 @@ void DungeonMapInfo::addMonster(const PlayerInfo &player, int type) {
// Limit monsters to levels
if (level - 2 > player._level)
return;
+
// Not always there anyway
- if (RND() > 0.4)
+ if (RND() > 0.6)
return;
// Fill in details
Commit: a24abbebbd207e2effe2edd0ccd462b0d3a93cc0
https://github.com/scummvm/scummvm/commit/a24abbebbd207e2effe2edd0ccd462b0d3a93cc0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Fix mixed up x/y params in monster drawing code
Changed paths:
engines/ultima/ultima0/gfx/monster.cpp
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index cee7e993c41..6d661c5537e 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -73,83 +73,83 @@ void Monster::hPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
}
void Monster::drawSkeleton(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y - 23 / d, x, y - 15 / d, x, y - 15 / d, x - 15 / d, y - 8 / d, x - 30 / d, y + 8 / d, x - 30 / d, y + 15 / d, x - 15 / d, y + 15 / d, x, y + 23 / d, x, END, END);
- hPlot(s, y, x - 26 / d, y, x - 65 / d, END, END);
- hPlot(s, y - 2 / d + .5, x - 38 / d, y + 2 / d + .5, x - 38 / d, END, END);
- hPlot(s, y - 3 / d + .5, x - 45 / d, y + 3 / d + .5, x - 45 / d, END, END);
- hPlot(s, y - 5 / d + .5, x - 53 / d, y + 5 / d + .5, x - 53 / d, END, END);
- hPlot(s, y - 23 / d, x - 56 / d, y - 30 / d, x - 53 / d, y - 23 / d, x - 45 / d, y - 23 / d, x - 53 / d, y - 8 / d, x - 38 / d, END, END);
- hPlot(s, y - 15 / d, x - 45 / d, y - 8 / d, x - 60 / d, y + 8 / d, x - 60 / d, y + 15 / d, x - 45 / d, END, END);
- hPlot(s, y + 15 / d, x - 42 / d, y + 15 / d, x - 57 / d, END, END);
- hPlot(s, y + 12 / d, x - 45 / d, y + 20 / d, x - 45 / d, END, END);
- hPlot(s, y, x - 75 / d, y - 5 / d + .5, x - 80 / d, y - 8 / d, x - 75 / d, y - 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 65 / d, y + 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 68 / d, y - 5 / d + .5, x - 65 / d, END, END);
- hPlot(s, y + 5 / d + .5, x - 65 / d, y + 8 / d, x - 75 / d, y + 5 / d + .5, x - 80 / d, y - 5 / d + .5, x - 80 / d, END, END);
- hPlot(s, y - 5 / d + .5, x - 72 / d, END, END);
- hPlot(s, y + 5 / d + .5, x - 72 / d, END, END);
+ hPlot(s, x - 23 / d, y, x - 15 / d, y, x - 15 / d, y - 15 / d, x - 8 / d, y - 30 / d, x + 8 / d, y - 30 / d, x + 15 / d, y - 15 / d, x + 15 / d, y, x + 23 / d, y, END, END);
+ hPlot(s, x, y - 26 / d, x, y - 65 / d, END, END);
+ hPlot(s, x - 2 / d + .5, y - 38 / d, x + 2 / d + .5, y - 38 / d, END, END);
+ hPlot(s, x - 3 / d + .5, y - 45 / d, x + 3 / d + .5, y - 45 / d, END, END);
+ hPlot(s, x - 5 / d + .5, y - 53 / d, x + 5 / d + .5, y - 53 / d, END, END);
+ hPlot(s, x - 23 / d, y - 56 / d, x - 30 / d, y - 53 / d, x - 23 / d, y - 45 / d, x - 23 / d, y - 53 / d, x - 8 / d, y - 38 / d, END, END);
+ hPlot(s, x - 15 / d, y - 45 / d, x - 8 / d, y - 60 / d, x + 8 / d, y - 60 / d, x + 15 / d, y - 45 / d, END, END);
+ hPlot(s, x + 15 / d, y - 42 / d, x + 15 / d, y - 57 / d, END, END);
+ hPlot(s, x + 12 / d, y - 45 / d, x + 20 / d, y - 45 / d, END, END);
+ hPlot(s, x, y - 75 / d, x - 5 / d + .5, y - 80 / d, x - 8 / d, y - 75 / d, x - 5 / d + .5, y - 65 / d, x + 5 / d + .5, y - 65 / d, x + 5 / d + .5, y - 68 / d, x - 5 / d + .5, y - 68 / d, x - 5 / d + .5, y - 65 / d, END, END);
+ hPlot(s, x + 5 / d + .5, y - 65 / d, x + 8 / d, y - 75 / d, x + 5 / d + .5, y - 80 / d, x - 5 / d + .5, y - 80 / d, END, END);
+ hPlot(s, x - 5 / d + .5, y - 72 / d, END, END);
+ hPlot(s, x + 5 / d + .5, y - 72 / d, END, END);
}
void Monster::drawThief(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y, x - 56 / d, y, x - 8 / d, y + 10 / d, x, y + 30 / d, x, y + 30 / d, x - 45 / d, y + 10 / d, x - 64 / d, y, x - 56 / d, END, END);
- hPlot(s, y - 10 / d, x - 64 / d, y - 30 / d, x - 45 / d, y - 30 / d, x, y - 10 / d, x, y, x - 8 / d, END, END);
- hPlot(s, y - 10 / d, x - 64 / d, y - 10 / d, x - 75 / d, y, x - 83 / d, y + 10 / d, x - 75 / d, y, x - 79 / d, y - 10 / d, x - 75 / d, y, x - 60 / d, y + 10 / d, x - 75 / d, y + 10 / d, x - 64 / d, END, END);
+ hPlot(s, x, y - 56 / d, x, y - 8 / d, x + 10 / d, y, x + 30 / d, y, x + 30 / d, y - 45 / d, x + 10 / d, y - 64 / d, x, y - 56 / d, END, END);
+ hPlot(s, x - 10 / d, y - 64 / d, x - 30 / d, y - 45 / d, x - 30 / d, y, x - 10 / d, y, x, y - 8 / d, END, END);
+ hPlot(s, x - 10 / d, y - 64 / d, x - 10 / d, y - 75 / d, x, y - 83 / d, x + 10 / d, y - 75 / d, x, y - 79 / d, x - 10 / d, y - 75 / d, x, y - 60 / d, x + 10 / d, y - 75 / d, x + 10 / d, y - 64 / d, END, END);
}
void Monster::drawRat(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y + 5 / d, x - 30 / d, y, x - 25 / d, y - 5 / d, x - 30 / d, y - 15 / d, x - 5 / d, y - 10 / d, x, y + 10 / d, x, y + 15 / d, x - 5 / d, END, END);
- hPlot(s, y + 20 / d, x - 5 / d, y + 10 / d, x, y + 15 / d, x - 5 / d, y + 5 / d, x - 30 / d, y + 10 / d, x - 40 / d, y + 3 / d + .5, x - 35 / d, y - 3 / d + .5, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 30 / d, END, END);
- hPlot(s, y - 5 / d, x - 33 / d, y - 3 / d + .5, x - 30 / d, END, END);
- hPlot(s, y + 5 / d, x - 33 / d, y + 3 / d + .5, x - 30 / d, END, END);
- hPlot(s, y - 5 / d, x - 20 / d, y - 5 / d, x - 15 / d, END, END);
- hPlot(s, y + 5 / d, x - 20 / d, y + 5 / d, x - 15 / d, END, END);
- hPlot(s, y - 7 / d, x - 20 / d, y - 7 / d, x - 15 / d, END, END);
- hPlot(s, y + 7 / d, x - 20 / d, y + 7 / d, x - 15 / d, END, END);
+ hPlot(s, x + 5 / d, y - 30 / d, x, y - 25 / d, x - 5 / d, y - 30 / d, x - 15 / d, y - 5 / d, x - 10 / d, y, x + 10 / d, y, x + 15 / d, y - 5 / d, END, END);
+ hPlot(s, x + 20 / d, y - 5 / d, x + 10 / d, y, x + 15 / d, y - 5 / d, x + 5 / d, y - 30 / d, x + 10 / d, y - 40 / d, x + 3 / d + .5, y - 35 / d, x - 3 / d + .5, y - 35 / d, x - 10 / d, y - 40 / d, x - 5 / d, y - 30 / d, END, END);
+ hPlot(s, x - 5 / d, y - 33 / d, x - 3 / d + .5, y - 30 / d, END, END);
+ hPlot(s, x + 5 / d, y - 33 / d, x + 3 / d + .5, y - 30 / d, END, END);
+ hPlot(s, x - 5 / d, y - 20 / d, x - 5 / d, y - 15 / d, END, END);
+ hPlot(s, x + 5 / d, y - 20 / d, x + 5 / d, y - 15 / d, END, END);
+ hPlot(s, x - 7 / d, y - 20 / d, x - 7 / d, y - 15 / d, END, END);
+ hPlot(s, x + 7 / d, y - 20 / d, x + 7 / d, y - 15 / d, END, END);
}
void Monster::drawOrc(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y, x, y - 15 / d, x, y - 8 / d, x - 8 / d, y - 8 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 23 / d, END, END);
- hPlot(s, y - 23 / d, x - 45 / d, y - 15 / d, x - 53 / d, y - 8 / d, x - 53 / d, y - 15 / d, x - 68 / d, y - 8 / d, x - 75 / d, y, x - 75 / d, END, END);
- hPlot(s, y, x, y + 15 / d, x, y + 8 / d, x - 8 / d, y + 8 / d, x - 15 / d, y + 15 / d, x - 23 / d, y + 15 / d, x - 15 / d, y + 23 / d, x - 23 / d, END, END);
- hPlot(s, y + 23 / d, x - 45 / d, y + 15 / d, x - 53 / d, y + 8 / d, x - 53 / d, y + 15 / d, x - 68 / d, y + 8 / d, x - 75 / d, y, x - 75 / d, END, END);
- hPlot(s, y - 15 / d, x - 68 / d, y + 15 / d, x - 68 / d, END, END);
- hPlot(s, y - 8 / d, x - 53 / d, y + 8 / d, x - 53 / d, END, END);
- hPlot(s, y - 23 / d, x - 15 / d, y + 8 / d, x - 45 / d, END, END);
- hPlot(s, y - 8 / d, x - 68 / d, y, x - 60 / d, y + 8 / d, x - 68 / d, y + 8 / d, x - 60 / d, y - 8 / d, x - 60 / d, y - 8 / d, x - 68 / d, END, END);
- hPlot(s, y, x - 38 / d, y - 8 / d, x - 38 / d, y + 8 / d, x - 53 / d, y + 8 / d, x - 45 / d, y + 15 / d, x - 45 / d, y, x - 30 / d, y, x - 38 / d, END, END);
+ hPlot(s, x, y, x - 15 / d, y, x - 8 / d, y - 8 / d, x - 8 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 23 / d, END, END);
+ hPlot(s, x - 23 / d, y - 45 / d, x - 15 / d, y - 53 / d, x - 8 / d, y - 53 / d, x - 15 / d, y - 68 / d, x - 8 / d, y - 75 / d, x, y - 75 / d, END, END);
+ hPlot(s, x, y, x + 15 / d, y, x + 8 / d, y - 8 / d, x + 8 / d, y - 15 / d, x + 15 / d, y - 23 / d, x + 15 / d, y - 15 / d, x + 23 / d, y - 23 / d, END, END);
+ hPlot(s, x + 23 / d, y - 45 / d, x + 15 / d, y - 53 / d, x + 8 / d, y - 53 / d, x + 15 / d, y - 68 / d, x + 8 / d, y - 75 / d, x, y - 75 / d, END, END);
+ hPlot(s, x - 15 / d, y - 68 / d, x + 15 / d, y - 68 / d, END, END);
+ hPlot(s, x - 8 / d, y - 53 / d, x + 8 / d, y - 53 / d, END, END);
+ hPlot(s, x - 23 / d, y - 15 / d, x + 8 / d, y - 45 / d, END, END);
+ hPlot(s, x - 8 / d, y - 68 / d, x, y - 60 / d, x + 8 / d, y - 68 / d, x + 8 / d, y - 60 / d, x - 8 / d, y - 60 / d, x - 8 / d, y - 68 / d, END, END);
+ hPlot(s, x, y - 38 / d, x - 8 / d, y - 38 / d, x + 8 / d, y - 53 / d, x + 8 / d, y - 45 / d, x + 15 / d, y - 45 / d, x, y - 30 / d, x, y - 38 / d, END, END);
}
void Monster::drawViper(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y - 10 / d, x - 15 / d, y - 10 / d, x - 30 / d, y - 15 / d, x - 20 / d, y - 15 / d, x - 15 / d, y - 15 / d, x, y + 15 / d, x, y + 15 / d, x - 15 / d, y - 15 / d, x - 15 / d, END, END);
- hPlot(s, y - 15 / d, x - 10 / d, y + 15 / d, x - 10 / d, END, END);
- hPlot(s, y - 15 / d, x - 5 / d, y + 15 / d, x - 5 / d, END, END);
- hPlot(s, y, x - 15 / d, y - 5 / d, x - 20 / d, y - 5 / d, x - 35 / d, y + 5 / d, x - 35 / d, y + 5 / d, x - 20 / d, y + 10 / d, x - 15 / d, END, END);
- hPlot(s, y - 5 / d, x - 20 / d, y + 5 / d, x - 20 / d, END, END);
- hPlot(s, y - 5 / d, x - 25 / d, y + 5 / d, x - 25 / d, END, END);
- hPlot(s, y - 5 / d, x - 30 / d, y + 5 / d, x - 30 / d, END, END);
- hPlot(s, y - 10 / d, x - 35 / d, y - 10 / d, x - 40 / d, y - 5 / d, x - 45 / d, y + 5 / d, x - 45 / d, y + 10 / d, x - 40 / d, y + 10 / d, x - 35 / d, END, END);
- hPlot(s, y - 10 / d, x - 40 / d, y, x - 45 / d, y + 10 / d, x - 40 / d, END, END);
- hPlot(s, y - 5 / d, x - 40 / d, y + 5 / d, x - 40 / d, y + 15 / d, x - 30 / d, y, x - 40 / d, y - 15 / d, x - 30 / d, y - 5 / d + .5, x - 40 / d, END, END);
+ hPlot(s, x - 10 / d, y - 15 / d, x - 10 / d, y - 30 / d, x - 15 / d, y - 20 / d, x - 15 / d, y - 15 / d, x - 15 / d, y, x + 15 / d, y, x + 15 / d, y - 15 / d, x - 15 / d, y - 15 / d, END, END);
+ hPlot(s, x - 15 / d, y - 10 / d, x + 15 / d, y - 10 / d, END, END);
+ hPlot(s, x - 15 / d, y - 5 / d, x + 15 / d, y - 5 / d, END, END);
+ hPlot(s, x, y - 15 / d, x - 5 / d, y - 20 / d, x - 5 / d, y - 35 / d, x + 5 / d, y - 35 / d, x + 5 / d, y - 20 / d, x + 10 / d, y - 15 / d, END, END);
+ hPlot(s, x - 5 / d, y - 20 / d, x + 5 / d, y - 20 / d, END, END);
+ hPlot(s, x - 5 / d, y - 25 / d, x + 5 / d, y - 25 / d, END, END);
+ hPlot(s, x - 5 / d, y - 30 / d, x + 5 / d, y - 30 / d, END, END);
+ hPlot(s, x - 10 / d, y - 35 / d, x - 10 / d, y - 40 / d, x - 5 / d, y - 45 / d, x + 5 / d, y - 45 / d, x + 10 / d, y - 40 / d, x + 10 / d, y - 35 / d, END, END);
+ hPlot(s, x - 10 / d, y - 40 / d, x, y - 45 / d, x + 10 / d, y - 40 / d, END, END);
+ hPlot(s, x - 5 / d, y - 40 / d, x + 5 / d, y - 40 / d, x + 15 / d, y - 30 / d, x, y - 40 / d, x - 15 / d, y - 30 / d, x - 5 / d + .5, y - 40 / d, END, END);
}
void Monster::drawCarrion(Graphics::ManagedSurface *s, double x, double y, double d) {
// 79-dst.recty(d) line here
- hPlot(s, y - 20 / d, x - 79 / d, y - 20 / d, x - 88 / d, y - 10 / d, x - 83 / d, y + 10 / d, x - 83 / d, y + 20 / d, x - 88 / d, y + 20 / d, x - 79 / d, y - 20 / d, x - 79 / d, END, END);
- hPlot(s, y - 20 / d, x - 88 / d, y - 30 / d, x - 83 / d, y - 30 / d, x - 78 / d, END, END);
- hPlot(s, y + 20 / d, x - 88 / d, y + 30 / d, x - 83 / d, y + 40 / d, x - 83 / d, END, END);
- hPlot(s, y - 15 / d, x - 86 / d, y - 20 / d, x - 83 / d, y - 20 / d, x - 78 / d, y - 30 / d, x - 73 / d, y - 30 / d, x - 68 / d, y - 20 / d, x - 63 / d, END, END);
- hPlot(s, y - 10 / d, x - 83 / d, y - 10 / d, x - 58 / d, y, x - 50 / d, END, END);
- hPlot(s, y + 10 / d, x - 83 / d, y + 10 / d, x - 78 / d, y + 20 / d, x - 73 / d, y + 20 / d, x - 40 / d, END, END);
- hPlot(s, y + 15 / d, x - 85 / d, y + 20 / d, x - 78 / d, y + 30 / d, x - 76 / d, y + 30 / d, x - 60 / d, END, END);
- hPlot(s, y, x - 83 / d, y, x - 73 / d, y + 10 / d, x - 68 / d, y + 10 / d, x - 63 / d, y, x - 58 / d, END, END);
+ hPlot(s, x - 20 / d, y - 79 / d, x - 20 / d, y - 88 / d, x - 10 / d, y - 83 / d, x + 10 / d, y - 83 / d, x + 20 / d, y - 88 / d, x + 20 / d, y - 79 / d, x - 20 / d, y - 79 / d, END, END);
+ hPlot(s, x - 20 / d, y - 88 / d, x - 30 / d, y - 83 / d, x - 30 / d, y - 78 / d, END, END);
+ hPlot(s, x + 20 / d, y - 88 / d, x + 30 / d, y - 83 / d, x + 40 / d, y - 83 / d, END, END);
+ hPlot(s, x - 15 / d, y - 86 / d, x - 20 / d, y - 83 / d, x - 20 / d, y - 78 / d, x - 30 / d, y - 73 / d, x - 30 / d, y - 68 / d, x - 20 / d, y - 63 / d, END, END);
+ hPlot(s, x - 10 / d, y - 83 / d, x - 10 / d, y - 58 / d, x, y - 50 / d, END, END);
+ hPlot(s, x + 10 / d, y - 83 / d, x + 10 / d, y - 78 / d, x + 20 / d, y - 73 / d, x + 20 / d, y - 40 / d, END, END);
+ hPlot(s, x + 15 / d, y - 85 / d, x + 20 / d, y - 78 / d, x + 30 / d, y - 76 / d, x + 30 / d, y - 60 / d, END, END);
+ hPlot(s, x, y - 83 / d, x, y - 73 / d, x + 10 / d, y - 68 / d, x + 10 / d, y - 63 / d, x, y - 58 / d, END, END);
}
void Monster::drawGremlin(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y + 5 / d + .5, x - 10 / d, y - 5 / d + .5, x - 10 / d, y, x - 15 / d, y + 10 / d, x - 20 / d, y + 5 / d + .5, x - 15 / d, y + 5 / d + .5, x - 10 / d, END, END);
- hPlot(s, y + 7 / d + .5, x - 6 / d, y + 5 / d + .5, x - 3 / d, y - 5 / d + .5, x - 3 / d, y - 7 / d + .5, x - 6 / d, y - 5 / d + .5, x - 10 / d, END, END);
- hPlot(s, y + 2 / d + .5, x - 3 / d, y + 5 / d + .5, x, y + 8 / d, x, END, END);
- hPlot(s, y - 2 / d + .5, x - 3 / d, y - 5 / d + .5, x, y - 8 / d, x, END, END);
- hPlot(s, y + 3 / d + .5, x - 8 / d, END, END);
- hPlot(s, y - 3 / d + .5, x - 8 / d, END, END);
- hPlot(s, y + 3 / d + .5, x - 5 / d, y - 3 / d + .5, x - 5 / d, END, END);
+ hPlot(s, x + 5 / d + .5, y - 10 / d, x - 5 / d + .5, y - 10 / d, x, y - 15 / d, x + 10 / d, y - 20 / d, x + 5 / d + .5, y - 15 / d, x + 5 / d + .5, y - 10 / d, END, END);
+ hPlot(s, x + 7 / d + .5, y - 6 / d, x + 5 / d + .5, y - 3 / d, x - 5 / d + .5, y - 3 / d, x - 7 / d + .5, y - 6 / d, x - 5 / d + .5, y - 10 / d, END, END);
+ hPlot(s, x + 2 / d + .5, y - 3 / d, x + 5 / d + .5, y, x + 8 / d, y, END, END);
+ hPlot(s, x - 2 / d + .5, y - 3 / d, x - 5 / d + .5, y, x - 8 / d, y, END, END);
+ hPlot(s, x + 3 / d + .5, y - 8 / d, END, END);
+ hPlot(s, x - 3 / d + .5, y - 8 / d, END, END);
+ hPlot(s, x + 3 / d + .5, y - 5 / d, x - 3 / d + .5, y - 5 / d, END, END);
}
void Monster::drawMimic(Graphics::ManagedSurface *s, double x, double y, double d) {
@@ -160,37 +160,37 @@ void Monster::drawMimic(Graphics::ManagedSurface *s, double x, double y, double
}
void Monster::drawDaemon(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y - 14 / d, x - 46 / d, y - 12 / d, x - 37 / d, y - 20 / d, x - 32 / d, y - 30 / d, x - 32 / d, y - 22 / d, x - 24 / d, y - 40 / d, x - 17 / d, y - 40 / d, x - 7 / d, y - 38 / d, x - 5 / d, y - 40 / d, x - 3 / d, y - 40 / d, x, END, END);
- hPlot(s, y - 36 / d, x, y - 34 / d, x - 2 / d, y - 32 / d, x, y - 28 / d, x, y - 28 / d, x - 3 / d, y - 30 / d, x - 5 / d, y - 28 / d, x - 7 / d, y - 28 / d, x - 15 / d, y, x - 27 / d, END, END);
- hPlot(s, y + 14 / d, x - 46 / d, y + 12 / d, x - 37 / d, y + 20 / d, x - 32 / d, y + 30 / d, x - 32 / d, y + 22 / d, x - 24 / d, y + 40 / d, x - 17 / d, y + 40 / d, x - 7 / d, y + 38 / d, x - 5 / d, y + 40 / d, x - 3 / d, y + 40 / d, x, END, END);
- hPlot(s, y + 36 / d, x, y + 34 / d, x - 2 / d, y + 32 / d, x, y + 28 / d, x, y + 28 / d, x - 3 / d, y + 30 / d, x - 5 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 15 / d, y, x - 27 / d, END, END);
- hPlot(s, y + 6 / d, x - 48 / d, y + 38 / d, x - 41 / d, y + 40 / d, x - 42 / d, y + 18 / d, x - 56 / d, y + 12 / d, x - 56 / d, y + 10 / d, x - 57 / d, y + 8 / d, x - 56 / d, y - 8 / d, x - 56 / d, y - 10 / d, x - 58 / d, y + 14 / d, x - 58 / d, y + 16 / d, x - 59 / d, END, END);
- hPlot(s, y + 8 / d, x - 63 / d, y + 6 / d, x - 63 / d, y + 2 / d + .5, x - 70 / d, y + 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 63 / d, y - 2 / d + .5, x - 70 / d, y - 6 / d, x - 63 / d, y - 8 / d, x - 63 / d, y - 16 / d, x - 59 / d, y - 14 / d, x - 58 / d, END, END);
- hPlot(s, y - 10 / d, x - 57 / d, y - 12 / d, x - 56 / d, y - 18 / d, x - 56 / d, y - 36 / d, x - 47 / d, y - 36 / d, x - 39 / d, y - 28 / d, x - 41 / d, y - 28 / d, x - 46 / d, y - 20 / d, x - 50 / d, y - 18 / d, x - 50 / d, y - 14 / d, x - 46 / d, END, END);
- hPlot(s, y - 28 / d, x - 41 / d, y + 30 / d, x - 55 / d, END, END);
- hPlot(s, y + 28 / d, x - 58 / d, y + 22 / d, x - 56 / d, y + 22 / d, x - 53 / d, y + 28 / d, x - 52 / d, y + 34 / d, x - 54 / d, END, END);
- hPlot(s, y + 20 / d, x - 50 / d, y + 26 / d, x - 47 / d, END, END);
- hPlot(s, y + 10 / d, x - 58 / d, y + 10 / d, x - 61 / d, y + 4 / d, x - 58 / d, END, END);
- hPlot(s, y - 10 / d, x - 58 / d, y - 10 / d, x - 61 / d, y - 4 / d, x - 58 / d, END, END);
- hPlot(s, y + 40 / d, x - 9 / d, y + 50 / d, x - 12 / d, y + 40 / d, x - 7 / d, END, END);
- hPlot(s, y - 8 / d, x - 25 / d, y + 6 / d, x - 7 / d, y + 28 / d, x - 7 / d, y + 28 / d, x - 9 / d, y + 20 / d, x - 9 / d, y + 6 / d, x - 25 / d, END, END);
+ hPlot(s, x - 14 / d, y - 46 / d, x - 12 / d, y - 37 / d, x - 20 / d, y - 32 / d, x - 30 / d, y - 32 / d, x - 22 / d, y - 24 / d, x - 40 / d, y - 17 / d, x - 40 / d, y - 7 / d, x - 38 / d, y - 5 / d, x - 40 / d, y - 3 / d, x - 40 / d, y, END, END);
+ hPlot(s, x - 36 / d, y, x - 34 / d, y - 2 / d, x - 32 / d, y, x - 28 / d, y, x - 28 / d, y - 3 / d, x - 30 / d, y - 5 / d, x - 28 / d, y - 7 / d, x - 28 / d, y - 15 / d, x, y - 27 / d, END, END);
+ hPlot(s, x + 14 / d, y - 46 / d, x + 12 / d, y - 37 / d, x + 20 / d, y - 32 / d, x + 30 / d, y - 32 / d, x + 22 / d, y - 24 / d, x + 40 / d, y - 17 / d, x + 40 / d, y - 7 / d, x + 38 / d, y - 5 / d, x + 40 / d, y - 3 / d, x + 40 / d, y, END, END);
+ hPlot(s, x + 36 / d, y, x + 34 / d, y - 2 / d, x + 32 / d, y, x + 28 / d, y, x + 28 / d, y - 3 / d, x + 30 / d, y - 5 / d, x + 28 / d, y - 7 / d, x + 28 / d, y - 15 / d, x, y - 27 / d, END, END);
+ hPlot(s, x + 6 / d, y - 48 / d, x + 38 / d, y - 41 / d, x + 40 / d, y - 42 / d, x + 18 / d, y - 56 / d, x + 12 / d, y - 56 / d, x + 10 / d, y - 57 / d, x + 8 / d, y - 56 / d, x - 8 / d, y - 56 / d, x - 10 / d, y - 58 / d, x + 14 / d, y - 58 / d, x + 16 / d, y - 59 / d, END, END);
+ hPlot(s, x + 8 / d, y - 63 / d, x + 6 / d, y - 63 / d, x + 2 / d + .5, y - 70 / d, x + 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 70 / d, x - 6 / d, y - 63 / d, x - 8 / d, y - 63 / d, x - 16 / d, y - 59 / d, x - 14 / d, y - 58 / d, END, END);
+ hPlot(s, x - 10 / d, y - 57 / d, x - 12 / d, y - 56 / d, x - 18 / d, y - 56 / d, x - 36 / d, y - 47 / d, x - 36 / d, y - 39 / d, x - 28 / d, y - 41 / d, x - 28 / d, y - 46 / d, x - 20 / d, y - 50 / d, x - 18 / d, y - 50 / d, x - 14 / d, y - 46 / d, END, END);
+ hPlot(s, x - 28 / d, y - 41 / d, x + 30 / d, y - 55 / d, END, END);
+ hPlot(s, x + 28 / d, y - 58 / d, x + 22 / d, y - 56 / d, x + 22 / d, y - 53 / d, x + 28 / d, y - 52 / d, x + 34 / d, y - 54 / d, END, END);
+ hPlot(s, x + 20 / d, y - 50 / d, x + 26 / d, y - 47 / d, END, END);
+ hPlot(s, x + 10 / d, y - 58 / d, x + 10 / d, y - 61 / d, x + 4 / d, y - 58 / d, END, END);
+ hPlot(s, x - 10 / d, y - 58 / d, x - 10 / d, y - 61 / d, x - 4 / d, y - 58 / d, END, END);
+ hPlot(s, x + 40 / d, y - 9 / d, x + 50 / d, y - 12 / d, x + 40 / d, y - 7 / d, END, END);
+ hPlot(s, x - 8 / d, y - 25 / d, x + 6 / d, y - 7 / d, x + 28 / d, y - 7 / d, x + 28 / d, y - 9 / d, x + 20 / d, y - 9 / d, x + 6 / d, y - 25 / d, END, END);
}
void Monster::drawBalrog(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, y + 6 / d, x - 60 / d, y + 30 / d, x - 90 / d, y + 60 / d, x - 30 / d, y + 60 / d, x - 10 / d, y + 30 / d, x - 40 / d, y + 15 / d, x - 40 / d, END, END);
- hPlot(s, y - 6 / d, x - 60 / d, y - 30 / d, x - 90 / d, y - 60 / d, x - 30 / d, y - 60 / d, x - 10 / d, y - 30 / d, x - 40 / d, y - 15 / d, x - 40 / d, END, END);
- hPlot(s, y, x - 25 / d, y + 6 / d, x - 25 / d, y + 10 / d, x - 20 / d, y + 12 / d, x - 10 / d, y + 10 / d, x - 6 / d, y + 10 / d, x, y + 14 / d, x, y + 15 / d, x - 5 / d, y + 16 / d, x, y + 20 / d, x, END, END);
- hPlot(s, y + 20 / d, x - 6 / d, y + 18 / d, x - 10 / d, y + 18 / d, x - 20 / d, y + 15 / d, x - 30 / d, y + 15 / d, x - 45 / d, y + 40 / d, x - 60 / d, y + 40 / d, x - 70 / d, END, END);
- hPlot(s, y + 10 / d, x - 55 / d, y + 6 / d, x - 60 / d, y + 10 / d, x - 74 / d, y + 6 / d, x - 80 / d, y + 4 / d + .5, x - 80 / d, y + 3 / d + .5, x - 82 / d, y + 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
- hPlot(s, y, x - 25 / d, y - 6 / d, x - 25 / d, y - 10 / d, x - 20 / d, y - 12 / d, x - 10 / d, y - 10 / d, x - 6 / d, y - 10 / d, x, y - 14 / d, x, y - 15 / d, x - 5 / d, y - 16 / d, x, y - 20 / d, x, END, END);
- hPlot(s, y - 20 / d, x - 6 / d, y - 18 / d, x - 10 / d, y - 18 / d, x - 20 / d, y - 15 / d, x - 30 / d, y - 15 / d, x - 45 / d, y - 40 / d, x - 60 / d, y - 40 / d, x - 70 / d, END, END);
- hPlot(s, y - 10 / d, x - 55 / d, y - 6 / d, x - 60 / d, y - 10 / d, x - 74 / d, y - 6 / d, x - 80 / d, y - 4 / d + .5, x - 80 / d, y - 3 / d + .5, x - 82 / d, y - 2 / d + .5, x - 80 / d, y, x - 80 / d, END, END);
- hPlot(s, y - 6 / d, x - 25 / d, y, x - 6 / d, y + 10 / d, x, y + 4 / d + .5, x - 8 / d, y + 6 / d, x - 25 / d, END, END);
- hPlot(s, y - 40 / d, x - 64 / d, y - 40 / d, x - 90 / d, y - 52 / d, x - 80 / d, y - 52 / d, x - 40 / d, END, END);
- hPlot(s, y + 40 / d, x - 86 / d, y + 38 / d, x - 92 / d, y + 42 / d, x - 92 / d, y + 40 / d, x - 86 / d, y + 40 / d, x - 50 / d, END, END);
- hPlot(s, y + 4 / d + .5, x - 70 / d, y + 6 / d, x - 74 / d, END, END);
- hPlot(s, y - 4 / d + .5, x - 70 / d, y - 6 / d, x - 74 / d, END, END);
- hPlot(s, y, x - 64 / d, y, x - 60 / d, END, END);
+ hPlot(s, x + 6 / d, y - 60 / d, x + 30 / d, y - 90 / d, x + 60 / d, y - 30 / d, x + 60 / d, y - 10 / d, x + 30 / d, y - 40 / d, x + 15 / d, y - 40 / d, END, END);
+ hPlot(s, x - 6 / d, y - 60 / d, x - 30 / d, y - 90 / d, x - 60 / d, y - 30 / d, x - 60 / d, y - 10 / d, x - 30 / d, y - 40 / d, x - 15 / d, y - 40 / d, END, END);
+ hPlot(s, x, y - 25 / d, x + 6 / d, y - 25 / d, x + 10 / d, y - 20 / d, x + 12 / d, y - 10 / d, x + 10 / d, y - 6 / d, x + 10 / d, y, x + 14 / d, y, x + 15 / d, y - 5 / d, x + 16 / d, y, x + 20 / d, y, END, END);
+ hPlot(s, x + 20 / d, y - 6 / d, x + 18 / d, y - 10 / d, x + 18 / d, y - 20 / d, x + 15 / d, y - 30 / d, x + 15 / d, y - 45 / d, x + 40 / d, y - 60 / d, x + 40 / d, y - 70 / d, END, END);
+ hPlot(s, x + 10 / d, y - 55 / d, x + 6 / d, y - 60 / d, x + 10 / d, y - 74 / d, x + 6 / d, y - 80 / d, x + 4 / d + .5, y - 80 / d, x + 3 / d + .5, y - 82 / d, x + 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
+ hPlot(s, x, y - 25 / d, x - 6 / d, y - 25 / d, x - 10 / d, y - 20 / d, x - 12 / d, y - 10 / d, x - 10 / d, y - 6 / d, x - 10 / d, y, x - 14 / d, y, x - 15 / d, y - 5 / d, x - 16 / d, y, x - 20 / d, y, END, END);
+ hPlot(s, x - 20 / d, y - 6 / d, x - 18 / d, y - 10 / d, x - 18 / d, y - 20 / d, x - 15 / d, y - 30 / d, x - 15 / d, y - 45 / d, x - 40 / d, y - 60 / d, x - 40 / d, y - 70 / d, END, END);
+ hPlot(s, x - 10 / d, y - 55 / d, x - 6 / d, y - 60 / d, x - 10 / d, y - 74 / d, x - 6 / d, y - 80 / d, x - 4 / d + .5, y - 80 / d, x - 3 / d + .5, y - 82 / d, x - 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
+ hPlot(s, x - 6 / d, y - 25 / d, x, y - 6 / d, x + 10 / d, y, x + 4 / d + .5, y - 8 / d, x + 6 / d, y - 25 / d, END, END);
+ hPlot(s, x - 40 / d, y - 64 / d, x - 40 / d, y - 90 / d, x - 52 / d, y - 80 / d, x - 52 / d, y - 40 / d, END, END);
+ hPlot(s, x + 40 / d, y - 86 / d, x + 38 / d, y - 92 / d, x + 42 / d, y - 92 / d, x + 40 / d, y - 86 / d, x + 40 / d, y - 50 / d, END, END);
+ hPlot(s, x + 4 / d + .5, y - 70 / d, x + 6 / d, y - 74 / d, END, END);
+ hPlot(s, x - 4 / d + .5, y - 70 / d, x - 6 / d, y - 74 / d, END, END);
+ hPlot(s, x, y - 64 / d, x, y - 60 / d, END, END);
}
} // namespace Views
Commit: c6ffbce7bbc76af92d423e7768dcc2619d131b2e
https://github.com/scummvm/scummvm/commit/c6ffbce7bbc76af92d423e7768dcc2619d131b2e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Monster rendering fixes
Changed paths:
engines/ultima/ultima0/gfx/monster.cpp
diff --git a/engines/ultima/ultima0/gfx/monster.cpp b/engines/ultima/ultima0/gfx/monster.cpp
index 6d661c5537e..e810a928262 100644
--- a/engines/ultima/ultima0/gfx/monster.cpp
+++ b/engines/ultima/ultima0/gfx/monster.cpp
@@ -60,12 +60,19 @@ void Monster::hPlot(Graphics::ManagedSurface *s, double x, double y, ...) {
// Start reading values
va_start(alist, y);
+ bool isPixel = true;
do {
x1 = va_arg(alist, double); // Get the next two
y1 = va_arg(alist, double);
- if (x1 != END && y1 != END) // If legit, draw the line
+ if (x1 != END && y1 != END) {
+ // If legit, draw the line
HWLine(_xPos + x, _yPos + y, _xPos + x1, _yPos + y1);
+ isPixel = false;
+ } else if (isPixel)
+ // Single pixel only
+ HWLine(_xPos + x, _yPos + y, _xPos + x, _yPos + y);
+
x = x1; y = y1;
} while (x1 != END && y1 != END);
@@ -107,9 +114,9 @@ void Monster::drawRat(Graphics::ManagedSurface *s, double x, double y, double d)
void Monster::drawOrc(Graphics::ManagedSurface *s, double x, double y, double d) {
hPlot(s, x, y, x - 15 / d, y, x - 8 / d, y - 8 / d, x - 8 / d, y - 15 / d, x - 15 / d, y - 23 / d, x - 15 / d, y - 15 / d, x - 23 / d, y - 23 / d, END, END);
- hPlot(s, x - 23 / d, y - 45 / d, x - 15 / d, y - 53 / d, x - 8 / d, y - 53 / d, x - 15 / d, y - 68 / d, x - 8 / d, y - 75 / d, x, y - 75 / d, END, END);
+ hPlot(s, x - 23 / d, y - 23 / d, x - 15 / d, y - 53 / d, x - 8 / d, y - 53 / d, x - 15 / d, y - 68 / d, x - 8 / d, y - 75 / d, x, y - 75 / d, END, END);
hPlot(s, x, y, x + 15 / d, y, x + 8 / d, y - 8 / d, x + 8 / d, y - 15 / d, x + 15 / d, y - 23 / d, x + 15 / d, y - 15 / d, x + 23 / d, y - 23 / d, END, END);
- hPlot(s, x + 23 / d, y - 45 / d, x + 15 / d, y - 53 / d, x + 8 / d, y - 53 / d, x + 15 / d, y - 68 / d, x + 8 / d, y - 75 / d, x, y - 75 / d, END, END);
+ hPlot(s, x + 23 / d, y - 23 / d, x + 15 / d, y - 53 / d, x + 8 / d, y - 53 / d, x + 15 / d, y - 68 / d, x + 8 / d, y - 75 / d, x, y - 75 / d, END, END);
hPlot(s, x - 15 / d, y - 68 / d, x + 15 / d, y - 68 / d, END, END);
hPlot(s, x - 8 / d, y - 53 / d, x + 8 / d, y - 53 / d, END, END);
hPlot(s, x - 23 / d, y - 15 / d, x + 8 / d, y - 45 / d, END, END);
@@ -143,13 +150,13 @@ void Monster::drawCarrion(Graphics::ManagedSurface *s, double x, double y, doubl
}
void Monster::drawGremlin(Graphics::ManagedSurface *s, double x, double y, double d) {
- hPlot(s, x + 5 / d + .5, y - 10 / d, x - 5 / d + .5, y - 10 / d, x, y - 15 / d, x + 10 / d, y - 20 / d, x + 5 / d + .5, y - 15 / d, x + 5 / d + .5, y - 10 / d, END, END);
- hPlot(s, x + 7 / d + .5, y - 6 / d, x + 5 / d + .5, y - 3 / d, x - 5 / d + .5, y - 3 / d, x - 7 / d + .5, y - 6 / d, x - 5 / d + .5, y - 10 / d, END, END);
- hPlot(s, x + 2 / d + .5, y - 3 / d, x + 5 / d + .5, y, x + 8 / d, y, END, END);
- hPlot(s, x - 2 / d + .5, y - 3 / d, x - 5 / d + .5, y, x - 8 / d, y, END, END);
- hPlot(s, x + 3 / d + .5, y - 8 / d, END, END);
- hPlot(s, x - 3 / d + .5, y - 8 / d, END, END);
- hPlot(s, x + 3 / d + .5, y - 5 / d, x - 3 / d + .5, y - 5 / d, END, END);
+ hPlot(s, x + 5 / d + 1, y - 10 / d, x - 5 / d + 1, y - 10 / d, x, y - 15 / d, x + 10 / d, y - 20 / d, x + 5 / d + 1, y - 15 / d, x + 5 / d + 1, y - 10 / d, END, END);
+ hPlot(s, x + 5 / d + 1, y - 10 / d, x + 7 / d + 1, y - 6 / d, x + 5 / d + 1, y - 3 / d, x - 5 / d + 1, y - 3 / d, x - 7 / d + 1, y - 6 / d, x - 5 / d + 1, y - 10 / d, END, END);
+ hPlot(s, x + 2 / d + 1, y - 3 / d, x + 5 / d + 1, y, x + 8 / d, y, END, END);
+ hPlot(s, x - 2 / d + 1, y - 3 / d, x - 5 / d + 1, y, x - 8 / d, y, END, END);
+ hPlot(s, x + 3 / d + 1, y - 8 / d, END, END);
+ hPlot(s, x - 3 / d + 1, y - 8 / d, END, END);
+ hPlot(s, x + 3 / d + 1, y - 5 / d, x - 3 / d + 1, y - 5 / d, END, END);
}
void Monster::drawMimic(Graphics::ManagedSurface *s, double x, double y, double d) {
@@ -161,11 +168,11 @@ void Monster::drawMimic(Graphics::ManagedSurface *s, double x, double y, double
void Monster::drawDaemon(Graphics::ManagedSurface *s, double x, double y, double d) {
hPlot(s, x - 14 / d, y - 46 / d, x - 12 / d, y - 37 / d, x - 20 / d, y - 32 / d, x - 30 / d, y - 32 / d, x - 22 / d, y - 24 / d, x - 40 / d, y - 17 / d, x - 40 / d, y - 7 / d, x - 38 / d, y - 5 / d, x - 40 / d, y - 3 / d, x - 40 / d, y, END, END);
- hPlot(s, x - 36 / d, y, x - 34 / d, y - 2 / d, x - 32 / d, y, x - 28 / d, y, x - 28 / d, y - 3 / d, x - 30 / d, y - 5 / d, x - 28 / d, y - 7 / d, x - 28 / d, y - 15 / d, x, y - 27 / d, END, END);
+ hPlot(s, x - 40 / d, y, x - 36 / d, y, x - 34 / d, y - 2 / d, x - 32 / d, y, x - 28 / d, y, x - 28 / d, y - 3 / d, x - 30 / d, y - 5 / d, x - 28 / d, y - 7 / d, x - 28 / d, y - 15 / d, x, y - 27 / d, END, END);
hPlot(s, x + 14 / d, y - 46 / d, x + 12 / d, y - 37 / d, x + 20 / d, y - 32 / d, x + 30 / d, y - 32 / d, x + 22 / d, y - 24 / d, x + 40 / d, y - 17 / d, x + 40 / d, y - 7 / d, x + 38 / d, y - 5 / d, x + 40 / d, y - 3 / d, x + 40 / d, y, END, END);
- hPlot(s, x + 36 / d, y, x + 34 / d, y - 2 / d, x + 32 / d, y, x + 28 / d, y, x + 28 / d, y - 3 / d, x + 30 / d, y - 5 / d, x + 28 / d, y - 7 / d, x + 28 / d, y - 15 / d, x, y - 27 / d, END, END);
+ hPlot(s, x + 40 / d, y, x + 36 / d, y, x + 34 / d, y - 2 / d, x + 32 / d, y, x + 28 / d, y, x + 28 / d, y - 3 / d, x + 30 / d, y - 5 / d, x + 28 / d, y - 7 / d, x + 28 / d, y - 15 / d, x, y - 27 / d, END, END);
hPlot(s, x + 6 / d, y - 48 / d, x + 38 / d, y - 41 / d, x + 40 / d, y - 42 / d, x + 18 / d, y - 56 / d, x + 12 / d, y - 56 / d, x + 10 / d, y - 57 / d, x + 8 / d, y - 56 / d, x - 8 / d, y - 56 / d, x - 10 / d, y - 58 / d, x + 14 / d, y - 58 / d, x + 16 / d, y - 59 / d, END, END);
- hPlot(s, x + 8 / d, y - 63 / d, x + 6 / d, y - 63 / d, x + 2 / d + .5, y - 70 / d, x + 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 70 / d, x - 6 / d, y - 63 / d, x - 8 / d, y - 63 / d, x - 16 / d, y - 59 / d, x - 14 / d, y - 58 / d, END, END);
+ hPlot(s, x + 16 / d, y - 59 / d, x + 8 / d, y - 63 / d, x + 6 / d, y - 63 / d, x + 2 / d + .5, y - 70 / d, x + 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 63 / d, x - 2 / d + .5, y - 70 / d, x - 6 / d, y - 63 / d, x - 8 / d, y - 63 / d, x - 16 / d, y - 59 / d, x - 14 / d, y - 58 / d, x - 10 / d, y - 58 / d, END, END);
hPlot(s, x - 10 / d, y - 57 / d, x - 12 / d, y - 56 / d, x - 18 / d, y - 56 / d, x - 36 / d, y - 47 / d, x - 36 / d, y - 39 / d, x - 28 / d, y - 41 / d, x - 28 / d, y - 46 / d, x - 20 / d, y - 50 / d, x - 18 / d, y - 50 / d, x - 14 / d, y - 46 / d, END, END);
hPlot(s, x - 28 / d, y - 41 / d, x + 30 / d, y - 55 / d, END, END);
hPlot(s, x + 28 / d, y - 58 / d, x + 22 / d, y - 56 / d, x + 22 / d, y - 53 / d, x + 28 / d, y - 52 / d, x + 34 / d, y - 54 / d, END, END);
@@ -180,11 +187,11 @@ void Monster::drawBalrog(Graphics::ManagedSurface *s, double x, double y, double
hPlot(s, x + 6 / d, y - 60 / d, x + 30 / d, y - 90 / d, x + 60 / d, y - 30 / d, x + 60 / d, y - 10 / d, x + 30 / d, y - 40 / d, x + 15 / d, y - 40 / d, END, END);
hPlot(s, x - 6 / d, y - 60 / d, x - 30 / d, y - 90 / d, x - 60 / d, y - 30 / d, x - 60 / d, y - 10 / d, x - 30 / d, y - 40 / d, x - 15 / d, y - 40 / d, END, END);
hPlot(s, x, y - 25 / d, x + 6 / d, y - 25 / d, x + 10 / d, y - 20 / d, x + 12 / d, y - 10 / d, x + 10 / d, y - 6 / d, x + 10 / d, y, x + 14 / d, y, x + 15 / d, y - 5 / d, x + 16 / d, y, x + 20 / d, y, END, END);
- hPlot(s, x + 20 / d, y - 6 / d, x + 18 / d, y - 10 / d, x + 18 / d, y - 20 / d, x + 15 / d, y - 30 / d, x + 15 / d, y - 45 / d, x + 40 / d, y - 60 / d, x + 40 / d, y - 70 / d, END, END);
- hPlot(s, x + 10 / d, y - 55 / d, x + 6 / d, y - 60 / d, x + 10 / d, y - 74 / d, x + 6 / d, y - 80 / d, x + 4 / d + .5, y - 80 / d, x + 3 / d + .5, y - 82 / d, x + 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
+ hPlot(s, x + 20 / d, y, x + 20 / d, y - 6 / d, x + 18 / d, y - 10 / d, x + 18 / d, y - 20 / d, x + 15 / d, y - 30 / d, x + 15 / d, y - 45 / d, x + 40 / d, y - 60 / d, x + 40 / d, y - 70 / d, END, END);
+ hPlot(s, x + 40 / d, y - 70 / d, x + 10 / d, y - 55 / d, x + 6 / d, y - 60 / d, x + 10 / d, y - 74 / d, x + 6 / d, y - 80 / d, x + 4 / d + .5, y - 80 / d, x + 3 / d + .5, y - 82 / d, x + 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
hPlot(s, x, y - 25 / d, x - 6 / d, y - 25 / d, x - 10 / d, y - 20 / d, x - 12 / d, y - 10 / d, x - 10 / d, y - 6 / d, x - 10 / d, y, x - 14 / d, y, x - 15 / d, y - 5 / d, x - 16 / d, y, x - 20 / d, y, END, END);
- hPlot(s, x - 20 / d, y - 6 / d, x - 18 / d, y - 10 / d, x - 18 / d, y - 20 / d, x - 15 / d, y - 30 / d, x - 15 / d, y - 45 / d, x - 40 / d, y - 60 / d, x - 40 / d, y - 70 / d, END, END);
- hPlot(s, x - 10 / d, y - 55 / d, x - 6 / d, y - 60 / d, x - 10 / d, y - 74 / d, x - 6 / d, y - 80 / d, x - 4 / d + .5, y - 80 / d, x - 3 / d + .5, y - 82 / d, x - 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
+ hPlot(s, x - 20 / d, y, x - 20 / d, y - 6 / d, x - 18 / d, y - 10 / d, x - 18 / d, y - 20 / d, x - 15 / d, y - 30 / d, x - 15 / d, y - 45 / d, x - 40 / d, y - 60 / d, x - 40 / d, y - 70 / d, END, END); // left wing
+ hPlot(s, x - 40 / d, y - 70 / d, x - 10 / d, y - 55 / d, x - 6 / d, y - 60 / d, x - 10 / d, y - 74 / d, x - 6 / d, y - 80 / d, x - 4 / d + .5, y - 80 / d, x - 3 / d + .5, y - 82 / d, x - 2 / d + .5, y - 80 / d, x, y - 80 / d, END, END);
hPlot(s, x - 6 / d, y - 25 / d, x, y - 6 / d, x + 10 / d, y, x + 4 / d + .5, y - 8 / d, x + 6 / d, y - 25 / d, END, END);
hPlot(s, x - 40 / d, y - 64 / d, x - 40 / d, y - 90 / d, x - 52 / d, y - 80 / d, x - 52 / d, y - 40 / d, END, END);
hPlot(s, x + 40 / d, y - 86 / d, x + 38 / d, y - 92 / d, x + 42 / d, y - 92 / d, x + 40 / d, y - 86 / d, x + 40 / d, y - 50 / d, END, END);
Commit: 74a39a6805980c32ffbfd3877cae4f2d7e493973
https://github.com/scummvm/scummvm/commit/74a39a6805980c32ffbfd3877cae4f2d7e493973
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Fix dungeon messages to start at X = 1
Changed paths:
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/status.cpp
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index 7f6f290c491..c80aba6381b 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -28,7 +28,7 @@ namespace Ultima0 {
namespace Views {
Attack::Attack() : View("Attack") {
- setBounds(Gfx::TextRect(0, 22, 26, 24));
+ setBounds(Gfx::TextRect(1, 22, 26, 24));
}
bool Attack::msgFocus(const FocusMessage &msg) {
@@ -48,10 +48,10 @@ void Attack::draw() {
s.clear();
if (_mode == AMULET) {
- s.writeString(Common::Point(1, 0), "1] Ladder Up");
- s.writeString(Common::Point(1, 1), "2] Ladder Down");
- s.writeString(Common::Point(1, 2), "3] Attack Monster");
- s.writeString(Common::Point(1, 3), "4] Bad Magic");
+ s.writeString(Common::Point(0, 0), "1] Ladder Up");
+ s.writeString(Common::Point(0, 1), "2] Ladder Down");
+ s.writeString(Common::Point(0, 2), "3] Attack Monster");
+ s.writeString(Common::Point(0, 3), "4] Bad Magic");
return;
}
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 01cbf5837e5..ca3ba3f0ff7 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -126,7 +126,7 @@ bool Dungeon::msgAction(const ActionMessage &msg) {
interact();
break;
case KEYBIND_ATTACK:
- showMessage("\x9""Attack!");
+ showMessage(" \x9""Attack!");
_status.draw(); // Render the message before we switch views
addView("Attack");
break;
diff --git a/engines/ultima/ultima0/views/status.cpp b/engines/ultima/ultima0/views/status.cpp
index 46702c84e58..76321f44027 100644
--- a/engines/ultima/ultima0/views/status.cpp
+++ b/engines/ultima/ultima0/views/status.cpp
@@ -81,7 +81,7 @@ void DungeonStatus::draw() {
// Draw any extra lines
for (uint i = 0; i < _lines.size(); ++i)
- s.writeString(Common::Point(0, 1 + i), _lines[i]);
+ s.writeString(Common::Point(1, 1 + i), _lines[i]);
}
bool DungeonStatus::msgGame(const GameMessage &msg) {
@@ -101,6 +101,10 @@ bool DungeonStatus::msgGame(const GameMessage &msg) {
return true;
} else {
+ if (msg._name == "MSG")
+ // Changing message also resets any message lines
+ _lines.clear();
+
return Status::msgGame(msg);
}
}
Commit: 9b0753d16f55f3d866d5ab7d157a8dcd595b74da
https://github.com/scummvm/scummvm/commit/9b0753d16f55f3d866d5ab7d157a8dcd595b74da
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:31+11:00
Commit Message:
ULTIMA: ULTIMA0: Intro screen
Changed paths:
A engines/ultima/ultima0/views/intro.cpp
A engines/ultima/ultima0/views/intro.h
engines/ultima/module.mk
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 428cb2dcfb0..e0b6a118f0c 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -27,6 +27,7 @@ MODULE_OBJS += \
ultima0/views/dead.o \
ultima0/views/dungeon.o \
ultima0/views/info.o \
+ ultima0/views/intro.o \
ultima0/views/startup.o \
ultima0/views/status.o \
ultima0/views/title.o \
diff --git a/engines/ultima/ultima0/views/intro.cpp b/engines/ultima/ultima0/views/intro.cpp
new file mode 100644
index 00000000000..38199998525
--- /dev/null
+++ b/engines/ultima/ultima0/views/intro.cpp
@@ -0,0 +1,49 @@
+/* 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 "ultima/ultima0/views/intro.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+void Intro::draw() {
+ auto s = getSurface();
+ s.clear();
+ s.writeString(Common::Point(5, 1), "Many, many, many years ago the");
+ s.writeString(Common::Point(0, 3), "Dark Lord Mondain, Archfoe of British,");
+ s.writeString(Common::Point(0, 5), "traversed the lands of Akalabeth,");
+ s.writeString(Common::Point(0, 7), "spreading evil and death as he passed.");
+ s.writeString(Common::Point(0, 9), "By the time Mondain was driven from the");
+ s.writeString(Common::Point(0, 11), "land by British, bearer of the White");
+ s.writeString(Common::Point(0, 13), "Light, he had done much damage unto");
+ s.writeString(Common::Point(0, 15), "the lands.");
+ s.writeString(Common::Point(0, 17), "`Tis thy duty to help rid Akalabeth of");
+ s.writeString(Common::Point(0, 19), "the foul beasts which infest it,");
+ s.writeString(Common::Point(0, 21), "while trying to stay alive!!!");
+
+ s.writeString(Common::Point(20, 24), "Press any Key to Continue",
+ Graphics::kTextAlignCenter);
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/intro.h b/engines/ultima/ultima0/views/intro.h
new file mode 100644
index 00000000000..d366df96d1b
--- /dev/null
+++ b/engines/ultima/ultima0/views/intro.h
@@ -0,0 +1,60 @@
+/* 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 ULTIMA0_VIEWS_INTRO_H
+#define ULTIMA0_VIEWS_INTRO_H
+
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Intro : public View {
+private:
+ void showTitle() {
+ replaceView("Title");
+ }
+public:
+ Intro() : View("Intro") {}
+ ~Intro() override {}
+
+ void draw() override;
+
+ bool msgKeypress(const KeypressMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgMouseDown(const MouseDownMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgAction(const ActionMessage &msg) override {
+ showTitle();
+ return true;
+ }
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 45d45ad49e2..72c098c3ac0 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -28,6 +28,7 @@
#include "ultima/ultima0/views/dead.h"
#include "ultima/ultima0/views/dungeon.h"
#include "ultima/ultima0/views/info.h"
+#include "ultima/ultima0/views/intro.h"
#include "ultima/ultima0/views/startup.h"
#include "ultima/ultima0/views/title.h"
#include "ultima/ultima0/views/town.h"
@@ -44,6 +45,7 @@ struct Views {
Dead _dead;
Dungeon _dungeon;
Info _info;
+ Intro _intro;
Startup _startup;
Title _title;
Town _town;
Commit: 81a48f6a6416f889647a05f3f1b979f74eb51ea0
https://github.com/scummvm/scummvm/commit/81a48f6a6416f889647a05f3f1b979f74eb51ea0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:32+11:00
Commit Message:
ULTIMA: ULTIMA0: Added Acknowledgements view
Changed paths:
A engines/ultima/ultima0/views/acknowledgements.cpp
A engines/ultima/ultima0/views/acknowledgements.h
engines/ultima/module.mk
engines/ultima/ultima0/views/views.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index e0b6a118f0c..0d3e9ac7533 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -21,6 +21,7 @@ MODULE_OBJS += \
ultima0/gfx/map.o \
ultima0/gfx/monster.o \
ultima0/views/view.o \
+ ultima0/views/acknowledgements.o \
ultima0/views/attack.o \
ultima0/views/castle.o \
ultima0/views/create_character.o \
diff --git a/engines/ultima/ultima0/views/acknowledgements.cpp b/engines/ultima/ultima0/views/acknowledgements.cpp
new file mode 100644
index 00000000000..d42f9750524
--- /dev/null
+++ b/engines/ultima/ultima0/views/acknowledgements.cpp
@@ -0,0 +1,112 @@
+/* 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 "ultima/ultima0/views/acknowledgements.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+static const char *LINES[] = {
+ "Akalabeth PC-Conversion",
+ "",
+ "",
+ "Written by Richard Garriott",
+ "",
+ "",
+ "",
+ "PC-Conversion by",
+ "Corey Roth",
+ "with special assistance by",
+ "Nathan Tucker",
+ "",
+ "",
+ "",
+ "",
+ "Greets and Thanx go out to",
+ "Jake Groshong",
+ "Ronny McCrory",
+ "Adrian Dilley",
+ "Russell Kabir",
+ "James Ashley",
+ "Chris Harjo",
+ "and everyone else out there",
+ "who helped me out"
+ "",
+ "",
+ "",
+ "",
+ "This game made possible by:",
+ "",
+ "Origin",
+ "and",
+ "JUiCEY Bird Productions"
+};
+
+
+bool Acknowledgements::msgFocus(const FocusMessage &msg) {
+ // Set up the lines to display
+ _ctr = -1;
+ _lines.clear();
+ for (const char *line : LINES)
+ _lines.push(line);
+
+ for (int i = 0; i < 25; ++i)
+ _lines.push("");
+
+ auto s = getSurface();
+ s.clear();
+
+ // Create a buffer for rendering new lines
+ _pendingLine.create(s.w, Gfx::CHAR_HEIGHT);
+
+ return true;
+}
+
+void Acknowledgements::draw() {
+ auto s = getSurface();
+
+ // Shift up by one line
+ s.blitFrom(s, Common::Rect(0, 1, s.w, s.h), Common::Point(0, 0));
+ s.blitFrom(_pendingLine, Common::Rect(0, 0, _pendingLine.w, 1),
+ Common::Point(0, s.h - 1));
+ _pendingLine.blitFrom(_pendingLine, Common::Rect(0, 1, s.w, Gfx::CHAR_HEIGHT),
+ Common::Point(0, 0));
+}
+
+bool Acknowledgements::tick() {
+ _ctr = (_ctr + 1) % Gfx::CHAR_HEIGHT;
+ if (_ctr == 0) {
+ if (_lines.empty()) {
+ showTitle();
+ } else {
+ Common::String line = _lines.pop();
+ _pendingLine.writeString(Common::Point(20, 0), line, Graphics::kTextAlignCenter);
+ }
+ }
+
+ redraw();
+ return View::tick();
+}
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/acknowledgements.h b/engines/ultima/ultima0/views/acknowledgements.h
new file mode 100644
index 00000000000..b049924ca34
--- /dev/null
+++ b/engines/ultima/ultima0/views/acknowledgements.h
@@ -0,0 +1,66 @@
+/* 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 ULTIMA0_VIEWS_ACKNOWLEDGEMENTS_H
+#define ULTIMA0_VIEWS_ACKNOWLEDGEMENTS_H
+
+#include "common/queue.h"
+#include "ultima/ultima0/views/view.h"
+
+namespace Ultima {
+namespace Ultima0 {
+namespace Views {
+
+class Acknowledgements : public View {
+private:
+ Common::Queue<Common::String> _lines;
+ Gfx::GfxSurface _pendingLine;
+ int _ctr = 0;
+
+ void showTitle() {
+ replaceView("Title");
+ }
+public:
+ Acknowledgements() : View("Acknowledgements") {}
+ ~Acknowledgements() override {}
+
+ bool msgFocus(const FocusMessage &msg) override;
+ void draw() override;
+ bool tick() override;
+ bool msgKeypress(const KeypressMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgMouseDown(const MouseDownMessage &msg) override {
+ showTitle();
+ return true;
+ }
+ bool msgAction(const ActionMessage &msg) override {
+ showTitle();
+ return true;
+ }
+};
+
+} // namespace Views
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/views/views.h b/engines/ultima/ultima0/views/views.h
index 72c098c3ac0..8cdefd6e6be 100644
--- a/engines/ultima/ultima0/views/views.h
+++ b/engines/ultima/ultima0/views/views.h
@@ -22,6 +22,7 @@
#ifndef ULTIMA0_VIEWS_H
#define ULTIMA0_VIEWS_H
+#include "ultima/ultima0/views/acknowledgements.h"
#include "ultima/ultima0/views/attack.h"
#include "ultima/ultima0/views/castle.h"
#include "ultima/ultima0/views/create_character.h"
@@ -39,6 +40,7 @@ namespace Ultima0 {
namespace Views {
struct Views {
+ Acknowledgements _acknowledgements;
Attack _attack;
Castle _castle;
CreateCharacter _createCharacter;
Commit: eedc2811329fd2b0f7d8becb7e0243978817ff2a
https://github.com/scummvm/scummvm/commit/eedc2811329fd2b0f7d8becb7e0243978817ff2a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:32+11:00
Commit Message:
ULTIMA: ULTIMA0: Switching more keys to keybinder
Changed paths:
engines/ultima/ultima0/data/data.cpp
engines/ultima/ultima0/data/data.h
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/metaengine.h
engines/ultima/ultima0/views/attack.cpp
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/info.cpp
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/title.h
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/ultima0/data/data.cpp b/engines/ultima/ultima0/data/data.cpp
index 98fbc8536c8..7b4b1dd1db4 100644
--- a/engines/ultima/ultima0/data/data.cpp
+++ b/engines/ultima/ultima0/data/data.cpp
@@ -26,12 +26,12 @@ namespace Ultima {
namespace Ultima0 {
const ObjectInfo OBJECT_INFO[] = {
- { "Food", 1, 0, Common::KEYCODE_f },
- { "Rapier", 8, 10, Common::KEYCODE_r },
- { "Axe", 5, 5, Common::KEYCODE_a },
- { "Shield", 6, 1, Common::KEYCODE_s },
- { "Bow and Arrow", 3, 4, Common::KEYCODE_b },
- { "Magic Amulet", 15, 0, Common::KEYCODE_m }
+ { "Food", 1, 0, KEYBIND_FOOD },
+ { "Rapier", 8, 10, KEYBIND_RAPIER },
+ { "Axe", 5, 5, KEYBIND_AXE },
+ { "Shield", 6, 1, KEYBIND_SHIELD },
+ { "Bow and Arrow", 3, 4, KEYBIND_BOW },
+ { "Magic Amulet", 15, 0, KEYBIND_AMULET }
};
const MonsterInfo MONSTER_INFO[] = {
diff --git a/engines/ultima/ultima0/data/data.h b/engines/ultima/ultima0/data/data.h
index 5b222bf5b7b..fcc97461963 100644
--- a/engines/ultima/ultima0/data/data.h
+++ b/engines/ultima/ultima0/data/data.h
@@ -39,7 +39,7 @@ struct ObjectInfo {
const char *_name;
int _cost;
int _maxDamage;
- Common::KeyCode _keycode;
+ int _action;
};
struct MonsterInfo {
const char *_name;
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index 8850fdc9397..ac92dc76838 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -41,6 +41,26 @@ static const KeybindingRecord MINIMAL_KEYS[] = {
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
+static const KeybindingRecord MENU_KEYS[] = {
+ { KEYBIND_UP, "UP", _s("Up"), "UP", "JOY_UP" },
+ { KEYBIND_DOWN, "DOWN", _s("Down"), "DOWN", "JOY_DOWN" },
+ { KEYBIND_SELECT, "SELECT", _s("Select"), "SPACE", nullptr },
+ { KEYBIND_QUIT, "QUIT", _s("Quit"), "q", nullptr },
+ { KEYBIND_SWING, "SWING", _s("Swing"), "s", nullptr },
+ { KEYBIND_THROW, "THROW", _s("Throw"), "t", nullptr },
+ { KEYBIND_FOOD, "FOOD", _s("Food"), "f", nullptr },
+ { KEYBIND_RAPIER, "RAPIER", _s("Rapier"), "r", nullptr },
+ { KEYBIND_AXE, "AXE", _s("Axe"), "a", nullptr },
+ { KEYBIND_SHIELD, "SHIELD", _s("Shield"), "s", nullptr },
+ { KEYBIND_BOW, "BOW", _s("Bow & Arrow"), "b", nullptr },
+ { KEYBIND_AMULET, "AMULET", _s("Magic Amulet"), "a", nullptr },
+ { KEYBIND_AMULET1, "AMULET1", _s("Amulet Option 1"), "1", nullptr },
+ { KEYBIND_AMULET2, "AMULET2", _s("Amulet Option 2"), "2", nullptr },
+ { KEYBIND_AMULET3, "AMULET3", _s("Amulet Option 3"), "3", nullptr },
+ { KEYBIND_AMULET4, "AMULET4", _s("Amulet Option 4"), "4", nullptr },
+ { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
+};
+
static const KeybindingRecord OVERWORLD_KEYS[] = {
{ KEYBIND_UP, "UP", _s("North"), "UP", "JOY_UP" },
{ KEYBIND_DOWN, "DOWN", _s("South"), "DOWN", "JOY_DOWN" },
@@ -48,6 +68,7 @@ static const KeybindingRecord OVERWORLD_KEYS[] = {
{ KEYBIND_RIGHT, "RIGHT", _s("East"), "RIGHT", "JOY_RIGHT" },
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
+ { KEYBIND_QUIT, "QUIT", _s("Quit"), "q", nullptr },
{ KEYBIND_MINIMAP, "MINIMAP", _s("Minimap"), "m", nullptr },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
@@ -60,6 +81,7 @@ static const KeybindingRecord DUNGEON_KEYS[] = {
{ KEYBIND_ATTACK, "ATTACK", _s("Attack"), "a", "JOY_A" },
{ KEYBIND_ENTER, "ENTER", _s("Enter/Exit"), "e", "JOY_B" },
{ KEYBIND_INFO, "INFO", _s("Info"), "z", "JOY_X" },
+ { KEYBIND_QUIT, "QUIT", _s("Quit"), "q", nullptr },
{ KEYBIND_MINIMAP, "MINIMAP", _s("Minimap"), "m", nullptr },
{ KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr }
};
@@ -72,6 +94,7 @@ struct KeysRecord {
static const KeysRecord ALL_RECORDS[] = {
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
+ { "menu", _s("Menu Keys"), MENU_KEYS },
{ "overworld", _s("Overworld Keys"), OVERWORLD_KEYS },
{ "dungeon", _s("Dungeon Keys"), DUNGEON_KEYS },
{ nullptr, nullptr, nullptr }
@@ -82,6 +105,12 @@ static const KeysRecord MINIMAL_RECORDS[] = {
{ nullptr, nullptr, nullptr }
};
+static const KeysRecord MENU_RECORDS[] = {
+ { "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
+ { "menu", _s("Menu Keys"), MENU_KEYS },
+ { nullptr, nullptr, nullptr }
+};
+
static const KeysRecord OVERWORLD_RECORDS[] = {
{ "ultima0", _s("Basic Keys"), MINIMAL_KEYS },
{ "overworld", _s("Overworld Keys"), OVERWORLD_KEYS },
@@ -97,6 +126,7 @@ static const KeysRecord DUNGEON_RECORDS[] = {
static const KeysRecord *MODE_RECORDS[] = {
ALL_RECORDS,
MINIMAL_RECORDS,
+ MENU_RECORDS,
OVERWORLD_RECORDS,
DUNGEON_RECORDS,
};
@@ -125,6 +155,8 @@ Common::KeymapArray MetaEngine::initKeymaps(KeybindingMode mode) {
act->addDefaultInputMapping(r->_joy);
if (r->_action == KEYBIND_ENTER)
act->addDefaultInputMapping("x");
+ else if (r->_action == KEYBIND_SELECT)
+ act->addDefaultInputMapping("RETURN");
if (r->_action == KEYBIND_UP || r->_action == KEYBIND_DOWN ||
r->_action == KEYBIND_LEFT || r->_action == KEYBIND_RIGHT)
diff --git a/engines/ultima/ultima0/metaengine.h b/engines/ultima/ultima0/metaengine.h
index c30af2c6016..932740c074f 100644
--- a/engines/ultima/ultima0/metaengine.h
+++ b/engines/ultima/ultima0/metaengine.h
@@ -29,8 +29,13 @@ namespace Ultima0 {
enum KeybindingAction {
KEYBIND_UP, KEYBIND_DOWN, KEYBIND_LEFT, KEYBIND_RIGHT,
- KEYBIND_SELECT, KEYBIND_ESCAPE, KEYBIND_ENTER, KEYBIND_INFO,
- KEYBIND_ATTACK, KEYBIND_MINIMAP,
+ KEYBIND_ESCAPE, KEYBIND_QUIT, KEYBIND_ENTER, KEYBIND_INFO,
+ KEYBIND_ATTACK, KEYBIND_SWING, KEYBIND_THROW,
+ KEYBIND_AMULET1, KEYBIND_AMULET2, KEYBIND_AMULET3, KEYBIND_AMULET4,
+ KEYBIND_MINIMAP,
+
+ KEYBIND_SELECT, KEYBIND_FOOD, KEYBIND_RAPIER, KEYBIND_AXE,
+ KEYBIND_SHIELD, KEYBIND_BOW, KEYBIND_AMULET,
KEYBIND_NONE
};
@@ -38,6 +43,7 @@ enum KeybindingAction {
enum KeybindingMode {
KBMODE_ALL,
KBMODE_MINIMAL,
+ KBMODE_MENUS,
KBMODE_OVERWORLD,
KBMODE_DUNGEONS
};
diff --git a/engines/ultima/ultima0/views/attack.cpp b/engines/ultima/ultima0/views/attack.cpp
index c80aba6381b..7823c673ea0 100644
--- a/engines/ultima/ultima0/views/attack.cpp
+++ b/engines/ultima/ultima0/views/attack.cpp
@@ -34,7 +34,7 @@ Attack::Attack() : View("Attack") {
bool Attack::msgFocus(const FocusMessage &msg) {
_mode = WHICH_WEAPON;
_message = "";
- MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
+ MetaEngine::setKeybindingMode(KBMODE_MENUS);
return true;
}
@@ -64,6 +64,15 @@ void Attack::draw() {
}
bool Attack::msgKeypress(const KeypressMessage &msg) {
+ if (_mode == WHICH_WEAPON) {
+ selectObject(-1);
+ return true;
+ }
+
+ return false;
+}
+
+bool Attack::msgAction(const ActionMessage &msg) {
int objNum;
switch (_mode) {
@@ -71,7 +80,7 @@ bool Attack::msgKeypress(const KeypressMessage &msg) {
// Check for object selection, anything but food
objNum = -1;
for (uint i = OB_RAPIER; i < MAX_OBJ; ++i) {
- if (msg.keycode == OBJECT_INFO[i]._keycode) {
+ if (msg._action == OBJECT_INFO[i]._action) {
objNum = i;
break;
}
@@ -81,16 +90,16 @@ bool Attack::msgKeypress(const KeypressMessage &msg) {
break;
case AMULET:
- if (msg.keycode >= Common::KEYCODE_1 && msg.keycode <= Common::KEYCODE_4) {
- selectMagic(msg.keycode - Common::KEYCODE_1);
+ if (msg._action >= KEYBIND_AMULET1 && msg._action <= KEYBIND_AMULET4) {
+ selectMagic(msg._action - KEYBIND_AMULET1);
}
break;
case THROW_SWING:
- if (msg.keycode == Common::KEYCODE_t) {
+ if (msg._action == KEYBIND_THROW) {
_message += "Throw\n";
attackMissile();
- } else if (msg.keycode == Common::KEYCODE_s) {
+ } else if (msg._action == KEYBIND_SWING) {
_message += "Swing\n";
attackWeapon();
}
@@ -103,15 +112,6 @@ bool Attack::msgKeypress(const KeypressMessage &msg) {
return true;
}
-bool Attack::msgAction(const ActionMessage &msg) {
- if (_mode == WHICH_WEAPON) {
- selectObject(-1);
- return true;
- }
-
- return false;
-}
-
void Attack::selectObject(int objNum) {
auto &player = g_engine->_player;
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index ca3ba3f0ff7..9f19868def9 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -130,6 +130,11 @@ bool Dungeon::msgAction(const ActionMessage &msg) {
_status.draw(); // Render the message before we switch views
addView("Attack");
break;
+ case KEYBIND_QUIT:
+ // "Quit" in the original which merely saves the game. For ScummVM,
+ // we open the GMM, allowing the user to either save or quit
+ g_engine->openMainMenuDialog();
+ return true;
case KEYBIND_MINIMAP:
g_engine->_showMinimap = !g_engine->_showMinimap;
redraw();
@@ -147,18 +152,7 @@ bool Dungeon::msgKeypress(const KeypressMessage &msg) {
if (isDelayActive())
return false;
- switch (msg.keycode) {
- case Common::KEYCODE_q:
- // "Quit" in the original which merely saves the game. For ScummVM,
- // we open the GMM, allowing the user to either save or quit
- g_engine->openMainMenuDialog();
- return true;
-
- default:
- showMessage("Huh???");
- break;
- }
-
+ showMessage("Huh???");
endOfTurn();
return true;
}
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
index 9a25f2b6532..fe1606d84eb 100644
--- a/engines/ultima/ultima0/views/info.cpp
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -80,40 +80,41 @@ void Info::draw() {
s.writeString(Common::Point(18, 10), "Q-Quit");
}
+void Info::leave() {
+ const auto &player = g_engine->_player;
+ replaceView(player._level == 0 ? "WorldMap" : "DungeonMap");
+}
+
bool Info::msgKeypress(const KeypressMessage &msg) {
if (isDelayActive())
return false;
for (int i = 0; i < MAX_OBJ; ++i) {
- if (msg.keycode == OBJECT_INFO[i]._keycode ||
- (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i]._cost)) {
+ if (Common::isDigit(msg.ascii) && (msg.ascii - '0') == OBJECT_INFO[i]._cost) {
selectObject(i);
return true;
}
}
- if (msg.keycode == Common::KEYCODE_q) {
- leave();
- return true;
- }
-
return false;
}
-void Info::leave() {
- const auto &player = g_engine->_player;
- replaceView(player._level == 0 ? "WorldMap" : "DungeonMap");
-}
-
bool Info::msgAction(const ActionMessage &msg) {
if (isDelayActive())
return false;
- if (msg._action == KEYBIND_ESCAPE) {
+ if (msg._action == KEYBIND_ESCAPE || msg._action == KEYBIND_QUIT) {
leave();
return true;
}
+ for (int i = 0; i < MAX_OBJ; ++i) {
+ if (msg._action == OBJECT_INFO[i]._action) {
+ selectObject(i);
+ return true;
+ }
+ }
+
return false;
}
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index 235d466672c..beee8dea7fc 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -32,6 +32,12 @@ Title::Title() : View("Title") {
bool Title::msgFocus(const FocusMessage &msg) {
_highlightedOption = 0;
updateSelections();
+ MetaEngine::setKeybindingMode(KBMODE_MENUS);
+ return true;
+}
+
+bool Title::msgUnfocus(const UnfocusMessage &msg) {
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
return true;
}
@@ -55,15 +61,6 @@ void Title::draw() {
s.writeString(Common::Point(20, 8), "Ultima 0 - Akalabeth!", Graphics::kTextAlignCenter);
}
-bool Title::msgKeypress(const KeypressMessage &msg) {
- if (msg.keycode == Common::KEYCODE_RETURN) {
- selectOption();
- return true;
- }
-
- return false;
-}
-
bool Title::msgAction(const ActionMessage &msg) {
switch (msg._action) {
case KEYBIND_UP:
diff --git a/engines/ultima/ultima0/views/title.h b/engines/ultima/ultima0/views/title.h
index e2b8e91582a..790213b237f 100644
--- a/engines/ultima/ultima0/views/title.h
+++ b/engines/ultima/ultima0/views/title.h
@@ -57,8 +57,8 @@ public:
~Title() override {}
bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
- bool msgKeypress(const KeypressMessage &msg) override;
bool msgAction(const ActionMessage &msg) override;
bool msgGame(const GameMessage &msg) override;
bool msgMouseDown(const MouseDownMessage &msg);
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index c57dd1a44de..29fa35f6a62 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -90,6 +90,11 @@ bool WorldMap::msgAction(const ActionMessage &msg) {
case KEYBIND_ENTER:
enter();
break;
+ case KEYBIND_QUIT:
+ // "Quit" in the original which merely saves the game. For ScummVM,
+ // we open the GMM, allowing the user to either save or quit
+ g_engine->openMainMenuDialog();
+ return true;
case KEYBIND_MINIMAP:
g_engine->_showMinimap = !g_engine->_showMinimap;
redraw();
@@ -107,17 +112,6 @@ bool WorldMap::msgKeypress(const KeypressMessage &msg) {
if (isDelayActive())
return false;
- switch (msg.keycode) {
- case Common::KEYCODE_q:
- // "Quit" in the original which merely saves the game. For ScummVM,
- // we open the GMM, allowing the user to either save or quit
- g_engine->openMainMenuDialog();
- return true;
-
- default:
- break;
- }
-
endOfTurn();
return true;
}
Commit: d1d7e7ed1da94a04079355c172ea3c8808e5ec1e
https://github.com/scummvm/scummvm/commit/d1d7e7ed1da94a04079355c172ea3c8808e5ec1e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:32+11:00
Commit Message:
ULTIMA: ULTIMA0: Implement Title screen Journey Onwards option
Changed paths:
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/title.cpp
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 0ce5122137a..7dd8704d160 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -20,6 +20,7 @@
*/
#include "common/system.h"
+#include "common/savefile.h"
#include "engines/util.h"
#include "graphics/paletteman.h"
#include "ultima/ultima0/ultima0.h"
@@ -107,5 +108,14 @@ void Ultima0Engine::syncSavegame(Common::Serializer &s) {
_dungeon.synchronize(s);
}
+bool Ultima0Engine::savegamesExist() const {
+ Common::String slotName = getSaveStateName(1);
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
+ bool result = saveFile != nullptr;
+
+ delete saveFile;
+ return result;
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index 999b1072977..ba40e4e9fbe 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -114,6 +114,11 @@ public:
* @return returns kNoError on success, else an error code.
*/
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
+
+ /**
+ * Returns true if any savegames exist
+ */
+ bool savegamesExist() const;
};
extern Ultima0Engine *g_engine;
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index beee8dea7fc..de542fb4743 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -97,8 +97,17 @@ bool Title::msgMouseDown(const MouseDownMessage &msg) {
}
void Title::selectOption() {
- const char *VIEW_NAMES[4] = { "Intro", "CreateCharacter", "Acknowledgements", "Game" };
- replaceView(VIEW_NAMES[_highlightedOption]);
+ if (_highlightedOption == 3) {
+ if (g_engine->savegamesExist()) {
+ g_engine->loadGameDialog();
+ } else {
+ // Otherwise to go the Create Character view
+ replaceView("CreateCharacter");
+ }
+ } else {
+ const char *VIEW_NAMES[4] = { "Intro", "CreateCharacter", "Acknowledgements" };
+ replaceView(VIEW_NAMES[_highlightedOption]);
+ }
}
/*-------------------------------------------------------------------*/
Commit: d77d243dfa3010772b5206813b5b43a13b37935a
https://github.com/scummvm/scummvm/commit/d77d243dfa3010772b5206813b5b43a13b37935a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:32+11:00
Commit Message:
ULTIMA: ULTIMA0: Keybinder fixes
Changed paths:
engines/ultima/ultima0/metaengine.cpp
engines/ultima/ultima0/views/info.cpp
engines/ultima/ultima0/views/info.h
engines/ultima/ultima0/views/town.cpp
diff --git a/engines/ultima/ultima0/metaengine.cpp b/engines/ultima/ultima0/metaengine.cpp
index ac92dc76838..4f4bbeea5a0 100644
--- a/engines/ultima/ultima0/metaengine.cpp
+++ b/engines/ultima/ultima0/metaengine.cpp
@@ -53,7 +53,7 @@ static const KeybindingRecord MENU_KEYS[] = {
{ KEYBIND_AXE, "AXE", _s("Axe"), "a", nullptr },
{ KEYBIND_SHIELD, "SHIELD", _s("Shield"), "s", nullptr },
{ KEYBIND_BOW, "BOW", _s("Bow & Arrow"), "b", nullptr },
- { KEYBIND_AMULET, "AMULET", _s("Magic Amulet"), "a", nullptr },
+ { KEYBIND_AMULET, "AMULET", _s("Magic Amulet"), "m", nullptr },
{ KEYBIND_AMULET1, "AMULET1", _s("Amulet Option 1"), "1", nullptr },
{ KEYBIND_AMULET2, "AMULET2", _s("Amulet Option 2"), "2", nullptr },
{ KEYBIND_AMULET3, "AMULET3", _s("Amulet Option 3"), "3", nullptr },
diff --git a/engines/ultima/ultima0/views/info.cpp b/engines/ultima/ultima0/views/info.cpp
index fe1606d84eb..3bd24dd8998 100644
--- a/engines/ultima/ultima0/views/info.cpp
+++ b/engines/ultima/ultima0/views/info.cpp
@@ -29,6 +29,16 @@ namespace Views {
Info::Info(const char *viewName) : View(viewName) {
}
+bool Info::msgFocus(const FocusMessage &msg) {
+ MetaEngine::setKeybindingMode(KBMODE_MENUS);
+ return true;
+}
+
+bool Info::msgUnfocus(const UnfocusMessage &msg) {
+ MetaEngine::setKeybindingMode(KBMODE_MINIMAL);
+ return true;
+}
+
void Info::draw() {
const auto &player = g_engine->_player;
auto s = getSurface();
diff --git a/engines/ultima/ultima0/views/info.h b/engines/ultima/ultima0/views/info.h
index abeae91492a..c332f3b4868 100644
--- a/engines/ultima/ultima0/views/info.h
+++ b/engines/ultima/ultima0/views/info.h
@@ -59,6 +59,8 @@ public:
Info(const char *viewName = "Info");
~Info() override {}
+ bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
bool msgKeypress(const KeypressMessage &msg) override;
bool msgAction(const ActionMessage &msg) override;
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
index 57fe20417c1..42816f68488 100644
--- a/engines/ultima/ultima0/views/town.cpp
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -38,7 +38,7 @@ Town::Town() : Info("Town") {
bool Town::msgFocus(const FocusMessage &msg) {
_message = WELCOME;
- return true;
+ return Info::msgFocus(msg);
}
void Town::draw() {
Commit: 0410d08f751c2bd5d4bf298bc4d50bc3400ca4b3
https://github.com/scummvm/scummvm/commit/0410d08f751c2bd5d4bf298bc4d50bc3400ca4b3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:32+11:00
Commit Message:
ULTIMA: ULTIMA0: Added missing pages to Intro view
Changed paths:
engines/ultima/ultima0/views/intro.cpp
engines/ultima/ultima0/views/intro.h
diff --git a/engines/ultima/ultima0/views/intro.cpp b/engines/ultima/ultima0/views/intro.cpp
index 38199998525..8eda6e22b07 100644
--- a/engines/ultima/ultima0/views/intro.cpp
+++ b/engines/ultima/ultima0/views/intro.cpp
@@ -25,25 +25,100 @@ namespace Ultima {
namespace Ultima0 {
namespace Views {
+bool Intro::msgFocus(const FocusMessage &msg) {
+ _page = 0;
+ return true;
+}
+
void Intro::draw() {
auto s = getSurface();
s.clear();
- s.writeString(Common::Point(5, 1), "Many, many, many years ago the");
- s.writeString(Common::Point(0, 3), "Dark Lord Mondain, Archfoe of British,");
- s.writeString(Common::Point(0, 5), "traversed the lands of Akalabeth,");
- s.writeString(Common::Point(0, 7), "spreading evil and death as he passed.");
- s.writeString(Common::Point(0, 9), "By the time Mondain was driven from the");
- s.writeString(Common::Point(0, 11), "land by British, bearer of the White");
- s.writeString(Common::Point(0, 13), "Light, he had done much damage unto");
- s.writeString(Common::Point(0, 15), "the lands.");
- s.writeString(Common::Point(0, 17), "`Tis thy duty to help rid Akalabeth of");
- s.writeString(Common::Point(0, 19), "the foul beasts which infest it,");
- s.writeString(Common::Point(0, 21), "while trying to stay alive!!!");
-
- s.writeString(Common::Point(20, 24), "Press any Key to Continue",
+
+ switch (_page) {
+ case 0:
+ s.writeString(Common::Point(5, 1), "Many, many, many years ago the");
+ s.writeString(Common::Point(0, 3), "Dark Lord Mondain, Archfoe of British,");
+ s.writeString(Common::Point(0, 5), "traversed the lands of Akalabeth,");
+ s.writeString(Common::Point(0, 7), "spreading evil and death as he passed.");
+ s.writeString(Common::Point(0, 9), "By the time Mondain was driven from the");
+ s.writeString(Common::Point(0, 11), "land by British, bearer of the White");
+ s.writeString(Common::Point(0, 13), "Light, he had done much damage unto");
+ s.writeString(Common::Point(0, 15), "the lands.");
+ s.writeString(Common::Point(0, 17), "`Tis thy duty to help rid Akalabeth of");
+ s.writeString(Common::Point(0, 19), "the foul beasts which infest it,");
+ s.writeString(Common::Point(0, 21), "while trying to stay alive!!!");
+ break;
+
+ case 1:
+ s.writeString(Common::Point(0, 0), "The Player's Stats:");
+ s.writeString(Common::Point(0, 2), "Hit Points- Amount of Damage a Player");
+ s.writeString(Common::Point(0, 4), " can absorb before Death");
+ s.writeString(Common::Point(0, 6), "Strength--- Related to Damage Inflicted");
+ s.writeString(Common::Point(0, 8), " by Player against Monsters.");
+ s.writeString(Common::Point(0, 10), "Dexterity-- Related to the Probability");
+ s.writeString(Common::Point(0, 12), " of a Player hitting a Monst.");
+ s.writeString(Common::Point(0, 14), "Stamina---- Related to Player Defense");
+ s.writeString(Common::Point(0, 16), " against Monsters");
+ s.writeString(Common::Point(0, 18), "Wisdom----- This Attribute is used");
+ s.writeString(Common::Point(0, 20), " in Special (Quest!) Routines");
+ s.writeString(Common::Point(0, 22), "Gold------- Money!! Cash!! Assets!!");
+ break;
+
+ case 2:
+ s.writeString(Common::Point(0, 0), "The Towns and Buying Items:");
+ s.writeString(Common::Point(0, 2), " To buy any items one need only");
+ s.writeString(Common::Point(0, 4), "type the first letter of the item");
+ s.writeString(Common::Point(0, 6), "wanted. The cost of the respective");
+ s.writeString(Common::Point(0, 8), "items is displayed while in the town.");
+ s.writeString(Common::Point(0, 10), "The Game is started in a town somewhere");
+ s.writeString(Common::Point(0, 12), "on the 20x20 map");
+ s.writeString(Common::Point(20, 14), "Fighters and Magi", Graphics::kTextAlignCenter);
+ s.writeString(Common::Point(0, 16), " The disadvantage of being a");
+ s.writeString(Common::Point(0, 18), "fighter is the lack of the ability to");
+ s.writeString(Common::Point(0, 20), "control the magic amulet, whereas magi");
+ s.writeString(Common::Point(0, 22), "can not use rapier and bows.");
+ break;
+
+ case 3:
+ s.writeString(Common::Point(1, 0), "Movement:");
+ s.writeString(Common::Point(1, 2), "-Key- Outdoors Dungeon");
+ s.writeString(Common::Point(1, 4), " UP Move North Move Forward");
+ s.writeString(Common::Point(1, 6), " LEFT Move West Turn Left");
+ s.writeString(Common::Point(1, 8), "RIGHT Move East Turn Right");
+ s.writeString(Common::Point(1, 10), " DOWN Move South Turn Around");
+ s.writeString(Common::Point(1, 12), " Z Statistics Statistics");
+ s.writeString(Common::Point(1, 14), " A N/A Attack");
+ s.writeString(Common::Point(1, 16), " P Pause Pause");
+ s.writeString(Common::Point(1, 18), " E Go Into Town Clibm Ladder");
+ s.writeString(Common::Point(1, 20), " E Go Castle Go Hole");
+ s.writeString(Common::Point(1, 22), "SPACE Pass Pass");
+ break;
+
+ case 4:
+ s.writeString(Common::Point(0, 2), " Thou doest know the basics of");
+ s.writeString(Common::Point(0, 4), "the game, experiment with the commands.");
+ s.writeString(Common::Point(0, 6), "There is much left unsid for");
+ s.writeString(Common::Point(0, 8), "thee to discover in the future...");
+ s.writeString(Common::Point(0, 10), "Go now unto the world and seek");
+ s.writeString(Common::Point(0, 12), "adventure where thou might!!!");
+ s.writeString(Common::Point(0, 14), "P.S.-Search out the Castle of");
+ s.writeString(Common::Point(0, 16), "Lord British, Use the -E- Key to go in!");
+
+ default:
+ break;
+ }
+
+ s.writeString(Common::Point(20, (_page == 4) ? 18 : 24), "Press any Key to Continue",
Graphics::kTextAlignCenter);
}
+void Intro::nextPage() {
+ if (++_page < 5)
+ redraw();
+ else
+ replaceView("Title");
+}
+
} // namespace Views
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/views/intro.h b/engines/ultima/ultima0/views/intro.h
index d366df96d1b..8ed52113be9 100644
--- a/engines/ultima/ultima0/views/intro.h
+++ b/engines/ultima/ultima0/views/intro.h
@@ -30,25 +30,27 @@ namespace Views {
class Intro : public View {
private:
- void showTitle() {
- replaceView("Title");
- }
+ int _page = 0;
+
+ void nextPage();
+
public:
Intro() : View("Intro") {}
~Intro() override {}
+ bool msgFocus(const FocusMessage &msg) override;
void draw() override;
bool msgKeypress(const KeypressMessage &msg) override {
- showTitle();
+ nextPage();
return true;
}
bool msgMouseDown(const MouseDownMessage &msg) override {
- showTitle();
+ nextPage();
return true;
}
bool msgAction(const ActionMessage &msg) override {
- showTitle();
+ nextPage();
return true;
}
};
Commit: 6e098aad9525e1a0815d6bfd3ccec02e1f945b55
https://github.com/scummvm/scummvm/commit/6e098aad9525e1a0815d6bfd3ccec02e1f945b55
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-01-04T16:42:32+11:00
Commit Message:
ULTIMA: ULTIMA0: Add music player
Changed paths:
A engines/ultima/ultima0/music.cpp
A engines/ultima/ultima0/music.h
engines/ultima/module.mk
engines/ultima/ultima0/ultima0.cpp
engines/ultima/ultima0/ultima0.h
engines/ultima/ultima0/views/castle.cpp
engines/ultima/ultima0/views/castle.h
engines/ultima/ultima0/views/dungeon.cpp
engines/ultima/ultima0/views/title.cpp
engines/ultima/ultima0/views/town.cpp
engines/ultima/ultima0/views/town.h
engines/ultima/ultima0/views/world_map.cpp
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 0d3e9ac7533..33555fc4461 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -13,6 +13,7 @@ MODULE_OBJS += \
ultima0/events.o \
ultima0/messages.o \
ultima0/metaengine.o \
+ ultima0/music.o \
ultima0/data/data.o \
ultima0/data/monster_logic.o \
ultima0/gfx/dungeon.o \
diff --git a/engines/ultima/ultima0/music.cpp b/engines/ultima/ultima0/music.cpp
new file mode 100644
index 00000000000..8a06c7524d4
--- /dev/null
+++ b/engines/ultima/ultima0/music.cpp
@@ -0,0 +1,93 @@
+/* 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 "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "ultima/ultima0/music.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+MusicPlayer::MusicPlayer(const char *filename) : _filename(filename) {
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+void MusicPlayer::playSMF(bool loop) {
+ Common::StackLock lock(_mutex);
+
+ stop();
+
+ // Load MIDI resource data
+ Common::File musicFile;
+ if (!musicFile.open(_filename))
+ return;
+
+ int midiMusicSize = musicFile.size();
+ free(_midiData);
+ _midiData = (byte *)malloc(midiMusicSize);
+ musicFile.read(_midiData, midiMusicSize);
+ musicFile.close();
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_midiData, midiMusicSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ _isLooping = loop;
+ _isPlaying = true;
+ } else {
+ delete parser;
+ }
+}
+
+} // namespace Ultima0
+} // namespace Ultima
diff --git a/engines/ultima/ultima0/music.h b/engines/ultima/ultima0/music.h
new file mode 100644
index 00000000000..45d47781f4b
--- /dev/null
+++ b/engines/ultima/ultima0/music.h
@@ -0,0 +1,47 @@
+/* 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/>.
+ *
+ */
+
+// Music class
+
+#ifndef ULTIMA_ULTIMA0_MUSIC_H
+#define ULTIMA_ULTIMA0_MUSIC_H
+
+#include "audio/midiplayer.h"
+
+namespace Ultima {
+namespace Ultima0 {
+
+class MusicPlayer : public Audio::MidiPlayer {
+private:
+ Common::Path _filename;
+
+public:
+ MusicPlayer(const char *filename);
+ void playSMF(bool loop = false);
+
+ // Overload Audio::MidiPlayer method
+ void sendToChannel(byte channel, uint32 b) override;
+};
+
+} // namespace Ultima0
+} // namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima0/ultima0.cpp b/engines/ultima/ultima0/ultima0.cpp
index 7dd8704d160..c29798eacca 100644
--- a/engines/ultima/ultima0/ultima0.cpp
+++ b/engines/ultima/ultima0/ultima0.cpp
@@ -54,6 +54,7 @@ Ultima0Engine::Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription
}
Ultima0Engine::~Ultima0Engine() {
+ stopMidi();
}
Common::Error Ultima0Engine::run() {
@@ -91,6 +92,7 @@ Common::Error Ultima0Engine::loadGameStream(Common::SeekableReadStream *stream)
Common::Serializer s(stream, nullptr);
syncSavegame(s);
+ stopMidi();
replaceView(_player._level == 0 ? "WorldMap" : "Dungeon");
return Common::kNoError;
@@ -117,5 +119,20 @@ bool Ultima0Engine::savegamesExist() const {
return result;
}
+void Ultima0Engine::playMidi(const char *name) {
+ stopMidi();
+
+ _music = new MusicPlayer(name);
+ _music->playSMF(true);
+}
+
+void Ultima0Engine::stopMidi() {
+ if (_music) {
+ _music->stop();
+ delete _music;
+ _music = nullptr;
+ }
+}
+
} // namespace Ultima0
} // namespace Ultima
diff --git a/engines/ultima/ultima0/ultima0.h b/engines/ultima/ultima0/ultima0.h
index ba40e4e9fbe..793cb6c1a3f 100644
--- a/engines/ultima/ultima0/ultima0.h
+++ b/engines/ultima/ultima0/ultima0.h
@@ -29,6 +29,7 @@
#include "ultima/detection.h"
#include "ultima/ultima0/data/data.h"
#include "ultima/ultima0/events.h"
+#include "ultima/ultima0/music.h"
namespace Ultima {
namespace Ultima0 {
@@ -50,6 +51,7 @@ public:
WorldMapInfo _worldMap;
DungeonMapInfo _dungeon;
bool _showMinimap = false;
+ MusicPlayer *_music = nullptr;
Ultima0Engine(OSystem *syst, const Ultima::UltimaGameDescription *gameDesc);
~Ultima0Engine() override;
@@ -119,6 +121,12 @@ public:
* Returns true if any savegames exist
*/
bool savegamesExist() const;
+
+ void playMidi(const char *name);
+ void stopMidi();
+ bool isMidiPlaying() const {
+ return _music != nullptr;
+ }
};
extern Ultima0Engine *g_engine;
diff --git a/engines/ultima/ultima0/views/castle.cpp b/engines/ultima/ultima0/views/castle.cpp
index 02720b11da9..22e1baa3ee3 100644
--- a/engines/ultima/ultima0/views/castle.cpp
+++ b/engines/ultima/ultima0/views/castle.cpp
@@ -42,6 +42,12 @@ bool Castle::msgFocus(const FocusMessage &msg) {
_mode = TASK_INCOMPLETE;
}
+ g_engine->playMidi("lordbrit.mid");
+ return true;
+}
+
+bool Castle::msgUnfocus(const UnfocusMessage &msg) {
+ g_engine->stopMidi();
return true;
}
diff --git a/engines/ultima/ultima0/views/castle.h b/engines/ultima/ultima0/views/castle.h
index 55261c49b55..4156160e2ae 100644
--- a/engines/ultima/ultima0/views/castle.h
+++ b/engines/ultima/ultima0/views/castle.h
@@ -48,6 +48,7 @@ public:
~Castle() override {}
bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
bool msgKeypress(const KeypressMessage &msg) override;
bool msgAction(const ActionMessage &msg) override;
diff --git a/engines/ultima/ultima0/views/dungeon.cpp b/engines/ultima/ultima0/views/dungeon.cpp
index 9f19868def9..f836a263a8c 100644
--- a/engines/ultima/ultima0/views/dungeon.cpp
+++ b/engines/ultima/ultima0/views/dungeon.cpp
@@ -37,6 +37,10 @@ bool Dungeon::msgFocus(const FocusMessage &msg) {
showMessage("");
showLines("");
MetaEngine::setKeybindingMode(KBMODE_DUNGEONS);
+
+ if (!g_engine->isMidiPlaying())
+ g_engine->playMidi("dungeon.mid");
+
return true;
}
@@ -162,6 +166,7 @@ void Dungeon::endOfTurn() {
auto &dungeon = g_engine->_dungeon;
if (player._attr[AT_HP] <= 0) {
+ g_engine->stopMidi();
replaceView("Dead");
return;
}
@@ -172,6 +177,7 @@ void Dungeon::endOfTurn() {
player._object[OB_FOOD] = MAX(player._object[OB_FOOD] - 0.1, 0.0);
if (player._object[OB_FOOD] == 0) {
showMessage("You have starved...");
+ g_engine->stopMidi();
delaySeconds(1);
}
@@ -272,6 +278,7 @@ void Dungeon::interact() {
void Dungeon::timeout() {
const auto &player = g_engine->_player;
+ g_engine->stopMidi();
replaceView((player._level == 0) ? "WorldMap" : "Dead");
}
diff --git a/engines/ultima/ultima0/views/title.cpp b/engines/ultima/ultima0/views/title.cpp
index de542fb4743..6d773e70dd2 100644
--- a/engines/ultima/ultima0/views/title.cpp
+++ b/engines/ultima/ultima0/views/title.cpp
@@ -33,6 +33,13 @@ bool Title::msgFocus(const FocusMessage &msg) {
_highlightedOption = 0;
updateSelections();
MetaEngine::setKeybindingMode(KBMODE_MENUS);
+
+
+ Common::String priorView = msg._priorView->getName();
+ if (priorView == "Startup" || priorView == "Dead") {
+ g_engine->playMidi("intro.mid");
+ }
+
return true;
}
@@ -97,6 +104,9 @@ bool Title::msgMouseDown(const MouseDownMessage &msg) {
}
void Title::selectOption() {
+ if (_highlightedOption == 1 || _highlightedOption == 3)
+ g_engine->stopMidi();
+
if (_highlightedOption == 3) {
if (g_engine->savegamesExist()) {
g_engine->loadGameDialog();
diff --git a/engines/ultima/ultima0/views/town.cpp b/engines/ultima/ultima0/views/town.cpp
index 42816f68488..eca1756538a 100644
--- a/engines/ultima/ultima0/views/town.cpp
+++ b/engines/ultima/ultima0/views/town.cpp
@@ -38,9 +38,15 @@ Town::Town() : Info("Town") {
bool Town::msgFocus(const FocusMessage &msg) {
_message = WELCOME;
+ g_engine->playMidi("shop.mid");
return Info::msgFocus(msg);
}
+bool Town::msgUnfocus(const UnfocusMessage &msg) {
+ g_engine->stopMidi();
+ return Info::msgUnfocus(msg);
+}
+
void Town::draw() {
Info::draw();
diff --git a/engines/ultima/ultima0/views/town.h b/engines/ultima/ultima0/views/town.h
index f263bf0fa22..46511d58f11 100644
--- a/engines/ultima/ultima0/views/town.h
+++ b/engines/ultima/ultima0/views/town.h
@@ -42,6 +42,7 @@ public:
~Town() override {}
bool msgFocus(const FocusMessage &msg) override;
+ bool msgUnfocus(const UnfocusMessage &msg) override;
void draw() override;
void timeout() override;
};
diff --git a/engines/ultima/ultima0/views/world_map.cpp b/engines/ultima/ultima0/views/world_map.cpp
index 29fa35f6a62..4d9925da51f 100644
--- a/engines/ultima/ultima0/views/world_map.cpp
+++ b/engines/ultima/ultima0/views/world_map.cpp
@@ -35,6 +35,10 @@ WorldMap::WorldMap() : View("WorldMap") {
bool WorldMap::msgFocus(const FocusMessage &msg) {
showMessage("");
MetaEngine::setKeybindingMode(KBMODE_OVERWORLD);
+
+ if (!g_engine->isMidiPlaying())
+ g_engine->playMidi("over.mid");
+
return true;
}
@@ -120,6 +124,7 @@ void WorldMap::endOfTurn() {
auto &player = g_engine->_player;
if (player._attr[AT_HP] <= 0) {
+ g_engine->stopMidi();
replaceView("Dead");
} else {
@@ -136,6 +141,8 @@ void WorldMap::timeout() {
auto &player = g_engine->_player;
auto &dungeon = g_engine->_dungeon;
+ g_engine->stopMidi();
+
if (player._attr[AT_HP] <= 0 || player._object[OB_FOOD] <= 0) {
// Timeout from displaying player was killed
replaceView("Dead");
More information about the Scummvm-git-logs
mailing list