English Amiga Board


Go Back   English Amiga Board > Other Projects > project.Amiga Game Factory

 
 
Thread Tools
Old 06 May 2022, 00:52   #21
NicoDE
research
NicoDE's Avatar
 
Join Date: May 2018
Location: Germany
Posts: 20
Finished the structural analysis of the secondary blocks of the mission track data.
No member names and not that many comments yet - but it might already help you to get started.

Here is some pseudo-code:
Code:
#ifndef DOGSOFWAR_TRACKDATA_DOWMIS_H
#define DOGSOFWAR_TRACKDATA_DOWMIS_H

#if !defined(__GHIDRA__)
#include <stdint.h>
#define byte uint8_t
#define sbyte int8_t
#define word uint16_t
#define sword int16_t
#define dword uint32_t
#define sdword int32_t
#endif

/* org #$06AAF8 */

/*
 * Many Dogs of War track data blocks start with this header.
 * This is not specific to the misson data and is completely
 * ignored by the game (included here for documentation only).
 * The misson track data starts with a struct DowMisDataInfo.
 * All later offsets are relative to the data (offset 0x001C).
 */
struct DowMisDataTrackHead {
  byte bras_data[2]; /* bra.s data */
  byte data_size[4]; /* big-endian */
  byte reserved[22]; /* dcb.b 22,0 */
#if defined(__GHIDRA__) ||                                                     \
    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
  byte data[];
#endif
};

struct DowMisDataInfo {
  word data1[4]; /* relative offset to struct DowMisData1Misc */
  word data2[7]; /* relative offset to struct DowMisData2Head */
};

/******************************************************************************/

/*
 * The data1 blocks start with this (unused?) block (the game
 * just skips it and starts reading data at offset + 0x0040).
 */
struct DowMisData1Misc {
  dword reserved[16]; /* dcb.l 16,$00000024 */
};

/*TODO: data1 analysis */

/******************************************************************************/

struct DowMisData2End {
  byte end_tag; /* $FF */
};

enum DowMisData2_OpCode
#if defined(__GHIDRA__) || (defined(__cplusplus) && (__cplusplus >= 201103L))
    : byte
#endif
{
  /* struct DowMisData2_EAEF */
  DowMisData2_OpCode_EAEFMin = 0xEA,
  DowMisData2_OpCode_EAEFMax = 0xEF,
  /* struct DowMisData2_F0F5 */
  DowMisData2_OpCode_F0F5Min = 0xF0,
  DowMisData2_OpCode_F0F5Max = 0xF5,
  /* struct DowMisData2_FE */
  DowMisData2_OpCode_FE = 0xFE,
  /* struct DowMisData2_FD */
  DowMisData2_OpCode_FD = 0xFD,
  /* struct DowMisData2_F6FC */
  DowMisData2_OpCode_F6FCMin = 0xF6,
  DowMisData2_OpCode_F6FCMax = 0xFC,
  /* struct DowMisData2 (default case) */
  DowMisData2_OpCode_Min = 0x00,
  DowMisData2_OpCode_Max = 0x6F
  /* everything else is undefined behaviour */
};

struct DowMisData2Head {
  byte seq_num; /* game starts with $B8, stops with $FF */
  byte op_code; /* enum DowMisData2_OpCode */
};

struct DowMisData2Data {
  byte field0_0x0;
  byte field1_0x1;
};

struct DowMisData2 {
  struct DowMisData2Head head;  /* op_code = index into a game offset table */
  struct DowMisData2Data data;
};

struct DowMisData2_EAEFData {
  byte field0_0x0;
  byte field1_0x1;
};

struct DowMisData2_EAEF {
  struct DowMisData2Head head;
  struct DowMisData2_EAEFData data;
};

struct DowMisData2_F0F5Data {
  byte field0_0x0;
  byte field1_0x1;
  byte field2_0x2;
  byte field3_0x3;
  byte field4_0x4;
  byte field5_0x5;
};

struct DowMisData2_F0F5 {
  struct DowMisData2Head head;
  struct DowMisData2_F0F5Data data;
};

struct DowMisData2_F6FCData {
  byte field0_0x0;
  byte field1_0x1;
  byte field2_0x2;
  byte field3_0x3;
  byte field4_0x4;
};

