Coder Social home page Coder Social logo

bakgl's Introduction

BaK GL - Betrayal at Krondor remake using OpenGL

GCC 13 Build Status Clang 17 Build Status

This project is my attempt to remake Betrayal at Krondor using OpenGL.

It started out as a fun project to learn about graphics programming, but I've spent the vast majority of the time reverse engineering and reimplementing the game mechanics instead!

The game is mostly playable (with many rough edges), excluding combat. Improving the graphics will probably land at the end of the roadmap at this point as matching as close as possible the original game behaviour is much more addictive.

Here's a very quick look at some gameplay.

video

Features

  • Camping
  • Chapter progression
  • Cutscenes/Book excerpts
  • Music and sound
  • Quests and story
  • Shops and inventory
  • Spell casting
  • Temples
  • Towns
  • World exploration
  • World map

To do

  • Combat
  • Movement clipping
  • Lots of polishing!

Acknowledgements

This project would not have been possible without Guido de Jong's original work on xbak (http://xbak.sourceforge.net/).

I have used the late Eysteinn Björnsson's wonderful BaK Help Web extensively as a reference. This website is currently hosted at https://dimwood.net/krondor.html by vga256. I've also archived the contents on github.

Requirements

You will need a copy of Betrayal at Krondor for the game data files. These can be found on the web pretty easily.

Requires CMake, SDL2, SDL_MixerX, OpenGL, GLFW, and glm. Most of these dependencies will be downloaded and built automatically.

I use some features of C++23, so a more recent gcc or clang will be required to compile the code. You can check the CI to see what versions I am currently using. GCC 13 Build Status Clang 17 Build Status

Build

Linux

This project uses cmake. It can be built easily with

mkdir build; cd build;
cmake ..
make

The relevant binaries will be placed in your build directory.

Windows

You can build on Windows by opening the project in Visual Studio.

You may need to manually download some of the dependencies (freeglut, glew, and SDL2) and modify the CMakeLists.txt to point to them.

Mac

Due to Apple's deprecation of OpenGL Mac is not currently supported. It may compile and run if the required dependencies are installed and with some massaging of the CMake files.

Setup

BaKGL file main directory

BaKGL needs to find a number of different files in order to run with the game's original data. These are searched for in the bak main directory.

On UNIX systems this will be $HOME/bak, under Windows it will be %APPDATA%\bak. I will hereafter refer to this directory as $BAK_MAIN_DIR for both platforms.

Locate the original data files

In order to play around with the project you will need the original game data files.

You will specifically need the following files from your game:

krondor.001
krondor.rmf
frp.sx
startup.gam

BaKGL will look in either the current directory from which you ran the executable, or $BAK_MAIN_DIR/data for the game data files, so please copy them to the appropriate folder.

Make sure you check the case of the filenames in the folder where you installed BaK, if they are capitalised you will need to rename or copy them to lowercase.

Save files will be searched for in the $BAK_MAIN_DIR/GAMES directory, you can copy your old saves directory to this location. Alternatively, if you have no saves, the game will create this folder when you save your first game.

Run main3d

The main application is main3d. You can run this in the terminal in linux, or select it as the target in Visual Studio.

build $ ./main3d

Start a new game from the main menu as normal, and enjoy :)

Screenshots

waterfall_ui

northlands

sumani

macmordain

bakgl's People

Contributors

jorisvaneijden avatar xavieran avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bakgl's Issues

Quality of life improvements

  • Implement undo for non-chance based combat moves e.g. if you accidentally sent a character to the wrong place, undo and move him to the right place..
  • specify the precise cell from which to attack an enemy
  • Select multiple items in inventory for moving/selling
  • show icon on items that are repairable
  • Minimap
  • Player controlled journal/notebook
  • drop pins on map with labels/notes
  • increased combat difficulty option
  • Toggle health bars above enemies
  • Departure from the original, but perhaps you can sell non-shop native goods for a large discount. Would save constantly running back and forth to a matching (weapon) shop...
  • More details in the detailed info screen for more items (modifiers, spell descs)
  • Have characters share a ration pool when camping - toggle able option
  • ability to toggle the ui off when in the main view
  • indicate whether a container/enemy has been clicked already and if so mark if empty
  • make the leather leggings a +1 speed mod item? :)

Display shop inventories

  • 6 items per page
  • Scroll or move to next page
  • Prices under items
  • Appropriate dialogs for buying and selling

