Exult Ultima 7 Turn Based Combat, Day 3

I continued digging thru the source code to find the missing ingredients for the initial approach.

Modifications in other game modules

Player character combat mode

If TBC is activated, the Avatar character should always behave as in combat mode Manual.

This should be done using avatar->set_attack_mode(Actor::manual)

Blocking player actions

If tbc.isActive && tbc.playerBlocked (i.e. the player just acted, waiting for a new turn), player cannot do any of the following actions:

  • Attack a monster
  • Cast a spell
  • Use an Item

This should be doable by:

  • Preventing the inventory windows from showing: In Actor::show_inventory in actors.cc
  • Ignoring double click events: in Game_window::double_clicked in gamewin.cc

Limit walking while in combat

Every step the avatar takes should invoke tbc.updateWalkCounter

Probably on Game_window::start_actor_alt, still not sure… code inspection won’t be enough.

Next step, let’s hit the code

I set up a git repo based on the svn one, to track my changes and prevent getting lost. Exult’s official repo is SVN under sourceforge.net, like the old times. So in the end if this works I would have to make a patch for the current maintainers to apply, or maybe even submit the diff for them to replay my changes. I don’t know yet.

All the previous assumptions where based on inspecting the code, so I went ahead to try and add messages to the code and see if they matched on runtime (of course, some of them didn’t and most required tweaking)

I also discovered what people meant when they said “the project is compiling”, there’s effectively enough time to stand up and grab a cup of coffee. Amazing!

As expected, detecting the event when the avatar is walking proved to be a bit complex to find. In the ended I managed to intercept most of the code I think I’ll need for an initial approach.

Screen Shot 2016-02-13 at 3.59.50 PM
what. I don’t have a savegame outside Trinsic, and I have to test combat!

Next up was the creation of the Turn Based Combat module. So I created a .h and a .cc files based on other files,  included the header file in gamewin.cc and prayed for success. After some small tweaks (and learning quite a bit of C++) it worked 😛

noidea
Ah! so this is what they call “the linker”

So it’s now calling the functions on the new module. I started adding some of the real effects (like pausing the game) and found out there will be an issue since the pausing function doesn’t let the player move, so I must look for another way of pausing the game (or somehow overriding the way the time queue works for the Avatar to break the boundaries of time)

If you are curious, you can checkout the current status here. (or more importantly, the changes over here)

Exult U7 Turn Based Combat – Designing stuff

Check previous post for context

I started digging through the code, got some guidance from Malignant_Manor over #exult at freenode IRC. Other than that it was good old code archeology 🙂

General Structure

The idea is to create a new module for turn based combat (turn_based_combat.cc), it will include all the methods that will be called from other modules.

All these changes apply only if combat mode is set to turn based.

turn_based_combat.cc methods

pauseGame()

  • gwin->get_tqueue()->pause(SDL_GetTicks());

resumeGame()

  • gwin->get_tqueue()->resume(SDL_GetTicks());

onCombatStarted()

  • Invoke freezeTurn()

onCombatEnded()

  • Hide the “pass turn” button in the UI
  • Resume the game if paused

runTurn()

  • Hide the “pass turn” button in the UI
  • Set playerActionsBlocked = true
  • Resume the game
  • Schedule “Freeze turn” in TURN_TIME_MS
  • TURN_TIME_MS = what it takes for a melee action. (Use 500ms initially)

freezeTurn()

  • If combat is over, onCombatEnded() and return
  • Show the “pass turn” button in the UI
  • Set playerActionsBlocked = false
  • pauseGame()
  • Set the player walk counter to 0

updateWalkCounter()

  • Increase player walk counter by 1
  • STEPS_LIMIT = how many steps can the player take over the TURN_TIME_MS
  • If walk counter > STEPS_LIMIT, runTurn()

Modifications in other game modules

Activate Turn Based Combat Mode

These places must invoke tbc.onCombatStarted.

  • Game_window::toggle_combat in gamewin.cc, when setting combat to true. This is triggered by either being attacked by a NPC, or attacking an NPC,  or manually changing combat mode

Deactivate Turn Based Combat Mode

These places must invoke tbc.onCombatEnded.

  • Game_window::toggle_combat in gamewin.cc, when setting combat to false. This is triggered when the player dies. Couldn’t find out if it’s called when battle ends.

Player character combat mode

If TBC is activated, the Avatar character should always behave as in combat mode Manual.

Check for player turn-ending actions

These player actions must invoke tbc.endTurn

  • Attack a monster

TBC mode will override the player combat mode so it’s always manual. That means attacking a monster will be done specifically by double clicking on it. This is handled in Game_window::double_clicked in gamewin.cc, specifically by main_actor->set_target(obj);

This should set the main actor’s schedule to Schedule::combat, which in due time will invoke Combat_schedule::attack_target (combat.cc).

Turn should end here regardless if attack hits.

This method seems to handle both melee and ranged attacks, as well as probably using items on enemies to attack them. It also seems to happen after the attack animation, which is great for our purposes.

  • Cast a spell