struct DowMisData2_F6FCItemData {
  byte field0_0x0;
  byte field1_0x1;
  byte field2_0x2;
  byte field3_0x3;
};

union DowMisData2_F6FCItem {
  struct DowMisData2End end;
  struct DowMisData2_F6FCItemData data;
};

struct DowMisData2_F6FC {
  struct DowMisData2Head head;
  struct DowMisData2_F6FCData data;
#if defined(__GHIDRA__) ||                                                     \
    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
  struct DowMisData2_F6FCItem item[];
#endif
};

struct DowMisData2_FDData {
  byte field0_0x0;
  byte field1_0x1;
  byte field2_0x2;
  byte field3_0x3;
};

struct DowMisData2_FD {
  struct DowMisData2Head head;
  struct DowMisData2_FDData data;
};

struct DowMisData2_FEData {
  byte field0_0x0;
  byte field1_0x1;
  byte field2_0x2;
};

struct DowMisData2_FE {
  struct DowMisData2Head head;
  struct DowMisData2_FEData data;
};

#if !defined(__GHIDRA__)
#undef byte
#undef sbyte
#undef word
#undef sword
#undef dword
#undef sdword
#endif

#endif /* DOGSOFWAR_TRACKDATA_DOWMIS_H */
Attached mission track data as separated files.
Attached Files
File Type: zip Dogs of War (1989)(Elite)(Missions).zip (40.7 KB, 8 views)
NicoDE is offline  
Old 11 May 2022, 08:19   #22
NicoDE
research
NicoDE's Avatar
 
Join Date: May 2018
Location: Germany
Posts: 20
The default branch (0x00..0x6F) is the infantry. It inserts a new foot troops soldier (only if there is one of the 25 slots free) at a given position with a specific behavior.
Code:
enum DowMisData2_SeqNum {
  DowMisData2_SeqNum_Start = 0xB8,
  DowMisData2_SeqNum_End = 0xFF
};

enum DowMisData2_OpCode1 {
  /* struct DowMisData2_EAEF */
  DowMisData2_OpCode1_EAEFMin = 0xEA,
  DowMisData2_OpCode1_EAEFMax = 0xEF,
  /* struct DowMisData2_F0F5 */
  DowMisData2_OpCode1_F0F5Min = 0xF0,
  DowMisData2_OpCode1_F0F5Max = 0xF5,
  /* struct DowMisData2_FE */
  DowMisData2_OpCode1_FE = 0xFE,
  /* struct DowMisData2_FD */
  DowMisData2_OpCode1_FD = 0xFD,
  /* struct DowMisData2_F6FC */
  DowMisData2_OpCode1_F6FCMin = 0xF6,
  DowMisData2_OpCode1_F6FCMax = 0xFC,
  /* struct DowMisData2Foot (default case) */
  DowMisData2_OpCode1_FootMin = 0x00,
  DowMisData2_OpCode1_FootMax = 0x6F
  /* everything else is undefined behaviour */
};

struct DowMisData2Head {
  uint8_t seq_num; /* enum DowMisData2_SeqNum */
  uint8_t opcode1; /* enum DowMisData2_OpCode1 */
};

struct DowMisData2FootData {
  /* foot.pos_x = dow_byte_range_to_short(data.pos_x, 0xBF) + 100 */
  /* foot.pos_x[36,291] = data.pos_x[-64,191] + 100 */
  uint8_t pos_x;
  /* foot.pos_y = dow_byte_range_to_short(data.pos_y, 0xB0) + 100 */
  /* foot.pos_y[21,276] = data.pos_y[-79,176] + 100 */
  uint8_t pos_y;
};

struct DowMisData2Foot {
  struct DowMisData2Head head;
  struct DowMisData2FootData data;
};
To save space for the position definitions are specially encoded:
Code:
/* game code (two's complement): int16_t s = (u_max < b) ? (int8_t)b : b */
short dow_byte_range_to_short(unsigned char b, unsigned char u_max) {
  return (b <= u_max) ? (short)b : (short)((short)b - (short)0x100);
};

