kpmpgsmkii/client/src/main.c
2022-03-05 19:06:31 -06:00

313 lines
7.7 KiB
C

/*
* Kangaroo Punch MultiPlayer Game Server Mark II
* Copyright (C) 2020-2021 Scott Duensing
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/*
* To Do:
*
* - Replace any direct data manipulation from outside a class with methods to handle it
* - More widget states: Ghosted (underway)
* - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well
* - Metrics, colors, etc. should be defined in each widget and not in GUI
* - Widgets should support a "changed" callback that can cancel the change
* - Use LabelT in all widgets that have a label
* - Find a light grey to replace white widget data areas
* - No thumb in listbox scrollbar
* - Layout container widgets!
* - Fix variable names. something = local; _something = file global; __something = project global
*/
#include "stddclmr.h"
#include "os.h"
#include "vesa.h"
#include "surface.h"
#include "mouse.h"
#include "keyboard.h"
#include "image.h"
#include "font.h"
#include "gui.h"
#include "config.h"
#include "runtime.h"
#include "comport.h"
#include "network.h"
#include "timer.h"
#include "welcome.h"
#include "settings.h"
PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h
RuntimeDataT __runtimeData; // Exported in runtime.h
static MouseT *_mouse = NULL;
static ImageT *_pointer = NULL;
static ColorT _alpha = 0;
#ifndef __linux__
char *_logName = NULL;
#endif
static void checkSettings(void);
static void eventLoop(void);
static uint8_t hasValidSettings(void);
static void shutdown(void);
static uint8_t startup(int argc, char *argv[]);
static void tableLoad(void);
static void tableSave(void);
static void checkSettings(void) {
// Do we have a valid COM port?
if (!hasValidSettings()) {
logWrite("No compatible modem found. Cannot continue.\n");
guiStop();
return;
}
welcomeShow();
eventLoop();
}
static void eventLoop(void) {
// Main Event Loop.
do {
netProcess();
guiTimerProcess(rawclock());
_mouse = mouseRead();
if (keyHit()) {
guiKeyboardProcess(keyASCIIGet(), keyExtendedGet(), keyScanCodeGet(), keyShiftGet(), keyControlGet(), keyAltGet());
//logWrite("Key '%d' Extended '%d' Scancode '%d' Shift '%d' Control '%d' Alt '%d'\n", keyASCIIGet(), keyExtended(), keyScanCode(), keyShift(), keyControl(), keyAlt());
if (keyASCIIGet() == 27) guiStop();
}
guiMouseProcess(_mouse);
guiComposite();
imageRenderWithAlpha(_pointer, _mouse->x, _mouse->y, _alpha);
vbeVBlankWait();
vbePresent();
} while (!guiHasStopped());
shutdown();
}
static uint8_t hasValidSettings(void) {
// Returning false sends us immediately to the settings dialog.
return (__configData.serialCom > 0 && __configData.serialCom < 5);
}
static void shutdown(void) {
#ifndef __linux__
// On DOS, display the contets of the log now that we're back in text mode.
FILE *in = NULL;
#endif
imageUnload(&_pointer);
tableSave();
netShutdown();
guiShutdown();
mouseShutdown();
surfaceShutdown();
vbeShutdown();
cacheShutdown();
configShutdown();
osShutdown();
logClose();
memoryShutdown();
#ifndef __linux__
//***TODO*** Why the frack does this not work?!
textmode(C80);
// On DOS, display the contets of the log now that we're back in text mode.
in = fopen(_logName, "r");
if (in) {
while (!feof(in)) {
putc(fgetc(in), stdout);
}
fclose(in);
free(in);
}
free(_logName);
_Exit(0);
#endif
}
static uint8_t startup(int argc, char *argv[]) {
memoryStartup(argv[0]);
logOpenByHandle(memoryLogHandleGet());
osStartup();
configStartup(argv[0]);
#ifndef __linux__
_logName = utilAppNameWithNewExtensionGet(argv[0], "log");
#endif
// 0 1 2 3 4 5 6 7 8
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890
logWrite("%s", "Kangaroo Punch MultiPlayer DOS Game Client Mark II\n");
logWrite("%s", "Copyright (C) 2020-2021 Scott Duensing scott@kangaroopunch.com\n\n");
if (argc > 1) {
if (strcmp(argv[1], "/?") == 0) {
vbeInfoShow();
configShutdown();
logClose();
memoryShutdown();
return 1;
}
}
// Do we have the video mode they asked for?
if (vbeStartup(__configData.videoWidth, __configData.videoHeight, __configData.videoDepth)) {
configShutdown();
logClose();
memoryShutdown();
return 1;
}
cacheStartup(argv[0]);
surfaceStartup();
mouseStartup();
guiStartup();
netStartup();
_pointer = imageLoad(cacheFilenameGet("gui:mouse.png"));
_alpha = imagePixelGet(_pointer, 5, 0);
tableLoad();
return 0;
}
static void tableLoad(void) {
FILE *cache = NULL;
char *line = NULL;
char *p = NULL;
char *temp = NULL;
__runtimeData.integers = NULL;
__runtimeData.strings = NULL;
__runtimeData.protocolVersion = 0;
sh_new_strdup(__runtimeData.integers);
sh_new_strdup(__runtimeData.strings);
// ***TODO*** Default initial tables
line = (char *)malloc(4096);
if (line) {
// Load string cache.
cache = cacheFOpen("data:strings.dat", "rt");
if (cache) {
while (fscanf(cache, "%s\n", line) != EOF) {
p = strstr(line, "=");
if (p) {
*p = 0;
p++;
// Do we have this string already?
temp = shget(__runtimeData.strings, line);
if (temp) {
DEL(temp);
shdel(__runtimeData.strings, line);
}
shput(__runtimeData.strings, line, strdup(p));
}
}
cacheFClose(cache);
}
// Load integer cache.
cache = cacheFOpen("data:integers.dat", "rt");
if (cache) {
while (fscanf(cache, "%s\n", line) != EOF) {
p = strstr(line, "=");
if (p) {
*p = 0;
p++;
shput(__runtimeData.integers, line, atol(p));
}
}
cacheFClose(cache);
}
free(line);
line = NULL;
}
}
static void tableSave(void) {
FILE *cache = NULL;
// Save & free integer table.
cache = cacheFOpen("data:integers.dat", "wt");
if (cache) {
if (__runtimeData.integers) {
while (shlen(__runtimeData.integers) > 0) {
//logWrite("[%s]=[%d]\n", __runtimeData.integers[0].key, __runtimeData.integers[0].value);
fprintf(cache, "%s=%ld\n", __runtimeData.integers[0].key, (long)__runtimeData.integers[0].value);
shdel(__runtimeData.integers, __runtimeData.integers[0].key);
}
shfree(__runtimeData.integers);
}
cacheFClose(cache);
}
// Save & free string table.
cache = cacheFOpen("data:strings.dat", "wt");
if (cache) {
if (__runtimeData.strings) {
while (shlen(__runtimeData.strings) > 0) {
//logWrite("[%s]=[%s]\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
fprintf(cache, "%s=%s\n", __runtimeData.strings[0].key, __runtimeData.strings[0].value);
DEL(__runtimeData.strings[0].value);
shdel(__runtimeData.strings, __runtimeData.strings[0].key);
}
shfree(__runtimeData.strings);
}
cacheFClose(cache);
}
}
extern void browserShow(void);
int main(int argc, char *argv[]) {
if (startup(argc, argv)) return 1;
// Perform "first run" setup tasks or start the client?
if (hasValidSettings()) {
// We have what we need, start the client.
//welcomeShow();
browserShow();
eventLoop();
} else {
// Run the setup.
settingsShow(checkSettings);
}
return 0;
}