/* * 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 . * */ /* * 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 "task.h" #include "image.h" #include "font.h" #include "timer.h" #include "gui.h" #include "config.h" #include "runtime.h" #include "welcome.h" PacketThreadDataT *__packetThreadData = NULL; // Exported in os.h RuntimeDataT __runtimeData; // Exported in runtime.h static void taskComDebugLoop(void *data); static void taskGuiEventLoop(void *data); #include "comport.h" static void taskComDebugLoop(void *data) { int32_t r; int32_t x; char buffer[1024]; (void)data; // Open COM port. logWrite("Opening COM\n"); r = comOpen(__configData.serialCom - 1, 57600L, 8, 'n', 1, SER_HANDSHAKING_RTSCTS); if (r != SER_SUCCESS) { logWrite("Unable to open COM port! Please check settings.\n"); guiStop(); return; } // Send a CR to clear anything in the modem. logWrite("Clearing modem buffer\n"); snprintf(buffer, 1023, "%c", 13); comWrite(__configData.serialCom - 1, buffer, strlen(buffer)); // Wait roughly a second for anything. comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "weExpectNothing"); // Send actual init logWrite("Init modem\n"); snprintf(buffer, 1023, "%s%c", "AT+SOCK1", 13); comWrite(__configData.serialCom - 1, buffer, strlen(buffer)); // Wait roughly a second for "OK". r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4, "OK"); if (r <= 0) { comClose(__configData.serialCom - 1); logWrite("Modem does not support ENET! Please check settings.\n"); guiStop(); return; } logWrite("Modem OK\n"); // Flush COM port. timerQuarterSecondsWait(4); comReceiveBufferFlush(__configData.serialCom - 1); // Show dialing, dial service. logWrite("Dialing\n"); snprintf(buffer, 1023, "ATDT%s:%d%c", __configData.serverHost, __configData.serverPort, 13); comWrite(__configData.serialCom - 1, buffer, strlen(buffer)); // Wait 7 seconds for welcome banner. r = comWaitWithTimeout(__configData.serialCom - 1, buffer, 1023, 4 * 7, "KPMPGSMKII\r"); if (r <= 0) { comClose(__configData.serialCom - 1); logWrite("Unable to connect to server! Please check settings or try later.\n"); guiStop(); return; } // Connected! Show icon and negotiate session. logWrite("Connected\n"); packetEncryptionSetup(__packetThreadData); PacketEncodeDataT encoded = { 0 }; PacketDecodeDataT decoded = { 0 }; // Send it 10 times, waiting for a PONG between each. for (x=0; x<10; x++) { // Send PING. logWrite("Sending PING %d\n", x); encoded.control = PACKET_CONTROL_DAT; encoded.packetType = PACKET_TYPE_PING; encoded.channel = 1; encoded.encrypt = 0; packetEncode(__packetThreadData, &encoded, NULL, 0); // Must encode each packet - no reusing encoded data. packetSend(__packetThreadData, &encoded); // Wait for PONG. while (!guiHasStopped()) { r = comRead(__configData.serialCom - 1, buffer, 1); if (r == 1) { if (packetDecode(__packetThreadData, &decoded, buffer, 1)) { if (decoded.packetType == PACKET_TYPE_PONG) { logWrite("Received PONG\n"); break; } else { logWrite("Unexpected packet type received %d\n", decoded.packetType); } } } else { taskYield(); } } } if (guiHasStopped()) return; // Send LOGIN. logWrite("Sending LOGIN\n"); PacketTypeLoginT loginData; strcpy(loginData.user, "Encryption"); strcpy(loginData.pass, "Works!"); encoded.control = PACKET_CONTROL_DAT; encoded.packetType = PACKET_TYPE_LOGIN; encoded.channel = 1; encoded.encrypt = 1; packetEncode(__packetThreadData, &encoded, (char *)&loginData, sizeof(PacketTypeLoginT)); // Must encode each packet - no reusing encoded data. packetSend(__packetThreadData, &encoded); // Send CLIENT_SHUTDOWN. logWrite("Sending CLIENT_SHUTDOWN\n"); encoded.control = PACKET_CONTROL_DAT; encoded.packetType = PACKET_TYPE_CLIENT_SHUTDOWN; encoded.channel = 1; encoded.encrypt = 0; packetEncode(__packetThreadData, &encoded, NULL, 0); packetSend(__packetThreadData, &encoded); logWrite("Sleeping\n"); timerQuarterSecondsWait(8); logWrite("COM closed\n"); comClose(__configData.serialCom - 1); guiStop(); } static void taskGuiEventLoop(void *data) { MouseT *mouse = NULL; ImageT *pointer = NULL; ColorT alpha = { 0 }; (void)data; pointer = imageLoad("data/mouse.png"); alpha = imagePixelGet(pointer, 5, 0); do { timerUpdate(); 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(); taskYield(); } while (!guiHasStopped()); imageUnload(&pointer); } int main(int argc, char *argv[]) { #ifndef __linux__ // On DOS, display the contets of the log now that we're back in text mode. char *logName = NULL; FILE *in = NULL; #endif memoryStartup(argv[0]); logOpenByHandle(memoryLogHandleGet()); configStartup(argv[0]); // 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 0; } } // Do we have the video mode they asked for? if (vbeStartup(__configData.videoWidth, __configData.videoHeight, __configData.videoDepth)) { configShutdown(); logClose(); memoryShutdown(); return 1; } surfaceStartup(); mouseStartup(); timerStartup(); guiStartup(); taskStartup(); __packetThreadData = packetThreadDataCreate(NULL); packetSenderRegister(comPacketSender); //taskCreate(taskComDebugLoop, NULL); taskCreate(taskWelcome, NULL); taskCreate(taskGuiEventLoop, NULL); taskRun(); packetThreadDataDestroy(&__packetThreadData); taskShutdown(); guiShutdown(); timerShutdown(); mouseShutdown(); surfaceShutdown(); vbeShutdown(); configShutdown(); 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. logName = utilAppNameWithNewExtensionGet(argv[0], "log"); in = fopen(logName, "r"); if (in) { while (!feof(in)) { putc(fgetc(in), stdout); } fclose(in); free(in); } free(logName); _Exit(0); #endif return 0; }