/* int16_t s = (int8_t)b */
short dow_byte_to_short(unsigned char b) {
  return dow_byte_range_to_short(b, 0x7F);
};
The opcode for the soldier defines the behavior. It is used as index into an offset table of foot troop actions:
(too big - attached)

As usual, 0xFF means 'end' (active soldier is removed from list). 0xFD and 0xFE is shooting (bullet vs. grenade). 0xFC starts a new movement:
Code:
struct {
  uint8_t opcode2; /* 0xFC */
  uint8_t step_count;
  int8_t step_x;
  int8_t step_y;
};
But at the given offset, the list has to start with a definition item:
Code:
struct {
  uint8_t opcode2; /* 0x00..0x0C */
  uint8_t reserved; /* not used */
  uint8_t step_count;
  int8_t step_x;
  int8_t step_y;
};
where 'opcode2' is an index into another table (looks like shooting definitions).
Attached Files
File Type: txt dow_mis_foot_action.txt (25.6 KB, 10 views)

Last edited by NicoDE; 11 May 2022 at 11:00.
NicoDE is offline  
Old 11 May 2022, 17:07   #23
NicoDE
research
NicoDE's Avatar
 
Join Date: May 2018
Location: Germany
Posts: 20
To resolve the mystery about the opcode2 in the foot definition item:
Code:
/* first byte in a dow_mis_foot_action[] entry is an index into this table */
/* the value in this table is a relativ  offset into dow_mis_foot_shoot[] */
unsigned short dow_mis_foot_shoot_offset[0x0C - 0x00 + 1] = {
    0x0000, 0x0009, 0x0016, 0x0023, 0x002B, 0x0034, 0x0035, 0x0036, 0x003F,
    0x004C, 0x0059, 0x0061, 0x006A
};

/* references to dow_mis_foot_shoot_info[].shoot_op, */
/* where 0xFF means repeat from the initial offset */
unsigned char dow_mis_foot_shoot[0x006B] = {
/* clang-format off */
    /* [0x00] = 0x0000 */
    0x00, 0x00, 0x01, 0x02, 0x03, 0x03, 0x02, 0x01, 0xFF,
    /* [0x01] = 0x0009 */
    0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0xFF,
    /* [0x02] = 0x0016 */
    0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0xFF,
    /* [0x03] = 0x0023 */
    0x0C, 0x0C, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0xFF,
    /* [0x04] = 0x002B */
    0x0C, 0x0C, 0x0C, 0x23, 0x23, 0x24, 0x25, 0x26, 0xFF,
    /* [0x05] = 0x0034 */
    0xFF,
    /* [0x06] = 0x0035 */
    0xFF,
    /* [0x07] = 0x0036 */
    0x11, 0x11, 0x12, 0x13, 0x14, 0x14, 0x13, 0x12, 0xFF,
    /* [0x08] = 0x003F */
    0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0xFF,
    /* [0x09] = 0x004C */
    0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0xFF,
    /* [0x0A] = 0x0059 */
    0x1D, 0x1D, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0xFF,
    /* [0x0B] = 0x0061 */
    0x1D, 0x1D, 0x1D, 0x23, 0x23, 0x24, 0x25, 0x26, 0xFF,
    /* [0x0C] = 0x006A */
    0xFF
/* clang-format on */
};

struct DowMisFootShootInfo {
  short shoot_op;
  short step_x;
  short step_y;
  short rel_x; /* relative to foot object pos_x */
  short rel_y; /* relative to foot object pos_y */
} const dow_mis_foot_shoot_info[24] = {
    {0x00, 0, 3, 4, 15},
    {0x01, 0, 3, 4, 15},
    {0x02, 0, 3, 4, 15},
    {0x03, 0, 3, 4, 15},
    {0x08, -3, 0, 0, 10},
    {0x09, -3, 0, 0, 10},
    {0x0A, -3, 0, 0, 10},
    {0x0B, -3, 0, 0, 10},
    {0x04, 3, 0, 15, 10},
    {0x05, 3, 0, 15, 10},
    {0x06, 3, 0, 15, 10},
    {0x07, 3, 0, 15, 10},
    {0x11, 0, 3, 8, 15},
    {0x12, 0, 3, 8, 15},
    {0x13, 0, 3, 8, 15},
    {0x14, 0, 3, 8, 15},
    {0x19, -3, 0, 0, 10},
    {0x1A, -3, 0, 0, 10},
    {0x1B, -3, 0, 0, 10},
    {0x1C, -3, 0, 0, 10},
    {0x15, 3, 0, 15, 10},
    {0x16, 3, 0, 15, 10},
    {0x17, 3, 0, 15, 10},
    {0x18, 3, 0, 15, 10}
};
Well, the infantry / foot troop soldiers should be complete now...
NicoDE is offline  
Old 13 May 2022, 08:52   #24
NicoDE
research
NicoDE's Avatar
 