Complete TBL format loading

The remaining .TBL file to decipher is COMBAT.TBL. This seems to be mostly sprite indices and some objects (trap crystals and blasters).

Implement chapter transitions

For chapter 1 the transition happens when we click on the ladder to the palace:

10:12:11.10 INFO  [GameData]  Container: 22 addr: 4336f                                       
10:12:11.10 INFO  [GameData] DLog??: ac0a0b 720800,719600 #6 items: 0 capacity: 0 Tp: 3 Dunno
00000000: 00                                                                
10:12:11.10 INFO  [GameData] Picklock: 6a dialog: Key [ 0 ]                                   
10:12:11.10 DEBUG [GameData] PostLockDialog:  Key [ 231864 ]                                  
10:12:11.10 INFO  [GameData] Items:          

Dialog 231864 is:

17:50:51.11 INFO  [main] Current: Key [ 231864 ] (Offset { 23 @ 0x4ea })
17:50:51.11 INFO  [main] Snippet: [ ds: 0 act: 0 ds2: 10 ds3: 0 ]
>> GameState Chapter 1 | 1 : Offset { 23 @ 0x507 }
>> NoChoice 0 -> 0 | 0 : Offset { 23 @ 0x51a }
Text [  ]
Next [ Offset { 23 @ 0x51a } ]

GameState Chapter 1 | 1 : Offset { 23 @ 0x507 } (0)
NoChoice 0 -> 0 | 0 : Offset { 23 @ 0x51a } (1)
>>> 0
---------------------------------------- 
17:50:52.11 INFO  [main] Current: Offset { 23 @ 0x507 }
17:50:52.11 INFO  [main] Snippet: [ ds: 0 act: 0 ds2: 10 ds3: 0 ]
++ SetFlag {7541 mask: 0 data: 0 z: 0 val: 1}
Text [  ]
Next [ None ]

This simply sets the variable 0x7541 to 1. This must indicate to the transition from ch1 to ch2.

Need to figure out what actually happens

Properly implement logging to IMGUI console

Current impl is pretty hacky and ends up having a newline for every << operator. Fix this to buffer the string as it comes in and only send a new line to console when we encounter "\n"

Implement zone transitions

DEF_ZONE.DAT and zone encounters provide zone transitions. Decipher DEF_ZONE.DAT and implement the transitions.

Figure out overlapping "duplicate" hotspots

Some hotspots are duplicated. e.g. Sumani Dialog in GDS1B.DAT (Blue Wheel Inn)

20:41:41.09 SPAM  [BAK::SceneHotspots] Hotspot #4    
20:41:41.09 SPAM  [BAK::SceneHotspots] Unknown: 81df                                                                                                                                                                                             
20:41:41.09 SPAM  [BAK::SceneHotspots] Action: Dialog    
20:41:41.09 SPAM  [BAK::SceneHotspots] A1: 0 A2: 7 A3: 2dc6d4                                                                                                                        
20:41:41.09 SPAM  [BAK::SceneHotspots] RightClick: 16e366
20:41:41.09 SPAM  [BAK::SceneHotspots] Unknown2: 78f50000
20:41:41.09 SPAM  [BAK::SceneHotspots] LeftClick: 10000
20:41:41.09 SPAM  [BAK::SceneHotspots] Unknown3: 7530
20:41:41.09 SPAM  [BAK::SceneHotspots] Hotspot #5    
20:41:41.09 SPAM  [BAK::SceneHotspots] Unknown: 20                                                                                                                                                                                               
20:41:41.09 SPAM  [BAK::SceneHotspots] Action: Dialog    
20:41:41.09 SPAM  [BAK::SceneHotspots] A1: 0 A2: 7 A3: 2dc6d4                                                                                                                        
20:41:41.09 SPAM  [BAK::SceneHotspots] RightClick: 16e366
20:41:41.09 SPAM  [BAK::SceneHotspots] Unknown2: 79020000
20:41:41.09 SPAM  [BAK::SceneHotspots] LeftClick: 10000
20:41:41.09 SPAM  [BAK::SceneHotspots] Unknown3: 7530

Unknown seems to be some sort of condition determining which hotspot will be displayed.

There is similar in GDS2A.DAT (Krondor) for the palace

