📄 video.cpp
字号:
// Video.cpp
//
/////////////////////////////////////////////////////////////////////////////
#include "Game.h"
#include <memory.h>
#include "Video.h"
int Video::pillOffsets[] = {
0x62, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x0c, 0x01, 0x01, 0x04, 0x01, 0x01,
0x01, 0x04, 0x04, 0x03, 0x0c, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x0c, 0x03,
0x01, 0x01, 0x01, 0x03, 0x04, 0x04, 0x03, 0x0c, 0x06, 0x03, 0x04, 0x04, 0x03,
0x0c, 0x06, 0x03, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x03, 0x04, 0x04, 0x0f, 0x03, 0x06, 0x04, 0x04, 0x0f, 0x03,
0x06, 0x04, 0x04, 0x01, 0x01, 0x01, 0x0c, 0x03, 0x01, 0x01, 0x01, 0x03, 0x04,
0x04, 0x03, 0x0c, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x0c, 0x03, 0x03, 0x03,
0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x0c, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01,
0x01, 0x08, 0x18, 0x08, 0x18, 0x04, 0x01, 0x01, 0x01, 0x01, 0x03, 0x0c, 0x01,
0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x04, 0x04, 0x03, 0x0c, 0x03, 0x03, 0x03,
0x04, 0x04, 0x03, 0x0c, 0x03, 0x03, 0x03, 0x04, 0x04, 0x01, 0x01, 0x01, 0x0c,
0x03, 0x01, 0x01, 0x01, 0x03, 0x04, 0x04, 0x0f, 0x03, 0x06, 0x04, 0x04, 0x0f,
0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x03, 0x04, 0x04, 0x03, 0x0c, 0x06, 0x03, 0x04, 0x04, 0x03, 0x0c,
0x06, 0x03, 0x04, 0x04, 0x03, 0x0c, 0x03, 0x01, 0x01, 0x01, 0x03, 0x04, 0x04,
0x03, 0x0c, 0x03, 0x03, 0x03, 0x04, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x0c,
0x01, 0x01, 0x04, 0x01, 0x01, 0x01
};
/////////////////////////////////////////////////////////////////////////////
// conversion methods
/////////////////////////////////////////////////////////////////////////////
// converts a position to a tile position
void Video::pos2TilePos(int posX, int posY, int &tilePosX, int &tilePosY)
{
// each tile is 8x8
tilePosX = posX/8;
tilePosY = posY/8;
// adjust to tile ranges
tilePosX += 0x1e;
tilePosY += 0x20;
}
// converts a tile position to screen coordinates
int Video::tilePos2ScreenCoord(int tilePosX, int tilePosY)
{
tilePosX -= 0x20;
tilePosY -= 0x20;
return ((tilePosX & 0xff)*32 + (tilePosY & 0xff) + 0x40) & 0x3ff;
}
/////////////////////////////////////////////////////////////////////////////
// CRAM/VRAM initialization
/////////////////////////////////////////////////////////////////////////////
// clears Video RAM
void Video::clearVRAM(bool gamePlayAreaOnly)
{
int init = (gamePlayAreaOnly) ? 0x040 : 0x000;
int size = (gamePlayAreaOnly) ? 0x380 : 0x400;
memset(&theGame->VRAM[init], 0x40, size);
}
// clears Color RAM
void Video::clearCRAM()
{
memset(theGame->CRAM, 0x00, 0x400);
}
// inits CRAM data
void Video::initCRAM(int mode)
{
// inits gameplay CRAM
memset(&theGame->CRAM[0x040], (mode == 2) ? 0x1f : 0x10, 0x380);
// inits top UI CRAM
memset(&theGame->CRAM[0x3c0], 0x0f, 0x040);
// mark "special" tiles if necessary
if (mode == 1){
// special color entry for pacman and ghosts initial map positions
for (int i = 0; i < 6; i++){
theGame->CRAM[0x1a0 + i*0x20 + 0x0c] = 0x1a;
theGame->CRAM[0x1a0 + i*0x20 + 0x18] = 0x1a;
}
// special color entry for tunnel areas
for (int i = 0; i < 5; i++){
theGame->CRAM[0x040 + i*0x20 + 0x0e] = 0x1b;
theGame->CRAM[0x040 + i*0x20 + 0x0f] = 0x1b;
theGame->CRAM[0x040 + i*0x20 + 0x10] = 0x1b;
theGame->CRAM[0x320 + i*0x20 + 0x0e] = 0x1b;
theGame->CRAM[0x320 + i*0x20 + 0x0f] = 0x1b;
theGame->CRAM[0x320 + i*0x20 + 0x10] = 0x1b;
}
// special color entry for ghost door
theGame->CRAM[0x1ed] = 0x18;
theGame->CRAM[0x20d] = 0x18;
}
}
// init CRAM area where lives are displayed
void Video::initLivesCRAM()
{
for (int j = 0; j < 2; j++){
for (int i = 0; i < 10; i++){
theGame->CRAM[0x012 + 0x20*j + i] = 0x09;
}
}
}
// restores special CRAM entries overwriten by player one or player two strings
void Video::restorePlayerTextCRAM()
{
for (int i = 0; i < 6; i++){
theGame->CRAM[0x1a0 + i*0x20 + 0x0c] = 0x1a;
}
}
/////////////////////////////////////////////////////////////////////////////
// drawing
/////////////////////////////////////////////////////////////////////////////
// draw a ghost in the VRAM
void Video::drawTileGhost(int offset, int color)
{
// draw first half
theGame->VRAM[offset + 0x00] = 0xb1;
theGame->VRAM[offset + 0x01] = 0xb3;
theGame->VRAM[offset + 0x02] = 0xb5;
// draw second half
theGame->VRAM[offset + 0x20] = 0xb0;
theGame->VRAM[offset + 0x21] = 0xb2;
theGame->VRAM[offset + 0x22] = 0xb4;
// set the color
theGame->CRAM[offset + 0x00] = theGame->CRAM[offset + 0x01] = theGame->CRAM[offset + 0x02] = color;
theGame->CRAM[offset + 0x20] = theGame->CRAM[offset + 0x21] = theGame->CRAM[offset + 0x22] = color;
}
// draw the fruits corresponding to the level (up to 7)
void Video::drawLevelFruits()
{
if (theGame->state != DEMO){
int currentLevel = theGame->levelState[0].currentLevel;
static int levelFruit[20][2] =
{
{ 0x90, 0x14 }, // cherry
{ 0x94, 0x0f }, // strawberry
{ 0x98, 0x15 }, // 1st orange
{ 0x98, 0x15 }, // 2nd orange
{ 0xa0, 0x14 }, // 1st apple
{ 0xa0, 0x14 }, // 2nd apple
{ 0xa4, 0x17 }, // 1st pineapple
{ 0xa4, 0x17 }, // 2nd pineapple
{ 0xa8, 0x09 }, // 1st galaxian
{ 0xa8, 0x09 }, // 2nd galaxian
{ 0x9c, 0x16 }, // 1st bell
{ 0x9c, 0x16 }, // 2nd bell
{ 0xac, 0x16 }, // 1st key
{ 0xac, 0x16 }, // 1st key
{ 0xac, 0x16 }, // 2nd key
{ 0xac, 0x16 }, // 3rd key
{ 0xac, 0x16 }, // 4th key
{ 0xac, 0x16 }, // 5th key
{ 0xac, 0x16 }, // 6th key
{ 0xac, 0x16 } // 7th key
};
int startingIndex = currentLevel - 6;
// check bounds
if (startingIndex < 0) startingIndex = 0;
if (startingIndex > 12) startingIndex = 12;
// show the fruits
for (int i = 0; i < 7; i++){
// should this fruit be visible?
if (i <= currentLevel){
// draw fruit
Video::draw2x2Tile(0x004 + i*2, levelFruit[startingIndex + i][0]);
Video::set2x2TileColor(0x004 + i*2, levelFruit[startingIndex + i][1]);
} else {
// draw emplty space
Video::draw2x2Tile(0x004 + i*2, 0x40);
Video::set2x2TileColor(0x004 + i*2, 0x00);
}
}
}
}
// draw the lives
void Video::drawLives(int lives)
{
// maxium of 5 lives
for (int i = 0; i < 5; i++){
if ((lives >= 6) || (lives == 0)){
// empty that area
Video::clear2x2Tile(0x01a - 2*i, 0x40);
} else {
// draw a pacman
Video::draw2x2Tile(0x01a - 2*i, 0x20);
lives--;
}
}
}
// draw 2 invisible lines to create a mini level
void Video::drawInvisibleMiniLevel()
{
// for each column
for (int i = 0; i < 28; i++){
// mark two tiles as not accesible
theGame->VRAM[0x40 + i*0x20 + 0x11] = 0xfc;
theGame->VRAM[0x40 + i*0x20 + 0x13] = 0xfc;
}
}
// draws the game level
void Video::drawGameLevel()
{
static int levelTileData[] = {
0x40, 0xfc, 0xd0, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd4, 0xfc,
0xfc, 0xfc, 0xda, 0x02, 0xdc, 0xfc, 0xfc, 0xfc, 0xd0, 0xd2, 0xd2, 0xd2, 0xd2,
0xd6, 0xd8, 0xd2, 0xd2, 0xd2, 0xd2, 0xd4, 0xfc, 0xda, 0x09, 0xdc, 0xfc, 0xfc,
0xfc, 0xda, 0x02, 0xdc, 0xfc, 0xfc, 0xfc, 0xda, 0x05, 0xde, 0xe4, 0x05, 0xdc,
0xfc, 0xda, 0x02, 0xe6, 0xe8, 0xea, 0x02, 0xe6, 0xea, 0x02, 0xdc, 0xfc, 0xfc,
0xfc, 0xda, 0x02, 0xdc, 0xfc, 0xfc, 0xfc, 0xda, 0x02, 0xe6, 0xea, 0x02, 0xe7,
0xeb, 0x02, 0xe6, 0xea, 0x02, 0xdc, 0xfc, 0xda, 0x02, 0xde, 0xfc, 0xe4, 0x02,
0xde, 0xe4, 0x02, 0xdc, 0xfc, 0xfc, 0xfc, 0xda, 0x02, 0xdc, 0xfc, 0xfc, 0xfc,
0xda, 0x02, 0xde, 0xe4, 0x05, 0xde, 0xe4, 0x02, 0xdc, 0xfc, 0xda, 0x02, 0xde,
0xfc, 0xe4, 0x02, 0xde, 0xe4, 0x02, 0xdc, 0xfc, 0xfc, 0xfc, 0xda, 0x02, 0xdc,
0xfc, 0xfc, 0xfc, 0xda, 0x02, 0xde, 0xf2, 0xe8, 0xe8, 0xea, 0x02, 0xde, 0xe4,
0x02, 0xdc, 0xfc, 0xda, 0x02, 0xe7, 0xe9, 0xeb, 0x02, 0xe7, 0xeb, 0x02, 0xe7,
0xd2, 0xd2, 0xd2, 0xeb, 0x02, 0xe7, 0xd2, 0xd2, 0xd2, 0xeb, 0x02, 0xe7, 0xe9,
0xe9, 0xe9, 0xeb, 0x02, 0xde, 0xe4, 0x02, 0xdc, 0xfc, 0xda, 0x1b, 0xde, 0xe4,
0x02, 0xdc, 0xfc, 0xda, 0x02, 0xe6, 0xe8, 0xf8, 0x02, 0xf6, 0xe8, 0xe8, 0xe8,
0xe8, 0xe8, 0xe8, 0xf8, 0x02, 0xf6, 0xe8, 0xe8, 0xe8, 0xea, 0x02, 0xe6, 0xf8,
0x02, 0xf6, 0xe8, 0xe8, 0xf4, 0xe4, 0x02, 0xdc, 0xfc, 0xda, 0x02, 0xde, 0xfc,
0xe4, 0x02, 0xf7, 0xe9, 0xe9, 0xf5, 0xf3, 0xe9, 0xe9, 0xf9, 0x02, 0xf7, 0xe9,
0xe9, 0xe9, 0xeb, 0x02, 0xde, 0xe4, 0x02, 0xf7, 0xe9, 0xe9, 0xf5, 0xe4, 0x02,
0xdc, 0xfc, 0xda, 0x02, 0xde, 0xfc, 0xe4, 0x05, 0xde, 0xe4, 0x0b, 0xde, 0xe4,
0x05, 0xde, 0xe4, 0x02, 0xdc, 0xfc, 0xda, 0x02, 0xde, 0xfc, 0xe4, 0x02, 0xe6,
0xea, 0x02, 0xde, 0xe4, 0x02, 0xec, 0xd3, 0xd3, 0xd3, 0xee, 0x02, 0xe6, 0xea,
0x02, 0xde, 0xe4, 0x02, 0xe6, 0xea, 0x02, 0xde, 0xe4, 0x02, 0xdc, 0xfc, 0xda,
0x02, 0xe7, 0xe9, 0xeb, 0x02, 0xde, 0xe4, 0x02, 0xe7, 0xeb, 0x02, 0xdc, 0xfc,
0xfc, 0xfc, 0xda, 0x02, 0xde, 0xe4, 0x02, 0xe7, 0xeb, 0x02, 0xde, 0xe4, 0x02,
0xe7, 0xeb, 0x02, 0xdc, 0xfc, 0xda, 0x06, 0xde, 0xe4, 0x05, 0xf0, 0xfc, 0xfc,
0xfc, 0xda, 0x02, 0xde, 0xe4, 0x05, 0xde, 0xe4, 0x05, 0xdc, 0xfc, 0xfa, 0xe8,
0xe8, 0xe8, 0xea, 0x02, 0xde, 0xf2, 0xe8, 0xe8, 0xea, 0x02, 0xce, 0xfc, 0xfc,
0xfc, 0xda, 0x02, 0xde, 0xf2, 0xe8, 0xe8, 0xea, 0x02, 0xde, 0xf2, 0xe8, 0xe8,
0xea, 0x02, 0xdc, 0x00
};
int tile;
int i = 0;
int offset = 0;
while (true){
// get data (0 = end of level data)
tile = levelTileData[i];
if (tile == 0) break;
// if it's < 0x80, it's an offset
if (tile < 0x80){
offset += tile - 1;
i++;
tile = levelTileData[i];
}
offset++;
// store tile
theGame->VRAM[offset] = tile;
// calculate mirror position
int mirrorOffset = (0x3e0 + (offset & 0x1f)*2) - offset;
// store mirror tile
theGame->VRAM[mirrorOffset] = tile ^ 1;
i++;
}
}
// draw active player pills
void Video::drawPlayerPills()
{
int offset = 0;
// iterate through normal pills
for (int i = 0; i < 240; i++){
offset += pillOffsets[i];
// if the player hasn't eaten it, draw it
if (theGame->levelState[0].normalPills[i]){
theGame->VRAM[offset] = 0x10;
}
}
// draw big pills
theGame->VRAM[0x064] = theGame->levelState[0].superPills[0];
theGame->VRAM[0x078] = theGame->levelState[0].superPills[1];
theGame->VRAM[0x384] = theGame->levelState[0].superPills[2];
theGame->VRAM[0x398] = theGame->levelState[0].superPills[3];
}
// clear remainig level pills (used if rack test is set)
void Video::clearLevelPills()
{
int pos = 0x040;
while (pos != 0x3c0){
int tile = theGame->VRAM[pos];
// if it has found a tile, clear it
if ((tile == 0x10) || (tile == 0x12) || (tile == 0x14)){
theGame->VRAM[pos] = 0x40;
}
pos++;
}
}
/////////////////////////////////////////////////////////////////////////////
// helper methods
/////////////////////////////////////////////////////////////////////////////
// draws a 2x2 tile graphic
void Video::draw2x2Tile(int offset, int tile)
{
theGame->VRAM[offset + 0x00] = tile + 0;
theGame->VRAM[offset + 0x01] = tile + 1;
theGame->VRAM[offset + 0x20] = tile + 2;
theGame->VRAM[offset + 0x21] = tile + 3;
}
// clear a 2x2 tile graphic
void Video::clear2x2Tile(int offset, int tile)
{
theGame->VRAM[offset + 0x00] = tile;
theGame->VRAM[offset + 0x01] = tile;
theGame->VRAM[offset + 0x20] = tile;
theGame->VRAM[offset + 0x21] = tile;
}
// sets the color for a 2x2 tile graphic
void Video::set2x2TileColor(int offset, int color)
{
theGame->CRAM[offset + 0x00] = color;
theGame->CRAM[offset + 0x01] = color;
theGame->CRAM[offset + 0x20] = color;
theGame->CRAM[offset + 0x21] = color;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -