📜 ⬆️ ⬇️

How in 1995 they wrote games for Sega Saturn

This is a document that I wrote in 1995 when I was working on the first game of the Neversoft studio: Skeleton Warriors. It was the first game in which I did not use 68K assembly language.

Picture taken around the time. The developer kit (dev kit) (“Small Box” and ICE) is on my right.


Game state


The following document briefly describes the state of the Skeleton Warriors code for the Sega Saturn, as well as some of the many aspects that still need to be mentioned.
')
The document was needed to speed up familiarity with the ready-made code to Dan, Ken and James, to explain to them the purpose of each module and the interaction between them. He also let me evaluate the sad state of this code, and hopefully made me take up the mind.

I also talk a little about embedding data (.GOV and .GOB files) into the program, and what we will do in the future.

Development Equipment


Our target platform is Sega Saturn, which has two SH2 Risc microprocessors and one 68000. While we are using only the Master SH2 main processor, the auxiliary slave SH2 will be used when we figure out how to do it. 68000 is used to control the sound chip, we did not have to write code for it, because it will use the sound library provided by Sega.

The program is almost entirely written in pure C. We use the GNU SH2 compiler to get the SH2 output assembler. There are several SH2 modules in the code, which mainly contain data only. So far I have not written anything meaningful on SH2.

As a development system, we use PsyQ. This is not a standard development system of Sega, but it is all who worked with it, consider it the best. An alternative to it is SNASM, created by Sega's Cross Products studio. The bulk of the code examples supplied by Sega should work in the SNASM development system, but can easily be converted to PsyQ.

The PsyQ system consists of a SCSI interface board that is installed in a PC, a cartridge inserted into Saturn and a cable connecting them. Sources are compiled on PC and downloaded to Saturn, where the program is launched. The code can be debugged from the PC.


PsyQ Development System

Communication is controlled by the resident program (PSYBIOS), the processing communication between the machines. This allows the Saturn console to download files from a PC almost as much as it would load them from a CD. We use this feature to download files of each level.

I have a couple of large and loud boxes in my room, and two more PCs. The smaller of the two boxes is the E7000PC, which is the built-in SH2 emulator. It helps to figure out where the program crashes if the PsyQ debugger has not stopped it. It is also useful for keeping track of memory records, but for now I have hardly used this feature.

The second of the high-profile boxes is something called the “Small Box” (the first “Large Box” was about the size of a small refrigerator). In fact, it is Saturn with additional interfaces for the E7000 and the CD emulator. On the front panel, it has country ID switches and a switch between PAL and NTSC.

Inside the second computer there is a CD emulator - a large board, thanks to which the hard disk of the computer pretends to be a CD-drive. You can build a CD image in it and emulate it in real time to see what the game will look like when it gets to a real CD. The emulator works more or less, although it has some problems that we are currently working on with Sega to solve.

image

Dev kit of Sega company itself

Compiling and compiling


The overall build of the finished program is controlled by one makefile: MAKEFILE.MAK. It contains dependencies and targets for the entire project, including compiling .GOB and .GOV files.

Individual C source code modules (.C files) are compiled by CCSH into SH2 object modules (.OBJ). It first calls the GNU C preprocessor called CPPSH (located in C: \ GNUSH2 \ BIN), then calls CC1SH for its output to create SH2 assembler code, and finally calls ASSH (in C: \ PSYQ) to build it in the finished object format.

We do not use C ++ because I have been told that it creates huge object files. However, I did not work with him, you can experiment.

Several SH2 assembly language files (with the .S extension) are simply assembled using ASMSH directly into .OBJ files (this is not the same as ASSH, but a more complex macro assembler). Currently, they are used only for embedding data, and do not contain machine-dependent code.

The Saturn RAM into which the code can be loaded is divided into two blocks of 1MB each. One starts at $ 06 million, and the other - at $ 00200000. The block at $ 00200000 is used exclusively to store the graphics of the main character. The program code is written to the address $ 06010000 (the first $ 10,000 bytes are used for the system space, the stack, and the like.)