Join Date: May 2018
Location: Germany
Posts: 20
While making progress in the background, I want to document one of the easier ones: opcode1 0xFE inserts/sets the target (the mission is completed when colliding with it).
Code:
struct DowMisData2TargetData {
  /* target.pos_x = dow_byte_range_to_short(data.pos_x, 0xBF) + 100 */
  uint8_t pos_x;
  /* target.pos_y = dow_byte_range_to_short(data.pos_y, 0xB0) */
  uint8_t pos_y;
  /* index into image data */
  uint8_t image_id;
};

struct DowMisData2Target {
  struct DowMisData2Head head; /* opcode1 = 0xFE */
  struct DowMisData2TargetData data;
};
Have a nice weekend.

ps: if TIMBO has been entered, you can directly complete the mission with P

pps: seems like there are objects hidden in the mission terrain data - I changed the mission 7 (Florida) event table offsets from 17BB1AED19681B92160A1C3B14B400 to 0016001600160016001600160016FF (immediately end all event lists), and there is still one gun turret in the level (see attached screenshot)...
Attached Thumbnails
Click image for larger version

Name:	dogsofwar-mission07-nope.png
Views:	15
Size:	11.1 KB
ID:	75575  

Last edited by NicoDE; 13 May 2022 at 10:27.
NicoDE is offline  
Old 13 May 2022, 10:23   #25
rofl0r
Registered User
 
Join Date: Jun 2012
Location: mt meru / hyberborea
Posts: 33
wow, this is truly amazing work, thanks a lot!

/me fires up editor to hack this into openDOW // edit if i can figure this all out - do you happen to be in the IRC at times ?

Last edited by rofl0r; 13 May 2022 at 10:38.
rofl0r is offline  
Old 13 May 2022, 10:29   #26
jotd
This cat is no more
jotd's Avatar
 
Join Date: Dec 2004
Location: FRANCE
Age: 50
Posts: 6,289
great collaboration guys!

I suggest that you keep the format of the original data when creating the editor, so you can re-inject the new levels in the original engine with a hacked whdload slave.
jotd is offline  
Old 13 May 2022, 10:37   #27
NicoDE
research
NicoDE's Avatar
 
Join Date: May 2018
Location: Germany
Posts: 20
Quote:
Originally Posted by rofl0r View Post
/me fires up editor to hack this into openDOW
There might be still more research required. The game seems to use different coordinates/offsets for object/player positions/collision/drawing... but that can be clarified later when all object types and properties are analyzed...

ps: well, there is even code to draw bullets differently per mission (I guess due to dark/bright terrain).
pps: seems with TIMBO active you can use 1-9 to play the different SFX, and besides F5 (toggle invisibility) and SPACE (hold to display back buffer) there seems to be another hidden debug toggle F10 (found no usage yet) - don't press press TAB or NUM-RETURN with TIMBO active ;-)

Last edited by NicoDE; 13 May 2022 at 10:44.
NicoDE is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Dogs of War -like game Firestone Looking for a game name ? 19 06 January 2016 16:50
Comment from Dogs of War coder on Youtube laffer Retrogaming General Discussion 7 29 September 2009 00:16
Dogs of War longplay laffer Retrogaming General Discussion 3 22 March 2008 00:43
Dogs Of War Macdilla New to Emulation or Amiga scene 3 25 January 2008 19:16
Dogs of War lhate56k support.Games 0 28 August 2004 16:33

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 22:53.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2022, vBulletin Solutions Inc.
Page generated in 0.07515 seconds with 16 queries