20:45:18.09 SPAM  [BAK::SceneHotspots] Hotspot #5
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown: 1fd
20:45:18.09 SPAM  [BAK::SceneHotspots] Action: Dialog
20:45:18.09 SPAM  [BAK::SceneHotspots] A1: 0 A2: 0 A3: 16e403
20:45:18.09 SPAM  [BAK::SceneHotspots] RightClick: 16e377
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown2: 7bb70000
20:45:18.09 SPAM  [BAK::SceneHotspots] LeftClick: 10000
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown3: 7530
20:45:18.09 SPAM  [BAK::SceneHotspots] Hotspot #6
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown: 1fe
20:45:18.09 SPAM  [BAK::SceneHotspots] Action: Dialog
20:45:18.09 SPAM  [BAK::SceneHotspots] A1: 0 A2: 0 A3: 16e3fa
20:45:18.09 SPAM  [BAK::SceneHotspots] RightClick: 16e377
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown2: 7bbb0000
20:45:18.09 SPAM  [BAK::SceneHotspots] LeftClick: 10000
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown3: 7530
20:45:18.09 SPAM  [BAK::SceneHotspots] Hotspot #7
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown: 3
20:45:18.09 SPAM  [BAK::SceneHotspots] Action: Goto
20:45:18.09 SPAM  [BAK::SceneHotspots] A1: 2 A2: 0 A3: 16e40c
20:45:18.09 SPAM  [BAK::SceneHotspots] RightClick: 16e377
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown2: 7bbf0000
20:45:18.09 SPAM  [BAK::SceneHotspots] LeftClick: 10000
20:45:18.09 SPAM  [BAK::SceneHotspots] Unknown3: 7530

HS 5:
(Chapter 2 - "After all the trouble we went through to avoid being noticed, don't you think it would be a bit stupid to stroll back through the gates," @4 fumed. "Let's get headed to Romney before we are spotted.")
HS 6:
(Chapter 1)
Palace gates sabotaged dialog
HS7:
All other chapters
Enter the palace

GUI model allows modifying the element tree whilst events are propagating it

e.g. if we ahve the following tree:
Frame -> Scene -> [Button, Button]

and we click on a button, the button then removes the Scene from the Frame, we will continue iterating through the tree to propagate the click event to the next button that has already been destructed.

Either defer gui graph modifications until after an event has fully propagated (some sort of callback queue maybe?) or return early from event handling if the gui graph is modified.

Decipher DEF_COMB.DAT

We currently have

  • Combat inventories
  • Combatant statistics
  • Combat entity lists (which combatants are in which combats)
    Need mapping from DEF_COMB.DAT to the above.

Implement inventory screen

  • Display active armor, crossbow/staff
  • Display items
  • Display gold
  • Display keys
  • Drag items to another character
  • Drag items to container
  • Split stacks of items

Implement Barding in Inns

  • Classify reward according to best skill
  • Mark barding as having been completed in shop
  • Give reward
  • Increase player skill level

Haggling

  • Figure out the haggling algo
  • Improve skill when haggling is attempted
  • mark items as unavailable if haggling failed
  • Persist reduced price from haggling

Shadows

  • Shadow map viewpoint should encompass the majority of the players viewpoint

Implement proper dialog screen

#22
#13
#19

  • Query choices should be placed in an aesthetically pleasing position (YES|NO choices)
  • Query choice should only present choice when mRemainingText is empty (currently we present the choice to early)
  • Fix player portraits (cX and fX actor ids)
  • Correctly implement action area parchment background (stretch to cover inventory)
  • Fix some dialogs when interacting with world objects
  • Fix character names in dialogs (@1, @2, @3, etc...)

Shops: dont buy all items

  • Only buy items shops allow
  • When items are sold to the shop correctly add them to the shops inventory (dont affect the permanent goods)

Implement 0x2 and 0x8 choices

DisplayStyle3 == 0x2 is a series of buttons selecting which choice to choose from
0x8 is select a random choice (e.g. dialogs in inns)

Decipher container format

Very ad-hoc currently with lots of special cases. Should be easier now that the dialogue can be used to identify boxes.

Properly implement encounters

  • Better store for encounters (e.g. pull them per chapter)
  • Figure out the correct location offsets
  • Figure out the meaning of the unknown parts
  • Implement encounter state tracking (e.g. always enter towns, dont enter dialogs immediately after already having encountered them.)

