+ Added Message module, used for tutorials.

+ Added first tutorial level.
* Font now inserts line feed automatically if the next word is too long to fit.
* Gfx.c: added primitive list double buffering in order to gain some performance.
* MapEditor: now airport can be defined inside the tool.
This commit is contained in:
XaviDCR92 2018-02-25 05:25:33 +01:00
parent 81d9242514
commit baa647ad7c
20 changed files with 540 additions and 113 deletions

Binary file not shown.

13
Levels/TUTORIA1.PLT Normal file
View File

@ -0,0 +1,13 @@
16:30
MESSAGE;00:04;Welcome to Airport! On this series of tutorials, you will be instructed to become an Air Traffic Controller (or ATC). This first tutorial shows how to control departure flights.
MESSAGE;00:07;Right now, the airport is empty. However, flights will come up really soon. Press to show the aircraft list.
MESSAGE;00:12;On the aircraft list menu, all active flights are listed. The time for the next aircraft to appear is shown below.
DEPARTURE;PHX1802;150;00:14;19;200
MESSAGE;00:15;Here comes our first aircraft. This is a departure flight, which is listed with an orange plane icon.
MESSAGE;00:16;"PHX1802" is the flight number. The flight number is tied to the airline carrier, so each plane starting with "PHX will use the same colours. This can be helpful when dealing with many aircraft.
MESSAGE;00:17;Below, the flight state is shown. When the flight state blinks, this means it is waiting for your instructions. Right now, it is parked and waiting for taxi.
MESSAGE;00:18;So press to select the aircraft. By pressing again, you will define the path to follow. Your target is the runway holding point, marked in green.
MESSAGE;00:25;Don't panic if you cannot create a valid path. You can press anytime to cancel the current path.
MESSAGE;00:32;Once the aircraft arrives to the runway holding point, it waits for your clearance to get into the runway. "Holding" state will be shown on the aircraft list menu.
MESSAGE;00:31;Take into account you cannot enter an aircraft into a runway if another aircraft is still landing on it.
MESSAGE;00:40;If everything went well, your aircraft must be on the runway, ready for takeoff. Clear the takeoff and let's hear the engines roaring!