The code is position-dependent and is compiled to run at this particular address ($ 6,010,000) and nothing else.

The .OBJ files are compiled together using the PSYLINK program to create the MAIN.CPE file — an executable program with a small header that can be downloaded to Saturn by the RUN command. PSYLINK uses the TEST.LNK file to specify which .OBJ files to include and where to put them.

Data


The game is divided into several levels, many levels use the same data, but basically they are different for each level. All data for each level is collected in two huge .GOV and .GOB files. (in the case of a mine, this is MINE.GOV and MINE.GOB). The GOV file contains a short header, and then all the data that should be in the video memory. The .GOB file contains all the data that should be in RAM.

The level consists of a portion of the data files shown below.

.Ssq - sprite sequencer file
.SBM - bitmap file used for bit backgrounds
.MAP - both cards for backgrounds filled with symbols.
.TIL - tilesets and palettes for character-filled backgrounds.
.PTH - data of road points and triggers.
.TEX - textures for the road.

The .SSQ and .SBM files are created by my increasingly awkward SEQ sequencer. The .MAP, .TIL, .PTH, and .TEX files are created by the increasingly awesome TULE map editor written by Dan.

These files are assembled with the ASMSH assembler into the corresponding .GOV and .GOB files. To see how this is done, see the files LEVEL.S and LEVEL1.S. The .GOV file also includes a portion of the data at a specific level.

Modules


TEST.S - nothing special, sets several labels.

MAIN.C is the top level of the program. It contains hardware initialization, level setting, code for passing levels, and various other small elements that would actually be placed in more suitable modules. There is quite a lot of garbage in it, because the easiest thing to add to this module is something new for quick testing. Contains the boot code from the CD or file server on the PC. Contains a flag to enable and disable the TIMING color bars.

GFXLIB.C - various procedures for accessing equipment and performing various graphical functions. Almost all of them are written from scratch by Dan and are often very inefficient. If you often use the procedure from here, then it would be nice to have a look at what it does and write a faster version in your code.

Nevertheless, all functions work and provide an excellent framework for draft implementation and testing. Thank Dan, it would be impossible without him.

SMP_PAD.C - various procedures for reading from the Saturn joystick, very dependent on the equipment.

GLOBALS.C - all global variables and several common functions. Using global variables is an acceptable programming practice. However, for various reasons, the implementation of global variables in SH2 is rather slow, so over time I will probably transform a part into global structures, if necessary. Contains variables describing the state of MAN and PATH .

MAN.C - handles the movement and display of a person (Prince Lightstar, Talyn, Guardian or Grimskull - the character, which is controlled by the player). While this is basically the logic of movement and collisions with the road. In addition, it provides the appropriate animation for each action. There is still a lot of work to be done.

OB.C - handles the movement and display of objects in the game, especially the objects of enemies, for example, skeletal warriors and small aliens. Here the main part of the gameplay is programmed: enemy AI, basic movements and triggering of triggers. The data structure is not fully ready yet, in particular, problems with collisions and animation are not completely worked out. There is still a lot of work.

DATA.S - various tables, currently mainly animations of the main characters of the player.

LAYER.C - scrolling backgrounds with parallax. It updates character backgrounds and scrolls bitmaps. Also performs scrolling lines (wave effect) in the fog layer. For now, the tables for the character map layers are stored without compression. They need to be compressed into the RLE format that I used for the version on Genesis. This task can go to Ken if we get a Saturn development system earlier than for Sony.

PAL.C - palette. You can choose from 2048 colors. Any pixel on the screen can be one of these colors. I logically divided the palette into eight palettes of 256 colors. PAL.C contains the code for their initialization, preparation and code for their cyclic change. They will also need a blackout and more complex cyclic change, as well as brightness flashes, etc.