Implement GDS scene "local state"

Some events (usually random people in inns) check state 0x7530 - this seems to be if we've already clicked on them during this visit to the inn then evaluate to true. This resets when exiting/reentering the scene.
e.g.

---------------------------------------- 
22:41:23.09 INFO  [main] Current: Key [ 155cda ] (Offset { 14 @ 0x1452 })
22:41:23.09 INFO  [main] Snippet: [ ds: 0 act: 0 ds2: 10 ds3: 0 ]
>> 7530 -> 1 | ffff Offset { 14 @ 0x146f }
>> 0 -> 0 | 0 Offset { 14 @ 0x1693 }
Text [  ]
Next [ Offset { 14 @ 0x1693 } ]

7530 -> 1 | ffff Offset { 14 @ 0x146f } (0)
0 -> 0 | 0 Offset { 14 @ 0x1693 } (1)

Add names to dialog

e.g. Sumani in the dialog label when speaking to sumani. Will need to figure out KEYWORDS.DAT probably

Day/night cycle

Decide how to model time passing.
Probably on distance travelled as in the original.
Do the graphics to support this.

Figure out complex event states

Most events are simply setting a flag, but some are more complicated.

e.g. Captain Belfort at Lamut Garrison:

Text [  The Garrison was impressive.
        Sitting high on a hill overlooking LaMut, the military outpost had been constructed years earlier to head off a possible moredhel assault on the western border of the kingdom.
        They followed a road that snaked through town and up the rocky hill upon which the garrison sat. After speaking with the sentries at the gate, they were lead under the fortress's massive iron portcullis. ]
Next [ Offset { 19 @ 0xe69 } ]

dac0 -> 400 | ff01 Offset { 19 @ 0x1381 } (0)
dac0 -> 101 | ff01 Offset { 19 @ 0x995 } (1)
0 -> 0 | 0 Offset { 19 @ 0xe69 } (2)

This goes to

++ SetFlag {dac0, rest[ff 01 00 00 00 00]}
++ SetFlag {16, rest[00 00 00 00 01 00]}
Text [  Captain Belford stood as they entered the room.
        "It's good to see you once again, @4," he said, extending his hand.
        "I share that sentiment. What news have you? How is Earl Kasumi?" @4 asked as the men shook hands.
        They sat in hard wooden chairs as Belford replied. "He's well, but he's off taking care of some business with a few new guards come through the rift from Kelewan. As for the rest of us, we're looking for a group of grey warriors from Kelewan who slipped through the rift just before it closed."
        @4 looked a little puzzled. "King Lyam and Emperor Ichindar granted the grey warriors freedom and new status in the Kingdom."
        "Yes, but the agreement doesn't allow for the nationalization of stolen goods. Seems they may have absconded with a valuable ruby from Makala's entourage," said Belford.
        "Makala? The Tsurani Great One?" @3 asked.
        Belford smiled. "Yes. He has been talking to Prince Arutha about establishing a permanent rift to encourage trade between the Kingdom and Kelewan. He's really throwing his weight around trying to get his ruby back. If you should happen to come across it, bring it back here -- he's offering a reward!"
        They thanked him for his information and left. ]
Next [ None ]

The "SetFlag {dac0, [01ff]}" seems to set a full value rather than just a boolean flag.

Item description screen

Add item stats and "More Info"

More info for modifiers and status modifiers (amulet of upright man etc.)

Move items from and to containers

  • Move non-stackables
  • Move stackables
  • When taking key from container add it to parties keys.
  • Split stacks
  • Dialog when can't move item (e.g. inventory full)
  • Correctly handle moving equipped items
  • Generic framework for different container types (e.g. moving item into shop is selling)
  • Highlight active character
  • Grey out characters that can't accept items when dragging (green ones that can?)

Save Games

  • Character stats/skills
  • Character skills selected/unseen improvement flag
  • Character spells
  • Character conditions
  • Character inventories
  • Party key inventory
  • Active character list
  • chapter
  • save name
  • gold
  • location
  • world time
  • Shops (Barding, inventory)
  • Container inventories
  • Chests (Trapped or not)

Implement lock screen

  • Display keys and picklocks
  • Implement unlocking and picklocking logic
  • Implement query transition from world (Do you want to open the box)
  • Display lock types
  • Add text variable for selected character (@)
  • Highlight selected character

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.