BIN
Source/Exe/AIRPORT.elf Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -15,6 +15,21 @@
#define FONT_DEFAULT_CHAR_SIZE 16
#define FONT_DEFAULT_INIT_CHAR '!'
/* *************************************
* Structs and enums
* *************************************/
enum
{
// We will use the most significant bit
// for internal purposes.
SQUARE_BTN_8BIT = 128,
CROSS_BTN_8BIT,
CIRCLE_BTN_8BIT,
TRIANGLE_BTN_8BIT
};
/* *************************************
* Local Prototypes
* *************************************/
@ -88,6 +103,11 @@ void FontSetSize(TYPE_FONT * ptrFont, short size)
ptrFont->spr.h = ptrFont->char_h;
}
void FontSetMaxCharPerLine(TYPE_FONT* ptrFont, uint8_t max)
{
ptrFont->max_ch_wrap = max;
}
void FontSetSpacing(TYPE_FONT* ptrFont, short spacing)
{
ptrFont->char_spacing = spacing;
@ -101,7 +121,7 @@ void FontCyclic(void)
void FontPrintText(TYPE_FONT * ptrFont, short x, short y, char* str, ...)
{
uint16_t i;
uint16_t line_count = 0;
uint8_t line_count = 0;
int result;
short orig_x = x;
@ -133,7 +153,7 @@ void FontPrintText(TYPE_FONT * ptrFont, short x, short y, char* str, ...)
for (i = 0; i < result ; i++)
{
char _ch = _internal_text[i];
unsigned char _ch = _internal_text[i];
if (_ch == '\0')
{
@ -144,13 +164,73 @@ void FontPrintText(TYPE_FONT * ptrFont, short x, short y, char* str, ...)
switch(_ch)
{
case ' ':
x += ptrFont->char_w;
{
bool linefeed_needed = false;
// Check if the next word fits on the same line
if ( (ptrFont->flags & FONT_WRAP_LINE) && (ptrFont->max_ch_wrap != 0) )
{
uint16_t j;
uint8_t aux_line_count = line_count;
for (j = i + 1; j < result; j++)
{
if (_internal_text[j] != ' ')
{
if (++aux_line_count >= ptrFont->max_ch_wrap)
{
line_count = 0;
x = orig_x;
y += ptrFont->char_h;
linefeed_needed = true;
break;
}
}
else
{
break;
}
}
}
if (linefeed_needed == false)
{
x += ptrFont->char_w;
}
continue;
}
case '\n':
x = orig_x;
y += ptrFont->char_h;
break;
case SQUARE_BTN_8BIT:
GfxDrawButton(x, y, PAD_SQUARE);
x += BUTTON_SIZE;
break;
case CIRCLE_BTN_8BIT:
GfxDrawButton(x, y, PAD_CIRCLE);
x += BUTTON_SIZE;
break;
case TRIANGLE_BTN_8BIT:
GfxDrawButton(x, y, PAD_TRIANGLE);
x += BUTTON_SIZE;
break;
case CROSS_BTN_8BIT:
GfxDrawButton(x, y, PAD_CROSS);
x += BUTTON_SIZE;
break;
default:
if ( (ptrFont->flags & FONT_WRAP_LINE) && (ptrFont->max_ch_wrap != 0) )
{
if (++line_count >= ptrFont->max_ch_wrap)

View File

@ -27,6 +27,7 @@ void FontSetInitChar(TYPE_FONT * ptrFont, char c);
void FontSetFlags(TYPE_FONT * ptrFont, FONT_FLAGS flags);
void FontCyclic(void);
void FontSetSpacing(TYPE_FONT* ptrFont, short spacing);
void FontSetMaxCharPerLine(TYPE_FONT* ptrFont, uint8_t max);
/* *************************************
* Global variables

View File

@ -12,6 +12,7 @@
#include "EndAnimation.h"
#include "Sfx.h"
#include "Pad.h"
#include "Message.h"
/* *************************************
* Defines
@ -444,6 +445,9 @@ void GameInit(TYPE_GAME_CONFIGURATION* pGameCfg)
GameStartupFlag = true;
// Has to be initialized before loading *.PLT files inside LoadMenu().
MessageInit();
if (firstLoad != false)
{
firstLoad = false;
@ -782,7 +786,7 @@ void GameEmergencyMode(void)
for (i = 0; i < MAX_PLAYERS; i++)
{
if (disconnected_players & (1<<i) )
if (disconnected_players & (1 << i) )
{
FontPrintText( &SmallFont,
PAD_DISCONNECTED_TEXT_X,
@ -803,11 +807,11 @@ void GameEmergencyMode(void)
if (PadXConnected[i]() == false)
{
enabled = true;
disconnected_players |= 1<<i;
disconnected_players |= 1 << i;
}
else
{
disconnected_players &= ~(1<<i);
disconnected_players &= ~(1 << i);
}
}
}
@ -896,6 +900,7 @@ void GameCalculations(void)
GameGetAircraftTilemap(i);
}
MessageHandler();
AircraftHandler();
GameGuiCalculateSlowScore();
@ -1057,12 +1062,11 @@ void GameClockFlights(uint8_t i)
void GameGraphics(void)
{
int i;
uint8_t i;
bool split_screen = false;
SystemAcknowledgeFrame();
while ( (SystemRefreshNeeded() == false) || (GfxReadyForDMATransfer() == false) );
// Caution: blocking function!
MessageRender();
if (TwoPlayersActive != false)
{
@ -1113,8 +1117,8 @@ void GameGraphics(void)
if (split_screen != false)
{
GfxDrawScene_NoSwap();
while (GfxIsGPUBusy() != false);
//~ GfxDrawScene_NoSwap();
//~ while (GsIsDrawing() != false);
}
}
}
@ -1136,7 +1140,7 @@ void GameGraphics(void)
if (split_screen != false)
{
GfxDrawScene_NoSwap();
//~ GfxDrawScene_NoSwap();
}
GfxDrawScene();
@ -2739,8 +2743,6 @@ void GameAssignRunwaytoAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFli
// Remember that ptrPlayer->SelectedAircraft contains an index to
// be used with ptrFlightData.
Serial_printf("aircraftIndex = %d\n",aircraftIndex);
if (ptrFlightData->State[aircraftIndex] == STATE_APPROACH)
{
uint8_t j;
@ -2763,7 +2765,6 @@ void GameAssignRunwaytoAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFli
for (i = 0; i < GAME_MAX_RWY_LENGTH; i++)
{
rwyTiles[i] = GameLevelBuffer[rwyArray[i]];
dprintf("rwyTiles[%d] = 0x%02X\n", i, rwyTiles[i]);
}
for (i = 0; (i < GAME_MAX_RWY_LENGTH) && (rwyExit == 0); i++)
@ -2816,36 +2817,9 @@ void GameAssignRunwaytoAircraft(TYPE_PLAYER* ptrPlayer, TYPE_FLIGHT_DATA* ptrFli
targets[0] = rwyEntryData.rwyEntryTile;
targets[1] = targets[0] + rwyEntryData.rwyStep;
Serial_printf("Added the following targets = ");
for (i = 0; i < (sizeof(targets) / sizeof(targets[0])); i++)
{
Serial_printf("%d ", targets[i]);
}
Serial_printf("\n");
AircraftAddTargets(AircraftFromFlightDataIndex(aircraftIndex), targets);
ptrFlightData->State[aircraftIndex] = STATE_ENTERING_RWY;
/*uint16_t i;
i = rwyEntryData.rwyEntryTile;
DEBUG_PRINT_VAR(rwyEntryData.rwyEntryTile);
DEBUG_PRINT_VAR(rwyEntryData.rwyStep);
while (GameLevelBuffer[i] != TILE_RWY_START_1)
{
if (i > rwyEntryData.rwyStep)
{
i -= rwyEntryData.rwyStep;
}
}
GameGetSelectedRunwayArray(i);*/
}
}
@ -2905,11 +2879,9 @@ short GameGetYFromTile_short(uint16_t tile)
tile /= GameLevelColumns;
//retVal = (fix16_t)(tile << TILE_SIZE_BIT_SHIFT);
retVal = (tile << TILE_SIZE_BIT_SHIFT);
// Always point to tile center
//retVal += TILE_SIZE >> 1;
retVal += TILE_SIZE >> 1;
return retVal;
@ -3804,14 +3776,10 @@ void GameGetRunwayEntryTile(uint8_t aircraftIdx, TYPE_RWY_ENTRY_DATA* ptrRwyEntr
&&
((i - ptrRwyEntry->rwyStep) < GameLevelSize ) )
{
DEBUG_PRINT_VAR(i);
i -= ptrRwyEntry->rwyStep;
}
ptrRwyEntry->rwyHeader = i;
DEBUG_PRINT_VAR(ptrRwyEntry->rwyHeader);
DEBUG_PRINT_VAR(ptrRwyEntry->rwyEntryTile);
}
else
{

View File

@ -26,8 +26,6 @@
enum
{
BUTTON_SIZE = 16,
BUTTON_CROSS_U = 48,
BUTTON_CROSS_V = 0,
@ -82,7 +80,7 @@ GsSprite PSXButtons;
/* *************************************
* Local Prototypes
* *************************************/
void GfxSetPrimitiveList(unsigned int* ptrList);
/* *************************************
@ -95,6 +93,9 @@ static GsDrawEnv DrawEnv;
static GsDispEnv DispEnv;
// Primitive list (it contains all the graphical data for the GPU)
static unsigned int prim_list[PRIMITIVE_LIST_SIZE];
//Primitive list double buffering
static unsigned int prim_list2[PRIMITIVE_LIST_SIZE];
// Tells other modules whether data is being loaded to GPU
static volatile bool gfx_busy;
// Dictates (R,G,B) brigthness to all sprites silently
@ -213,9 +214,14 @@ void GfxInitDispEnv(void)
* used internally by PSXSDK).
*
* **********************************************************************/
void GfxSetPrimitiveList(void)
void GfxSetPrimitiveList(unsigned int* ptrList)
{
GsSetList(prim_list);
GsSetList(ptrList);
}
void GfxSetDefaultPrimitiveList(void)
{
GfxSetPrimitiveList(prim_list);
}
/* **********************************************************************
@ -278,12 +284,18 @@ bool GfxReadyForDMATransfer(void)
* **********************************************************************/
void GfxDrawScene(void)
{
while ( (SystemRefreshNeeded() == false)
||
static unsigned int* ptrPrimList = prim_list;
ptrPrimList = ((void*)ptrPrimList == (void*)&prim_list)? prim_list2 : prim_list;
while ( (SystemRefreshNeeded() == false)
||
(GfxIsGPUBusy() != false) );
GfxDrawScene_Fast();
GfxSetPrimitiveList(ptrPrimList);
SystemCyclicHandler();
}

View File

@ -23,6 +23,7 @@
#define GFX_2HZ_FLASH (1<<8)
#define FULL_LUMINANCE 0xFF
#define ROTATE_BIT_SHIFT 12 // 4096 = 2^12
#define BUTTON_SIZE 16
/* *************************************
* Global prototypes
@ -30,7 +31,7 @@
void GfxInitDrawEnv(void);
void GfxInitDispEnv(void);
void GfxSetPrimitiveList(void);
void GfxSetDefaultPrimitiveList(void);
// Renders new scene. Use this function unless you know what you are doing!
void GfxDrawScene(void);

View File

@ -50,7 +50,7 @@ SRC_DIR = .
OBJECTS = $(addprefix $(OBJ_DIR)/, main.o System.o Menu.o Gfx.o Pad.o MainMenuBtnAni.o \
LoadMenu.o GameGui.o Sfx.o Camera.o EndAnimation.o \
PSXSDKIntro.o PltParser.o Game.o Font.o MemCard.o \
Aircraft.o Serial.o Timer.o)
Aircraft.o Serial.o Timer.o Message.o)
# Source dependencies:
DEPS = $(OBJECTS:.o=.d)
@ -76,7 +76,7 @@ SOUND_OBJECTS = $(addprefix $(OBJ_SOUNDS_DIR)/, BELL.VAG \
# Level objects:
SRC_LEVELS_DIR = $(PROJECT_DIR)/Levels
OBJ_LEVELS_DIR = $(CDROM_ROOT)/DATA/LEVELS
LEVEL_OBJECTS = $(addprefix $(OBJ_LEVELS_DIR)/, LEVEL1.LVL LEVEL2.LVL LEVEL2.PLT LEVEL1.PLT EASY.PLT)
LEVEL_OBJECTS = $(addprefix $(OBJ_LEVELS_DIR)/, LEVEL1.LVL LEVEL2.LVL LEVEL2.PLT LEVEL1.PLT EASY.PLT TUTORIA1.PLT)
# Sprite objects:
BMP2TIM = bmp2tim

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.0.3, 2018-01-01T07:36:40. -->
<!-- Written by QtCreator 4.0.3, 2018-02-23T20:22:49. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@ -4,6 +4,8 @@
#include <QGraphicsPixmapItem>
#include <QInputDialog>
#define DEFAULT_AIRPORT_NAME QByteArray("Default Airport\0")
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
@ -11,13 +13,13 @@ MainWindow::MainWindow(QWidget *parent) :
selected_item(-1)
{
ui->setupUi(this);
ui->centralWidget->setWindowTitle("Airport Map Editor");
this->setWindowTitle(APP_NAME + " " + APP_VERSION_STRING);
connect(ui->LoadMap_Btn, SIGNAL(released()), this, SLOT(onLoadMap()));
connect(ui->CreateMap_Btn, SIGNAL(released()), this, SLOT(onCreateMap()));
connect(ui->saveMap_Btn, SIGNAL(released()), this, SLOT(onSaveMap(void)));
connect(ui->showNumbers_Checkbox, SIGNAL(stateChanged(int)), this, SLOT(onShowNumbers(int)));
connect(ui->airportName_Label, SIGNAL(textChanged(QString)), this, SLOT(onAirportNameModified(QString)));
connect(gscene, SIGNAL(positionClicked(QPointF)), this, SLOT(onMapItemClicked(QPointF)));
connect(gscene, SIGNAL(noItemSelected(void)), this, SLOT(onNoItemSelected(void)));
@ -161,15 +163,18 @@ void MainWindow::onCreateMap(void)
data.append((char)0x18);
}
data.append("Default airport");
data.append(DEFAULT_AIRPORT_NAME);
for (int i = 0x04 + DEFAULT_AIRPORT_NAME.count(); i < 0x1C; i++)
{
data.append('\0');
}
for (int i = (data.count() - 1); i < DATA_HEADER_SIZE; i++)
{
data.append(0xFF);
}
qDebug() << data.count();
int size_int = size.toInt(&ok, 10);
if (ok == false)
@ -243,7 +248,13 @@ void MainWindow::onProcessMapFile(QByteArray data)
return;
}
ds.skipRawData(0x3B);
char airportName[0x1A];
ds.readRawData(airportName, sizeof(airportName) / sizeof(airportName[0]));
ui->airportName_Label->setText(QString(airportName));
ds.skipRawData(0x3B - 0x1A);
gscene->clear();
gscene->clearFocus();
@ -417,3 +428,23 @@ void MainWindow::loadTilesetData(void)
}
}
}
void MainWindow::onAirportNameModified(QString name)
{
if (map_buffer.isEmpty() == true)
{
return;
}
for (int i = 0x04, j = 0; i < 0x1C; i++)
{
if (j < name.count() )
{
map_buffer[i] = name.at(j++).toLatin1();
}
else
{
map_buffer[i] = '\0';
}
}
}

View File

@ -9,6 +9,9 @@
#include "mygraphicsscene.h"
#include "ui_mainwindow.h"
#define APP_NAME QString("Airport Map Editor")
#define APP_VERSION_STRING QString("0.2")
#define TILE_SIZE 64
#define DATA_HEADER_SIZE 0x3F
#define TILE_MIRROR_FLAG ((char) 0x80)
@ -38,15 +41,16 @@ private:
int selected_item;
QHash<int, QString> tilesetData;
protected slots:
private slots:
void onLoadMap(void);
void onCreateMap(void);
void onProcessMapFile(QByteArray data);
void onProcessMapFile(QByteArray);
void onMapItemClicked(QPointF);
void onNoItemSelected(void);
void onListItemSelected(void);
void onSaveMap(void);
void onShowNumbers(int);
void onAirportNameModified(QString);
};
#endif // MAINWINDOW_H

View File

@ -24,7 +24,7 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="showNumbers_Checkbox">
@ -45,17 +45,7 @@
</item>
</layout>
</item>
<item row="0" column="2">
<widget class="QGraphicsView" name="graphicsView">
<property name="minimumSize">
<size>
<width>640</width>
<height>480</height>
</size>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="CreateMap_Btn">
@ -80,7 +70,17 @@
</item>
</layout>
</item>
<item row="0" column="0">
<item row="1" column="2">
<widget class="QGraphicsView" name="graphicsView">
<property name="minimumSize">
<size>
<width>640</width>
<height>480</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListWidget" name="listWidget">
<property name="maximumSize">
<size>
@ -90,6 +90,24 @@
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Airport name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="airportName_Label">
<property name="maxLength">
<number>18</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">

View File

@ -1,2 +1,2 @@
[app_settings]
last_dir=C:/cygwin/home/Xavier/Airport/Levels/LEVEL2.LVL
last_dir=C:/cygwin/home/Xavier/Airport/Levels/TEST_LEVEL2.LVL

View File

@ -20,7 +20,7 @@
* Defines *
* *************************************/
#define BUTTON_SIZE 64
#define MAIN_MENU_BUTTON_SIZE 64
#define SELECTED_BUTTON_LUMINANCE 0xC0
/* **************************************
@ -168,7 +168,11 @@ static const char* MainMenuFiles[] = { "cdrom:\\DATA\\SPRITES\\MAINMENU.TIM;1" ,
static const char* MainMenuLevelList[] = { [LEVEL1] = "cdrom:\\DATA\\LEVELS\\LEVEL1.LVL;1" ,
[LEVEL2] = "cdrom:\\DATA\\LEVELS\\LEVEL2.LVL;1" };
static const char* MainMenuLevel1Plt[] = {"cdrom:\\DATA\\LEVELS\\LEVEL1.PLT;1", "cdrom:\\DATA\\LEVELS\\EASY.PLT;1", NULL};
static const char* MainMenuLevel1Plt[] = { "cdrom:\\DATA\\LEVELS\\TUTORIA1.PLT;1",
"cdrom:\\DATA\\LEVELS\\LEVEL1.PLT;1",
"cdrom:\\DATA\\LEVELS\\EASY.PLT;1",
NULL};
static const char* MainMenuLevel2Plt[] = {"cdrom:\\DATA\\LEVELS\\LEVEL2.PLT;1", NULL};
static const char** MainMenuPltList[] = {[LEVEL1] = MainMenuLevel1Plt, [LEVEL2] = MainMenuLevel2Plt};
@ -751,8 +755,8 @@ void MainMenuButtonHandler(void)
void MainMenuDrawButton(TYPE_MMBtn * btn)
{
MenuSpr.w = BUTTON_SIZE;
MenuSpr.h = BUTTON_SIZE;
MenuSpr.w = MAIN_MENU_BUTTON_SIZE;
MenuSpr.h = MAIN_MENU_BUTTON_SIZE;
if ( (btn->timer) < (MainMenuBtnAni_sz - 1) )
{

187
Source/Message.c Normal file
View File

@ -0,0 +1,187 @@
/* **************************************
* Includes *
* *************************************/
#include "Message.h"
#include "Gfx.h"
#include "Pad.h"
/* **************************************
* Defines *
* *************************************/
#define NO_MESSAGE ((uint8_t)0xFF)
#define MESSAGE_FIFO_SIZE 16
/* **************************************
* Structs and enums *
* *************************************/
/* **************************************
* Local prototypes *
* *************************************/
/* **************************************
* Local variables *
* *************************************/
static TYPE_MESSAGE_DATA tMessageFIFO[MESSAGE_FIFO_SIZE];
static uint8_t MessageIdx;
void MessageInit(void)
{
bzero(tMessageFIFO, sizeof(tMessageFIFO));
MessageIdx = NO_MESSAGE;
}
bool MessageCreate(TYPE_MESSAGE_DATA* ptrMessage)
{
uint8_t i;
for (i = 0; i < MESSAGE_FIFO_SIZE; i++)
{
TYPE_MESSAGE_DATA* m = &tMessageFIFO[i];
if (m->used == false)
{
memcpy(m, ptrMessage, sizeof(TYPE_MESSAGE_DATA));
m->used = true;
Serial_printf("Successfully allocated message into slot %d.\n", i);
return true;
}
}
Serial_printf("Could not allocate message resource to FIFO.\n");
return false;
}
void MessageHandler(void)
{
uint8_t i;
if (System1SecondTick() != false)
{
for (i = 0; i < MESSAGE_FIFO_SIZE; i++)
{
TYPE_MESSAGE_DATA* ptrMessage = &tMessageFIFO[i];
if (ptrMessage->used != false)
{
if (ptrMessage->Timeout == 0)
{
ptrMessage->used = false;
MessageIdx = i;
}
else
{
ptrMessage->Timeout--;
}
}
}
}
}
void MessageRender(void)
{
if (MessageIdx != NO_MESSAGE)
{
enum
{
MESSAGE_RECT_W = 256,
MESSAGE_RECT_H = 72,
MESSAGE_RECT_X = (X_SCREEN_RESOLUTION - MESSAGE_RECT_W) >> 1,
MESSAGE_RECT_Y = (Y_SCREEN_RESOLUTION - MESSAGE_RECT_H) >> 1,
};
GsGPoly4 messageRect = { .x[0] = MESSAGE_RECT_X,
.x[1] = MESSAGE_RECT_X + MESSAGE_RECT_W,
.x[2] = messageRect.x[0],
.x[3] = messageRect.x[1],
.y[0] = MESSAGE_RECT_Y,
.y[1] = messageRect.y[0],
.y[2] = MESSAGE_RECT_Y + MESSAGE_RECT_H,
.y[3] = messageRect.y[2] ,
.r[0] = 0,
.r[1] = 0,
.r[2] = 0,
.r[3] = 0,
.g[0] = NORMAL_LUMINANCE,
.g[1] = NORMAL_LUMINANCE,
.g[2] = NORMAL_LUMINANCE >> 1,
.g[3] = NORMAL_LUMINANCE >> 1,
.b[0] = NORMAL_LUMINANCE >> 2,
.b[1] = NORMAL_LUMINANCE >> 2,
.b[2] = NORMAL_LUMINANCE >> 3,
.b[3] = NORMAL_LUMINANCE >> 3,
.attribute = 0 };
GsSprite backgroundSpr = {0};
GfxSaveDisplayData(&backgroundSpr);
backgroundSpr.x = 0;
backgroundSpr.y = 0;
do
{
enum
{
MESSAGE_TEXT_X = MESSAGE_RECT_X + 8,
MESSAGE_TEXT_Y = MESSAGE_RECT_Y + 8,
CONTINUE_TEXT_X = MESSAGE_TEXT_X,
CONTINUE_TEXT_Y = MESSAGE_RECT_Y + MESSAGE_RECT_H - 16,
};
char* strMessage = MessageGetString();
GfxSortSprite(&backgroundSpr);
GsSortGPoly4(&messageRect);
if (strMessage != NULL)
{
enum
{
MAX_CH_PER_LINE = 32
};
FontSetFlags(&SmallFont, FONT_WRAP_LINE);
FontSetMaxCharPerLine(&SmallFont, MAX_CH_PER_LINE);
FontPrintText(&SmallFont, MESSAGE_TEXT_X, MESSAGE_TEXT_Y, strMessage);
// Restore default values
FontSetFlags(&SmallFont, FONT_NOFLAGS);
FontSetMaxCharPerLine(&SmallFont, 0);
}
FontPrintText(&SmallFont, CONTINUE_TEXT_X, CONTINUE_TEXT_Y, "Press to continue...");
GfxDrawButton(CONTINUE_TEXT_X + (strlen("Press") << 3) - 4, CONTINUE_TEXT_Y - 4, PAD_CROSS);
GfxDrawScene_Slow();
} while (PadOneKeySinglePress(PAD_CROSS) == false);
MessageIdx = NO_MESSAGE;
}
}
char* MessageGetString(void)
{
if (MessageIdx != NO_MESSAGE)
{
return tMessageFIFO[MessageIdx].strMessage;
}
return NULL;
}

37
Source/Message.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef MESSAGE_HEADER__
#define MESSAGE_HEADER__
/* *************************************
* Includes
* *************************************/
#include "Global_Inc.h"
/* *************************************
* Defines
* *************************************/
#define MAX_MESSAGE_STR_SIZE 256
/* *************************************
* Structs and enums
* *************************************/
typedef struct t_messagedata
{
bool used;
uint32_t Timeout;
char strMessage[MAX_MESSAGE_STR_SIZE];
}TYPE_MESSAGE_DATA;
/* *************************************
* Global prototypes
* *************************************/
void MessageInit(void);
bool MessageCreate(TYPE_MESSAGE_DATA* ptrMessage);
void MessageHandler(void);
void MessageRender(void);
char* MessageGetString(void);
#endif // MESSAGE_HEADER__

View File

@ -5,12 +5,14 @@
#include "PltParser.h"
#include "System.h"
#include "Game.h"
#include "Message.h"
/* *************************************
* Defines
* *************************************/
#define LINE_MAX_CHARACTERS 100
#define LINE_MAX_CHARACTERS MAX_MESSAGE_STR_SIZE
#define MESSAGE_HEADER_STR "MESSAGE"
/* **************************************
* Structs and enums *
@ -28,22 +30,12 @@ static void PltParserResetBuffers(TYPE_FLIGHT_DATA* ptrFlightData);
bool PltParserLoadFile(char* strPath, TYPE_FLIGHT_DATA* ptrFlightData)
{
enum
{
DEPARTURE_ARRIVAL_INDEX = 0,
FLIGHT_NUMBER_INDEX,
PASSENGERS_INDEX,
HOURS_MINUTES_INDEX,
PARKING_INDEX,
REMAINING_TIME_INDEX
};
enum
{
PLT_HOUR_MINUTE_CHARACTERS = 2,
PLT_FIRST_LINE_CHARACTERS = 5,
PLT_COLON_POSITION = 2
};
enum
{
PLT_HOUR_MINUTE_CHARACTERS = 2,
PLT_FIRST_LINE_CHARACTERS = 5,
PLT_COLON_POSITION = 2
};
uint8_t i;
uint8_t j;
@ -138,6 +130,15 @@ bool PltParserLoadFile(char* strPath, TYPE_FLIGHT_DATA* ptrFlightData)
}
else
{
typedef enum t_lineType
{
MESSAGE_INFO,
AIRCRAFT_DATA
}TYPE_LINE;
TYPE_LINE tLine = AIRCRAFT_DATA; // Default value
TYPE_MESSAGE_DATA tMessage = {0};
// File header (initial game time) has already been read
strncpy(lineBuffer, buffer, LINE_MAX_CHARACTERS);
@ -151,6 +152,25 @@ bool PltParserLoadFile(char* strPath, TYPE_FLIGHT_DATA* ptrFlightData)
{
switch(i)
{
enum
{
DEPARTURE_ARRIVAL_INDEX = 0,
FLIGHT_NUMBER_INDEX,
PASSENGERS_INDEX,
HOURS_MINUTES_INDEX,
PARKING_INDEX,
REMAINING_TIME_INDEX
};
enum
{
MESSAGE_HEADER_INDEX = 0,
MESSAGE_TIMEOUT_INDEX,
MESSAGE_STR_INDEX
};
//case MESSAGE_HEADER_INDEX:
// Fall through
case DEPARTURE_ARRIVAL_INDEX:
if (strncmp(lineBufferPtr,"DEPARTURE",strlen("DEPARTURE") ) == 0)
@ -163,21 +183,69 @@ bool PltParserLoadFile(char* strPath, TYPE_FLIGHT_DATA* ptrFlightData)
ptrFlightData->FlightDirection[aircraftIndex] = ARRIVAL;
Serial_printf("Aircraft %d set to ARRIVAL.\n",aircraftIndex);
}
else if (strncmp(lineBufferPtr, MESSAGE_HEADER_STR, strlen(MESSAGE_HEADER_STR) ) == 0)
{
tLine = MESSAGE_INFO;
}
else
{
Serial_printf("Flight direction is not correct!\n");
}
break;
//case MESSAGE_TIMEOUT_INDEX:
// Fall through
case FLIGHT_NUMBER_INDEX:
strncpy(ptrFlightData->strFlightNumber[aircraftIndex],lineBufferPtr,GAME_MAX_CHARACTERS);
ptrFlightData->strFlightNumber[aircraftIndex][GAME_MAX_CHARACTERS - 1] = '\0';
Serial_printf("Aircraft %d flight number set to %s.\n",aircraftIndex,ptrFlightData->strFlightNumber[aircraftIndex]);
if (tLine == MESSAGE_INFO)
{
uint8_t Hours;
uint8_t Minutes;
if ( strlen(lineBufferPtr) != strlen("HH:MM") )
{
Serial_printf("Hour minute format is not correct! Read %s\n", lineBufferPtr);
break;
}
// Copy hour
strHour[0] = lineBufferPtr[0];
strHour[1] = lineBufferPtr[1];
// Copy minutes
strMinutes[0] = lineBufferPtr[3];
strMinutes[1] = lineBufferPtr[4];
Hours = (uint8_t)atoi(strHour);
Minutes = (uint8_t)atoi(strMinutes);
tMessage.Timeout = (uint32_t)(Hours * 60) + Minutes;
Serial_printf("Message timeout: %d seconds.\n", tMessage.Timeout);
}
else
{
strncpy(ptrFlightData->strFlightNumber[aircraftIndex],lineBufferPtr,GAME_MAX_CHARACTERS);
ptrFlightData->strFlightNumber[aircraftIndex][GAME_MAX_CHARACTERS - 1] = '\0';
Serial_printf("Aircraft %d flight number set to %s.\n",aircraftIndex,ptrFlightData->strFlightNumber[aircraftIndex]);
}
break;
// case MESSAGE_STR_INDEX:
// Fall through
case PASSENGERS_INDEX:
ptrFlightData->Passengers[aircraftIndex] = atoi(lineBufferPtr);
Serial_printf("Aircraft %d passengers set to %d.\n",aircraftIndex,ptrFlightData->Passengers[aircraftIndex]);
if (tLine == MESSAGE_INFO)
{
strncpy(tMessage.strMessage, lineBufferPtr, MAX_MESSAGE_STR_SIZE);
MessageCreate(&tMessage);
bzero(&tMessage, sizeof(tMessage));
}
else
{
ptrFlightData->Passengers[aircraftIndex] = atoi(lineBufferPtr);
Serial_printf("Aircraft %d passengers set to %d.\n",aircraftIndex,ptrFlightData->Passengers[aircraftIndex]);
}
break;
case PARKING_INDEX:
@ -210,8 +278,8 @@ bool PltParserLoadFile(char* strPath, TYPE_FLIGHT_DATA* ptrFlightData)
ptrFlightData->Minutes[aircraftIndex] = (uint8_t)atoi(strMinutes);
Serial_printf("Aircraft %d time set to %.2d:%.2d.\n", aircraftIndex,
ptrFlightData->Hours[aircraftIndex],
ptrFlightData->Minutes[aircraftIndex] );
ptrFlightData->Hours[aircraftIndex],
ptrFlightData->Minutes[aircraftIndex] );
break;
case REMAINING_TIME_INDEX:
@ -228,8 +296,11 @@ bool PltParserLoadFile(char* strPath, TYPE_FLIGHT_DATA* ptrFlightData)
i++;
}
ptrFlightData->State[aircraftIndex] = STATE_IDLE;
aircraftIndex++;
if (tLine == AIRCRAFT_DATA)
{
ptrFlightData->State[aircraftIndex] = STATE_IDLE;
aircraftIndex++;
}
}
buffer = strtok_r(NULL,"\n",&pltBufferSavePtr);

View File

@ -104,7 +104,7 @@ void SystemInit(void)
//Set VBlank Handler for screen refresh
SetVBlankHandler(&ISR_SystemDefaultVBlank);
//Set Primitive List
GfxSetPrimitiveList();
GfxSetDefaultPrimitiveList();
// Init memory card
MemCardInit();
//Initial value for system_busy