BUL.C is a primitive system for processing shells (throwing a sword, hitting a hand, firing missiles, etc.) as separate objects. It still requires quite a lot of work for more complex use of projectiles. You also need the correct collision and animation code.

PAD.C is a simple module for storing the state of the joystick in a more convenient format. Remembers whether the button was recently pressed and if it is pressed now.

START.C - one line indicating which level will be the first, for the simplicity of its change in the batch file.

PANEL.C - simple procedures for outputting a strip of force.

PATH.C - monstrous procedures for drawing the road, as well as handling collisions with the road.

MATH.C - simple sine, cosine and rotation of a point by an angle.

[Update] Here is a sample code from MAN.C. Everything is strictly written in the code and refers to the global data structure Man. A bunch of numbers written in the code.

/**************************************************************/ /* Trigger jumping if needed, also variable height jump logic */ Man_JumpTrigger() { if ( Man.JumpFudge ) { Man.JumpFudge--; } if ( Man.Mode != M_Crouch || Man_StandingRoom() ) // ok if not crouched, or there is headroom { if (Pad_Jump->Pressed) /* jump button pressed */ { if ((Man.Contact || (Man.Mode == M_Hang) || Man.JumpFudge) && Pad_Jump->Triggered && !Man.Blocking) /* and not already jumping */ { if (Man.Mode == M_Hang && Pad1.Down.Pressed) { Man.Contact=0; Man.Mode=M_Jump; Man.AnimBase = LS_Jumping; /* Change base anim to jumping */ Man_TriggerSeq(LS_Jump); /* start the jumping start anim */ Man.YV.f = 0x10000; /* and have no YV */ Man.Yi += 4; /* and have no YV */ } else { Pad_Jump->Triggered = 0; if ( !JetPacCheat ) Man.YV.f = -0x00080000; /* Initial jump speed */ else Man.YV.f = -0x00008000; // Initial speed in Jetpac mode Man.Contact = 0; /* not on the ground any more */ Man.JumpTime = 0; /* just started jumping */ Man.AnimBase = LS_Jumping; /* Change base anim to jumping */ Man_TriggerSeq(LS_Jump); /* start the jumping start anim */ Man.XV.f+=Man.FlyVel; if (Man.HangEnd && Man.Mode == M_Hang) // if hanging { // and on the end of a path Man.HangEnd = 0; Man.Xi += 12*Man.Facing; // the move past end of path Man.JumpTime = -3; // bit more fixed v jump time } Man.Mode = M_Jump; /* change mode to jumping */ } } else /* Already jumping */ { if (Man.JumpTime++ < MaxJumpTime) /* Still in initial jump period */ Man.YV.f -= 0x0005000; /* So can maintain jump YV */ } } else /* jump button not pressed */ { Man.JumpTime = MaxJumpTime+1; /* so can't alter YV again until landed */ } } } 

OB.C has grown to a monstrous file of 9000 lines, which include all the patterns of behavior of individual objects in the game. Also there is a huge amount of numbers written in the code, for example:

 Drop_Arac(S_Ob *pOb) { int t; if (pOb->Jump==1) { pOb->yv.f+=0x7fff; pOb->y.f+=pOb->yv.f; t=Path_GetYZ(pOb->xi,pOb->yi,pOb)-15; if ((t>pOb->yi)&&(t<pOb->y.i+20)) { pOb->Jump=0; pOb->y.i+=15; Turn_Around(pOb); pOb->SeqFile=Sprites[SpriteMap[34]]; Object_TriggerSeq(Arac_JumpLand,pOb); } } else { if (pOb->Frame==16) pOb->Jump=1; if (pOb->AnimStat==AnimDone) { pOb->t1=0; pOb->Mode=&Pattern_Arac; } } Command_Arac(pOb); } 

An unpleasant sight. This style of code came from the times when the games were very small and I turned it on when working with 68K.

image

Source: https://habr.com/ru/post/459622/


All Articles