non-exclusive instadrop and soft drop
[netris.git] / client.c
index bd12f8ec913146649ee64d42efe6ff65f0d05e10..788684cf0282be3be353b3c9dc90adc0d025907c 100644 (file)
--- a/client.c
+++ b/client.c
@@ -21,6 +21,7 @@
 #include "netris.h"
 
 #include <stdlib.h>
+#include <stdbool.h>
 #include <ctype.h>
 #include <string.h>
 #include <sys/types.h>
@@ -51,12 +52,12 @@ static struct option options[] = {
 };
 
 enum {
-       KT_left, KT_right, KT_rotright, KT_rotleft, KT_drop, KT_down,
+       KT_left, KT_right, KT_rotright, KT_rotleft, KT_drop, KT_dropsoft, KT_down,
        KT_faster, KT_pause, KT_redraw, KT_say, KT_quit, KT_numKeys
 };
 
 static char *keyNames[KT_numKeys+1] = {
-       "Left", "Right", "RotRight", "RotLeft", "Drop", "Down",
+       "Left", "Right", "RotRight", "RotLeft", "Drop", "DropSoft", "Down",
        "Faster", "Pause", "Redraw", "Say", "Quit", NULL
 };
 
@@ -64,6 +65,14 @@ _Sets Sets = {7, 0, 1, 1, 1};
 
 static char keyTable[KT_numKeys+1];
 
+enum {
+       CT_quit, CT_pause,
+       CT_MAX
+};
+static char *cmds[] = {
+       "quit", "pause"
+};
+
 static char *hostStr;
 static int paused = 0;
 static char lastadd;
@@ -105,20 +114,6 @@ void MapKeys(char *newKeys)
                exit(1);
 }
 