Over Spellbook_object::execute_spell (objs/spellbook.cc), this intercepts just before the spell is cast, however must also have in mind spells requiring a target, these use the click_on_item intrinsic too (see below)

  • Use an item

This one’s a bit complex: initially Game_object::activate (objs/objs.cc) may work, the problem is some items are not used immediately but require setting a target, and the target selection is handled by the UI_click_on_item usecode intrinsic, which is ultimately represented in usecode/intrinsics.cc (there’s a #define magic going on there, but basically the code over USECODE_INTRINSIC(click_on_item) becomes what the usecode calls)

Passing the Turn

This involves adding a new UI element to the game window. When it’s clicked it must invoke tbc.endTurn.

Blocking player actions

If tbc.isActive && tbc.playerBlocked (i.e. the player just acted, waiting for a new turn), player cannot do any of the following actions:

  • Attack a monster
  • Cast a spell
  • Use an Item

Limit walking while in combat

Every step the avatar takes should invoke tbc.updateWalkCounter

Pending research, may also need to find a way to interrupt the walk path.

Ultima 7 Turn Based Combat for Exult

Ultima VII is a great game, I still remember around 1998 when my aunt bought a Pentium PC with “multimedia”, CD-ROM and a Sound Blaster card. It even had dialup Internet!

In a time where all you could find around were CDs with Shareware demos, I found a treasure among the driver CDs: Ultima VII, Ultima Underworld, Savage Empire and some other awesome games were included as some sort of samples of the power of Creative Labs’ Sound Blaster card. They even came with a small thick book bundling the manuals for all of them.

creative
Thank you, Creative Labs

Funny enough, getting these games to run was actually quite complex… most of them required tweaking things around, but it was worth it… I played the heck out of all of them (Except Wing Commander Academy, which for some reason I never liked too much, and the Mahjong one because… well, it was Mahjong.). These games were a defining part of my life… I learned English reading these manuals and playing these games made my interest in game development grow even more…

Back on track, Ultima VII is a great game… I still remember once I finally managed to make it run how a world came alive in my aunt’s computer screen. It felt so massive… the graphics looked so vivid, the music was so great, the world was alive with everyone living their own life… I think I didn’t actually get to play thru the game back then, but it left a great impression on me.

Screen Shot 2016-02-07 at 1.00.57 AM
Hint: There’s something creepy in the stables

That being said, there are two things that have always bothered me about Ultima 7:

  • The weird overhead perspective: Although I have been pointed out that it’s actually pretty effective for gameplay over other projections, since less space is hidden by walls.
  • The combat.

Combat is an important part on cRPGs. In some cases it’s the only type of conflict, and you need conflict to control the pace of the game.

Now, imagine you are playing Chrono Trigger (another cool game, a bit more widely known). Imagine you meet a group of enemies but instead of going into battle mode all your party members just pop up and run toward the enemies, while the party of enemies rushes to your characters and starts breaking through them. You don’t have a chance to think thru and use spells or items, everything happens so quickly that after 2 seconds your party is dead.

Cyccave
Just sit through the battle and hope everything goes well (Image from Ultima Wikia)

That’s basically what combat in U7 felt like. You were never in control. What a wasted opportunity, specially since previous games had contributed a great share to how tactical battles were handled in computer RPGs!

I must note that the game provided you with the opportunity to set up a combat mode for each of your party members, you could set them to attack the strongest or weakest opponent, among many other options. However, this didn’t really help much to engage with the game once combat started.

Screen Shot 2016-02-07 at 12.59.12 AM
Granted, dark blue on black isn’t very readable 🙂

Exult is one of the oldest and more popular Ultima fan projects; it allows you to run all the games using the Ultima 7 engine in modern platforms. It’s not a remake… it takes the data files from the original games and uses them to run a custom made engine, adding a lot of options for improved user experience in addition to making it dead simple to run in about any modern computer.

But, there’s another thing that Exult allows doing, it gives us a chance to fix things we don’t like about the original game. And that’s what I intend to do!

xrotate1
Some years ago there even were some efforts to provide a different perspective change (it wasn’t included in the main version for technical reasons)

I want combat in Ultima 7 to be more interesting, more relevant, more tactical. I want to try and make it turn based.

The idea is pretty simple:

  • Exult already supports pausing in combat
  • We must detect when the party engages in combat and auto pause.
  • From here the player can either:
    • Move around a limited number of steps
      • This one may probably be the most complex thing to detect
    • Attack a monster (either melee or ranged)
    • Cast a spell
    • Use an item
    • Pass the turn
      • Requires adding a button to the UI
  • Once the player does any of these, the game resumes for about half a second, and pauses again if still on battle and the player is still alive.

So far I have checked-out Exult’s source code and set up my dev environment with help from dominus. I started looking around a bit and found out pausing and resuming the game can be accomplished using gwin->get_tqueue()->pause(SDL_GetTicks()); and gwin->get_tqueue()->resume(SDL_GetTicks());

I’m planning to meet with dominus next week to discuss my idea with him and maybe get some pointers 🙂