From: Constantin Date: Sun, 5 May 2013 09:53:45 +0000 (+0200) Subject: initial release, dirtyest code but works X-Git-Url: https://git.ralfj.de/multypo.git/commitdiff_plain/93e7259309717671bbaccf24b67bb0d49206f465?hp=4914498e271bd0fc1c678602001b1a6977bb5775 initial release, dirtyest code but works --- diff --git a/game.cpp b/game.cpp new file mode 100644 index 0000000..6611999 --- /dev/null +++ b/game.cpp @@ -0,0 +1,357 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Renderable { +public: + virtual void render (Display*, Window&, GC&) = 0; +}; + +class TextRenderable : public Renderable { +public: + int x, y; // position + int color; // text color + std::string text; // what to render + //bool centered; // render centered // TODO + + TextRenderable (int posx, int posy, int textcolor, const char * message) + : x(posx), y(posy), color(textcolor), text(message) {} + + virtual void render (Display * dpy, Window & w, GC & gc) { + XSetForeground(dpy, gc, color); + XDrawString(dpy, w, gc, x, y, text.c_str(), text.length()); + } +}; + +class Player { +private: + std::string name; + bool isReady; + TextRenderable * textField; + int indexToType; + int score; + +public: + Player () : name(), isReady(false), indexToType(0), score(0) {} + int getScore () { + return score; + } + void associateTextField (TextRenderable * t) { + textField = t; + } + void nameInput (const char * input) { + if (isReady) + return; + if (strlen(input) == 1) { + textField->text.append(input); + } else if (strcmp (input, "Return") == 0) { + name = textField->text; + isReady = true; + textField->text.append(" READY"); + } else if (strcmp (input, "BackSpace") == 0 && name.length() > 0) { + textField->text.erase (textField->text.length()-1); + } + } + // returns if player has just finished the word + bool input (const char * input, const std::string & currentWord) { + if (strlen(input) == 1 && currentWord[indexToType] == input[0] && !isReady) { + assert (textField != NULL); + assert (indexToType >= 0); + textField->text.push_back(input[0]); + indexToType++; + if (currentWord.length() == (unsigned int)indexToType) { // done + indexToType = 0; + textField->text.erase(); + isReady = true; + return true; + } + } + return false; + } + void clearText () { + textField->text.erase(); + indexToType = 0; + } + void addScore (int toAdd) { + assert (toAdd >= 0); + score += toAdd; + } + void unsetReady () { + isReady = false; + } + bool getReady () { + return isReady; + } + const char * getName () { + return name.c_str(); + } +}; + +void clearScreen (Display *d, Window& window, GC& gc, int color) { + XSetForeground (d, gc, color); + unsigned int width,height; // TODO: nicht jedes mal die query machen + unsigned int dummyu; int dummyi; Window dummyw; + XGetGeometry(d, window, &dummyw, &dummyi, &dummyi, &width, &height, &dummyu, &dummyu); + XFillRectangle (d, window, gc, 0, 0, width, height); +} + +void render (Display *d, Window& window, GC& gc, int bgcolor, std::vector < Renderable* > & toRender) { + clearScreen (d, window, gc, bgcolor); + for (size_t i=0; irender(d, window, gc); + } + XFlush (d); +} + +int getColorExact (Display *d, int r, int g, int b) { + int screen = DefaultScreen(d); + Colormap cmap = DefaultColormap(d,screen); + + if (r > 65535) r = 65535; + if (g > 65535) g = 65535; + if (b > 65535) b = 65535; + + XColor c; + c.red = r; c.green = g; c.blue = b; + + if (XAllocColor(d, cmap, &c)) { + if (c.red != r || c.green != g || c.blue != b) { + fprintf (stderr, "(%d,%d,%d) -> (%d,%d,%d)\n", r, g, b, c.red, c.green, c.blue); + } + return c.pixel; + } else { + fprintf (stderr, "Warning: couldn't allocate color %d %d %d\n", r, g, b); + return BlackPixel(d,screen); + } +} + +int getColor (Display *d, int r, int g, int b) { + // 0->0, 255->65535 + return getColorExact (d, r*257, g*257, b*257); +} + +std::string getNextWord (bool * isWord_return) { + std::string ret; + std::getline (std::cin, ret); + *isWord_return = !std::cin.eof(); + return ret; +} + +int main (int argc, char** argv) { + /* Connect to the X server */ + Display *dpy = XOpenDisplay(NULL); + if (!dpy) { + fprintf (stderr, "XOpenDisplay returned no display to display what is to display. Aborting.\n"); + exit (1); + } + + /* XInput Extension available? */ + int opcode, event, error; + if (!XQueryExtension(dpy, "XInputExtension", &opcode, &event, &error)) { + printf("X Input extension not available.\n"); + return -1; + } + + /* Which version of XI2? We support 2.0 */ + int major = 2, minor = 0; + if (XIQueryVersion(dpy, &major, &minor) == BadRequest) { + printf("XI2 not available. Server supports %d.%d\n", major, minor); + return -1; + } + + printf ("system is sane.\n"); + + // Get some colors + int blackColor = BlackPixel(dpy, DefaultScreen(dpy)); + int whiteColor = WhitePixel(dpy, DefaultScreen(dpy)); + + int nplayers=0; + int maxplayers=4; + TextRenderable playerTextFields [] = { + TextRenderable(0, 200, getColor (dpy, 255, 220, 32), ""), + TextRenderable(0, 300, getColor (dpy, 32, 128, 255), ""), + TextRenderable(0, 400, getColor (dpy, 64, 255, 0), ""), + TextRenderable(0, 500, getColor (dpy, 255, 0, 64), "") + }; + + // create window + Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 800, 600, 0, blackColor, blackColor); + + // which events we want? + XSelectInput(dpy, w, StructureNotifyMask); + + // put window on the screen + XMapWindow(dpy, w); + + // create graphics context + GC gc = XCreateGC(dpy, w, 0, NULL); + + // wait for MapNotify + while (true) { + XEvent e; + XNextEvent(dpy, &e); + if (e.type == MapNotify) + break; + } + + // Now let's listen to keypress events + XIEventMask eventmask; + unsigned char mask [1] = { 0 }; // will change + eventmask.deviceid = XIAllMasterDevices; + eventmask.mask_len = sizeof (mask); // in bytes, for whatever reason... + eventmask.mask = mask; + XISetMask(mask, XI_KeyPress); + XISelectEvents (dpy, w, &eventmask, 1); + XSelectInput (dpy, w, ExposureMask); + + // setup player data structures + std::map < int , Player* > kbd2player; + std::vector< Player* > players; + + // setup rendering stuff + std::vector< Renderable* > toRender; + for (int i = 0; i < maxplayers; i++) + toRender.push_back (playerTextFields+i); + TextRenderable mainTextField (50, 50, whiteColor, "Please type your name and then hit Return."); + toRender.push_back (&mainTextField); + + bool allReady = false; + while (!allReady) { + render(dpy, w, gc, blackColor, toRender); + XEvent ev; + XNextEvent(dpy, &ev); + if (ev.xcookie.type == GenericEvent && ev.xcookie.extension == opcode + && ev.xcookie.evtype == XI_KeyPress && XGetEventData(dpy, &ev.xcookie)) { + XIDeviceEvent *d_ev = (XIDeviceEvent*) ev.xcookie.data; + KeyCode keycode = d_ev->detail; + int kbdid = d_ev->deviceid; + if (!(d_ev->flags & XIKeyRepeat)) { + int keysyms_per_keycode; + //KeySym *keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode); + KeySym keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode)[0]; + Player * eventPlayer; + if (kbd2player.count(kbdid) == 0) { // add player + if (nplayers == maxplayers) { + fprintf (stderr, "zu viele Spieler, TODO: gescheites error handling. Bye ;-)\n"); + exit (1); + } + eventPlayer = new Player (); + eventPlayer->associateTextField (playerTextFields+nplayers); + nplayers++; + players.push_back(eventPlayer); + kbd2player[kbdid] = eventPlayer; + } else { // player already there + eventPlayer = kbd2player[kbdid]; + } + //debug out: mainTextField.text.append (XKeysymToString (keysym[0])); + eventPlayer->nameInput (XKeysymToString (keysym)); + } + + XFreeEventData(dpy, &ev.xcookie); + if (keycode == 9) {// Escape Key + printf ("you escaped successfully.\n"); + exit(0); + } + } else if (ev.type == Expose) { + printf ("exposeevent\n"); + } else { + printf ("other event\n"); + //printf ("else\n"); + } + if (!players.empty()) { + allReady = true; + for (size_t i=0; igetReady(); + } + } + } + + for (size_t i=0; iclearText(); + players[i]->unsetReady(); + } // readyflag will now be used for if they are already done with a word + + int notreadyplayers = 0; + std::string theWord; + + while (true) { + assert (notreadyplayers >= 0); + if (notreadyplayers == 0 || (notreadyplayers==1 && players.size()>1)) { + bool gotWord; + theWord = getNextWord(&gotWord); + if (!gotWord) + break; + mainTextField.text = theWord; + notreadyplayers = players.size(); + for (size_t i=0; iunsetReady(); + players[i]->clearText(); + printf ("cleared text\n"); + } + } + render(dpy, w, gc, blackColor, toRender); + XEvent ev; + XNextEvent(dpy, &ev); + if (ev.xcookie.type == GenericEvent && ev.xcookie.extension == opcode + && ev.xcookie.evtype == XI_KeyPress && XGetEventData(dpy, &ev.xcookie)) { + XIDeviceEvent *d_ev = (XIDeviceEvent*) ev.xcookie.data; + KeyCode keycode = d_ev->detail; + int kbdid = d_ev->deviceid; + if (!(d_ev->flags & XIKeyRepeat)) { + printf ("got key event\n"); + int keysyms_per_keycode; + //KeySym *keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode); + KeySym keysym = XGetKeyboardMapping (dpy, keycode, 1, &keysyms_per_keycode)[0]; + Player * eventPlayer; + if (kbd2player.count(kbdid) == 0) { // add player + printf ("you can't join in a match\n"); + exit (1); + /*if (nplayers == maxplayers) { + fprintf (stderr, "zu viele Spieler, TODO: gescheites error handling. Bye ;-)\n"); + exit (1); + } + eventPlayer = new Player (); + eventPlayer->associateTextField (playerTextFields+nplayers); + nplayers++; + players.push_back(eventPlayer); + kbd2player[srcid] = eventPlayer; */ + } else { // player already there + eventPlayer = kbd2player[kbdid]; + } + //debug out: mainTextField.text.append (XKeysymToString (keysym[0])); + bool pfinished = eventPlayer->input (XKeysymToString (keysym), theWord); + if (pfinished) { + notreadyplayers--; + eventPlayer->addScore (notreadyplayers); + printf ("score of %d added\n", notreadyplayers); + } + } + + XFreeEventData(dpy, &ev.xcookie); + if (keycode == 9) {// Escape Key + printf ("you escaped successfully.\n"); + exit(0); + } + } else if (ev.type == Expose) { + printf ("exposeevent\n"); + } else { + printf ("other event\n"); + //printf ("else\n"); + } + } + + //sleep(10); + + return 0; +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..b0a5267 --- /dev/null +++ b/makefile @@ -0,0 +1,4 @@ + +game: game.cpp + g++ -g -Wall -o game game.cpp -lX11 -lXi + diff --git a/play.sh b/play.sh new file mode 100755 index 0000000..7b22b59 --- /dev/null +++ b/play.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cat words.txt | ./game + diff --git a/words.txt b/words.txt new file mode 100644 index 0000000..916333c --- /dev/null +++ b/words.txt @@ -0,0 +1,4 @@ +garden +tree +dddddddddddddddddddddddddd +chamber