-void WriteConf(void)
-{
-       FILE *file_out;
-
-       file_out = fopen(CONFIG_FILE, "w");
-       if (file_out == NULL)
-               die("Error writing config file");
-
-       fprintf(file_out, "### NETRIS %s Config file ###\n\n", version_string);
-
-       fclose(file_out);
-       fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
-}
-
 void Usage(void)
 {
        Header();
@@ -311,7 +306,7 @@ void CheckClears(int scr)
                Players[scr].score.score += Game.gravity
                        ? linevaluesq[linesCleared - 1] : linevalues[linesCleared - 1];
                Players[scr].score.lines += linesCleared;
-               Players[scr].score.adds += linesCleared - (linesCleared < 4);
+               Players[scr].score.adds += linesCleared - (linesCleared < 4); //XXX match handicap
                if (scr == me) {
                        if (game == GT_classicTwo) {
                                SendPacket(scr, NP_clear, 0, NULL);
@@ -338,10 +333,71 @@ void OneGame(void)
 {
        int changed = 0;
        short gameStatus = 2; //2=loop; 1=new piece; 0=quit
-       int dropMode = 0;
        int chatMode = 0;
        char chatText[MSG_WIDTH] = "\0";
 
+       void handle_cmd(char cmd, char *arg)
+       {
+               switch (cmd) {
+               case CT_quit:
+                       ShowPause(me);
+                       refresh();
+                       gameStatus = 0;
+                       return;
+               case CT_pause:
+                       if (Players[me].alive <= 0) return;
+                       Players[me].flags ^= SCF_paused;
+                       if (Game.started > 1)
+                               Message(Players[me].flags & SCF_paused
+                                       ? "You paused the game" : "You unpaused the game");
+                       else
+                               Message(Players[me].flags & SCF_paused
+                                       ? "You are not ready" : "You are ready");
+                       checkPaused();
+                       if (game == GT_classicTwo)
+                               SendPacket(me, NP_pause, 0, NULL);
+                       ShowPause(me);
+                       changed = 1;
+                       return;
+               }
+       }
+
+       void handle_cmdstr(char *cmd)
+       {
+               char tag[17], value[81];
+               char *cmdend;
+               int i;
+
+               if ((cmdend = strchr(cmd, ' '))) {
+                       *cmdend = 0;
+               } else {
+                       cmdend = cmd + strlen(cmd); // whole string
+               }
+               for (i = 0; i < CT_MAX; i++){
+                       if (!strcasecmp(cmds[i], cmd)) {
+                               return handle_cmd(i, cmdend + 1);
+                       }
+               }
+               Message("Unknown command /%s", cmd);
+       }
+
+       void handle_str(char *str)
+       {
+               if (chatText[0] == '/') {
+                       if (chatText[1] != '/') {
+                               handle_cmdstr(chatText + 1);
+                               return;
+                       }
+                       memmove(chatText, chatText + 1, strlen(chatText));
+               }
+
+               Message("<\\%d%s\\7> %s",
+                       Players[me].team > 7 ? 7 : Players[me].team,
+                       Players[me].name, chatText);
+               if (game == GT_classicTwo)
+                       SendPacket(me, NP_msg, strlen(chatText) + 1, chatText);
+       }
+
        void GameKey(char key)
        {
                char *p;
@@ -351,11 +407,7 @@ void OneGame(void)
                                // enter text
                                chatMode = 0;
                                if (chatText[0]) {
-                                       Message("<\\%d%s\\7> %s",
-                                               Players[me].team > 7 ? 7 : Players[me].team,
-                                               Players[me].name, chatText);
-                                       if (game == GT_classicTwo)
-                                               SendPacket(me, NP_msg, strlen(chatText) + 1, chatText);
+                                       handle_str(chatText);
                                        memset(chatText, 0, sizeof(chatText));
                                } //say it
                                else Messagetype(27, -1, NULL); //escape
@@ -374,45 +426,33 @@ void OneGame(void)
                if (!(p = strchr(keyTable, tolower(key)))) return;
                key = p - keyTable;
 
-               // global actions (always possible, even if not playing)
+       bool handle_key(char key)
+       {
                switch (key) {
                case KT_redraw:
                        clear();
                        InitFields();
 //                     ScheduleFullRedraw();
                        refresh();
-                       return;
+                       return 1;
                case KT_say:
                        chatMode = 1;
                        Messagetype(key, strlen(chatText) - 1, chatText);
-                       return;
+                       return 1;
                case KT_quit:
-                       ShowPause(me);
-                       refresh();
-                       gameStatus = 0;
-                       return;
-               }
-
-               if (Players[me].alive <= 0) return;
-               // actions available while in game
-               switch (key) {
+                       handle_cmd(CT_quit, NULL);
+                       return 1;
                case KT_pause:
-                       Players[me].flags ^= SCF_paused;
-                       if (Game.started > 1)
-                               Message(Players[me].flags & SCF_paused
-                                       ? "You paused the game" : "You unpaused the game");
-                       else
-                               Message(Players[me].flags & SCF_paused
-                                       ? "You are not ready" : "You are ready");
-                       checkPaused();
-                       if (game == GT_classicTwo)
-                               SendPacket(me, NP_pause, 0, NULL);
-                       ShowPause(me);
-                       changed = 1;
-                       return;
+                       handle_cmd(CT_pause, NULL);
+                       return 1;
+               default:
+                       return 0;
                }
+       }
+               // global actions (always possible, even if not playing)
+               if (handle_key(key)) return;
 
-               if (paused) return;
+               if (Players[me].alive <= 0 || paused) return;
                // actions only available while actually playing
                switch (key) {
                case KT_left:
@@ -435,14 +475,19 @@ void OneGame(void)
                        else
                                gameStatus = 1; //completely dropped
                        break;
-               case KT_drop:
+               case KT_dropsoft:
                        SetITimer(Game.speed, Game.speed);
                        if (DropPiece(me)) {
                                if (spied) SendPacket(me, NP_drop, 0, NULL);
-                               if (!Sets.dropmode) gameStatus = 1; //instadrop
                        }
                        else gameStatus = 1; //dropped
-                       dropMode = Sets.dropmode > 1;
+                       break;
+               case KT_drop:
+                       SetITimer(Game.speed, Game.speed);
+                       if (DropPiece(me)) {
+                               if (spied) SendPacket(me, NP_drop, 0, NULL);
+                       }
+                       gameStatus = 1; // drop
                        break;
                case KT_faster:
                        if (game != GT_onePlayer) break;
@@ -454,11 +499,6 @@ void OneGame(void)
                        changed = 1;
                        break;
                }
-
-               if (dropMode && DropPiece(me) > 0) {
-                       SetITimer(Game.speed, Game.speed);
-                       if (spied) SendPacket(me, NP_drop, 0, NULL);
-               }
                return;
        } //GameKey
 
@@ -729,7 +769,6 @@ GameLoop:
                                oldPaused = paused;
                        } //(un)pause
                } //game loop
-               dropMode = 0;
                Players[me].score.score++;
                CheckClears(me);
        } //new piece loop