OSDN Git Service

[Refactor] #37353 コメント整理。 / Refactor comments.
[hengband/hengband.git] / src / chuukei.c
index a2d9034..840e038 100644 (file)
@@ -1,13 +1,21 @@
-/* chuukei.c */
+/*!
+    @file chuukei.c
+    @brief 中継機能の実装
+    @date 2014/01/02
+    @author
+    2014 Deskull rearranged comment for Doxygen.
+ */
 
 #include "angband.h"
 
-#ifdef CHUUKEI
-
 #include <stdio.h>
 #include <stdarg.h>
 #include <ctype.h>
+#ifdef WINDOWS
+#include <windows.h>
+#endif
 
+#ifdef CHUUKEI
 #if defined(WINDOWS)
 #include <winsock.h>
 #elif defined(MACINTOSH)
 #endif
 
 #define MAX_HOSTNAME 256
-#define RINGBUF_SIZE 65536*8
-#define FRESH_QUEUE_SIZE 1024
-#define WAIT 100*1000 /* ¥Ö¥é¥¦¥ºÂ¦¤Î¥¦¥¨¥¤¥È(usñ°Ì) */
+#endif
+
+#define RINGBUF_SIZE 1024*1024
+#define FRESH_QUEUE_SIZE 4096
+#ifdef WINDOWS
+#define WAIT 100
+#else
+#define WAIT 100*1000 /* ブラウズ側のウエイト(us単位) */
+#endif
 #define DEFAULT_DELAY 50
+#define RECVBUF_SIZE 1024
 
-static int sd; /* ¥½¥±¥Ã¥È¤Î¥Õ¥¡¥¤¥ë¥Ç¥£¥¹¥¯¥ê¥×¥¿ */
-static long epoch_time;  /* ³«»Ï»þ¹ï */
-static long time_diff;   /* ¥×¥ì¥¤Â¦¤È¤Î»þ´Ö¤Î¤º¤ì(¤³¤ì¤ò¸«¤Ê¤¬¤é¥Ç¥£¥ì¥¤¤òÄ´À°¤·¤Æ¤¤¤¯) */
-static int browse_delay; /* É½¼¨¤¹¤ë¤Þ¤Ç¤Î»þ´Ö(100msñ°Ì)(¤³¤Î´Ö¤Ë¥é¥°¤òµÛ¼ý¤¹¤ë) */
+static long epoch_time;  /* バッファ開始時刻 */
+static int browse_delay; /* 表示するまでの時間(100ms単位)(この間にラグを吸収する) */
+#ifdef CHUUKEI
+static int sd; /* ソケットのファイルディスクリプタ */
+static long time_diff;   /* プレイ側との時間のずれ(これを見ながらディレイを調整していく) */
 static int server_port;
-static char server_name[MAX_HOSTNAME];
+static GAME_TEXT server_name[MAX_HOSTNAME];
+#endif
 
+static int movie_fd;
+static int movie_mode;
 
+#ifdef CHUUKEI
 #ifdef WINDOWS
 #define close closesocket
 #endif
@@ -47,8 +67,8 @@ static char server_name[MAX_HOSTNAME];
 static InetSvcRef inet_services = nil;
 static EndpointRef ep                  = kOTInvalidEndpointRef;
 #endif
-
-/* ÉÁ²è¤¹¤ë»þ¹ï¤ò³Ð¤¨¤Æ¤ª¤¯¥­¥å¡¼¹½Â¤ÂΠ*/
+#endif
+/* 描画する時刻を覚えておくキュー構造体 */
 static struct
 {
        int time[FRESH_QUEUE_SIZE];
@@ -57,7 +77,7 @@ static struct
 }fresh_queue;
 
 
-/* ¥ê¥ó¥°¥Ð¥Ã¥Õ¥¡¹½Â¤ÂΠ*/
+/* リングバッファ構造体 */
 static struct
 {
        char *buf;
@@ -77,8 +97,30 @@ int recv(int s, char *buffer, size_t buflen, int flags)
 }
 #endif
 
-/* ANSI C¤Ë¤è¤ì¤ÐstaticÊÑ¿ô¤Ï0¤Ç½é´ü²½¤µ¤ì¤ë¤¬°ì±þ½é´ü²½¤¹¤ë */
-static errr init_chuukei(void)
+/*
+ * Original hooks
+ */
+static errr (*old_xtra_hook)(int n, int v);
+static errr (*old_curs_hook)(int x, int y);
+static errr (*old_bigcurs_hook)(int x, int y);
+static errr (*old_wipe_hook)(int x, int y, int n);
+static errr (*old_text_hook)(int x, int y, int n, TERM_COLOR a, concptr s);
+
+static void disable_chuukei_server(void)
+{
+       term *t = angband_term[0];
+#ifdef CHUUKEI
+       chuukei_server = FALSE;
+#endif /* CHUUKEI */
+       t->xtra_hook = old_xtra_hook;
+       t->curs_hook = old_curs_hook;
+       t->bigcurs_hook = old_bigcurs_hook;
+       t->wipe_hook = old_wipe_hook;
+       t->text_hook = old_text_hook;
+}
+
+/* ANSI Cによればstatic変数は0で初期化されるが一応初期化する */
+static errr init_buffer(void)
 {
        fresh_queue.next = fresh_queue.tail = 0;
        ring.wptr = ring.rptr = ring.inlen = 0;
@@ -89,11 +131,11 @@ static errr init_chuukei(void)
        return (0);
 }
 
-/* ¸½ºß¤Î»þ´Ö¤ò100msñ°Ì¤Ç¼èÆÀ¤¹¤ë */
+/* 現在の時間を100ms単位で取得する */
 static long get_current_time(void)
 {
 #ifdef WINDOWS
-       return GetTickCount() / 100;
+       return timeGetTime() / 100;
 #elif defined(MACINTOSH)
        return TickCount();
 #else
@@ -105,37 +147,48 @@ static long get_current_time(void)
 }
 
 
-/* ¥ê¥ó¥°¥Ð¥Ã¥Õ¥¡¹½Â¤ÂΤˠbuf ¤ÎÆâÍƤò²Ã¤¨¤ë */
+/* リングバッファ構造体に buf の内容を加える */
 static errr insert_ringbuf(char *buf)
 {
        int len;
-       len = strlen(buf) + 1; /* +1¤Ï½ªÃ¼Ê¸»úʬ */
+       len = strlen(buf) + 1; /* +1は終端文字分 */
+
+       if (movie_mode)
+       {
+               fd_write(movie_fd, buf, len);
+#ifdef CHUUKEI
+               if (!chuukei_server) return 0;
+#else
+               return 0;
+#endif
+       }
 
-       /* ¥Ð¥Ã¥Õ¥¡¤ò¥ª¡¼¥Ð¡¼ */
+       /* ã\83\90ã\83\83ã\83\95ã\82¡ã\82\92ã\82ªã\83¼ã\83\90ã\83¼ */
        if (ring.inlen + len >= RINGBUF_SIZE)
        {
-               chuukei_server = FALSE;
-               chuukei_client = FALSE;
+#ifdef CHUUKEI
+               if (chuukei_server) disable_chuukei_server();
+               else chuukei_client = FALSE;
 
-               prt("¥Ð¥Ã¥Õ¥¡¤¬°î¤ì¤Þ¤·¤¿¡£¥µ¡¼¥Ð¤È¤ÎÀܳ¤òÀÚÃǤ·¤Þ¤¹¡£", 0, 0);
+               prt("送受信バッファが溢れました。サーバとの接続を切断します。", 0, 0);
                inkey();
 
                close(sd);
-
+#endif
                return (-1);
        }
 
-       /* ¥Ð¥Ã¥Õ¥¡¤Î½ªÃ¼¤Þ¤Ç¤Ë¼ý¤Þ¤ë */
+       /* バッファの終端までに収まる */
        if (ring.wptr + len < RINGBUF_SIZE)
        {
                memcpy(ring.buf + ring.wptr, buf, len);
                ring.wptr += len;
        }
-       /* ¥Ð¥Ã¥Õ¥¡¤Î½ªÃ¼¤Þ¤Ç¤Ë¼ý¤Þ¤é¤Ê¤¤(¥Ô¥Ã¥¿¥ê¼ý¤Þ¤ë¾ì¹ç¤â´Þ¤à) */
+       /* バッファの終端までに収まらない(ピッタリ収まる場合も含む) */
        else
        {
-               int head = RINGBUF_SIZE - ring.wptr;  /* Á°È¾ */
-               int tail = len - head;               /* ¸åȾ */
+               int head = RINGBUF_SIZE - ring.wptr;  /* 前半 */
+               int tail = len - head;               /* 後半 */
 
                memcpy(ring.buf + ring.wptr, buf, head);
                memcpy(ring.buf, buf + head, tail);
@@ -148,12 +201,12 @@ static errr insert_ringbuf(char *buf)
        return (0);
 }
 
+#ifdef CHUUKEI
 void flush_ringbuf(void)
 {
 #ifndef MACINTOSH
        fd_set fdset;
        struct timeval tv;
-       int writen = 0;
 
        if (!chuukei_server) return;
 
@@ -168,26 +221,24 @@ void flush_ringbuf(void)
        while (1)
        {
                fd_set tmp_fdset;
-               struct timeval tmp_tv;
                int result;
 
                tmp_fdset = fdset;
-               tmp_tv = tv;
 
-               /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤ò½ñ¤­¹þ¤á¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
+               /* ソケットにデータを書き込めるかどうか調べる */
                select(sd+1, (fd_set *)NULL, &tmp_fdset, (fd_set *)NULL, &tv);
 
-               /* ½ñ¤­¹þ¤á¤Ê¤±¤ì¤ÐÌá¤ë */
+               /* 書き込めなければ戻る */
                if (FD_ISSET(sd, &tmp_fdset) == 0) break;
 
                result = send(sd, ring.buf + ring.rptr, ((ring.wptr > ring.rptr ) ? ring.wptr : RINGBUF_SIZE) - ring.rptr, 0);
 
                if (result <= 0)
                {
-                       /* ¥µ¡¼¥Ð¤È¤ÎÀܳÃÇ¡© */
-                       chuukei_server = FALSE;
+                       /* サーバとの接続断? */
+                       if (chuukei_server) disable_chuukei_server();
 
-                       prt("¥µ¡¼¥Ð¤È¤ÎÀܳ¤¬ÀÚÃǤµ¤ì¤Þ¤·¤¿¡£", 0, 0);
+                       prt("サーバとの接続が切断されました。", 0, 0);
                        inkey();
                        close(sd);
 
@@ -196,38 +247,28 @@ void flush_ringbuf(void)
 
                ring.rptr += result;
                ring.inlen -= result;
-               writen += result;
 
                if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
                if (ring.inlen == 0) break;
        }
 #else
-       struct timeval tv;
-       int writen = 0;
-
        if (!chuukei_server) return;
 
        if (ring.inlen == 0) return;
 
-       tv.tv_sec = 0;
-       tv.tv_usec = 0;
-
        while (1)
        {
-               struct timeval tmp_tv;
                int result;
 
-               tmp_tv = tv;
-
-               /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤ò½ñ¤­¹þ¤á¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
+               /* ソケットにデータを書き込めるかどうか調べる */
                result = OTSnd(ep, ring.buf + ring.rptr, ((ring.wptr > ring.rptr ) ? ring.wptr : RINGBUF_SIZE) - ring.rptr, 0);
 
                if (result <= 0)
                {
-                       /* ¥µ¡¼¥Ð¤È¤ÎÀܳÃÇ¡© */
-                       chuukei_server = FALSE;
+                       /* サーバとの接続断? */
+                       if (chuukei_server) disable_chuukei_server();
 
-                       prt("¥µ¡¼¥Ð¤È¤ÎÀܳ¤¬ÀÚÃǤµ¤ì¤Þ¤·¤¿¡£", 0, 0);
+                       prt("サーバとの接続が切断されました。", 0, 0);
                        inkey();
                        close(sd);
 
@@ -236,7 +277,6 @@ void flush_ringbuf(void)
 
                ring.rptr += result;
                ring.inlen -= result;
-               writen += result;
 
                if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
                if (ring.inlen == 0) break;
@@ -244,7 +284,8 @@ void flush_ringbuf(void)
 #endif
 }
 
-static int read_chuukei_prf(cptr prf_name)
+
+static int read_chuukei_prf(concptr prf_name)
 {
        char buf[1024];
        FILE *fp;
@@ -254,27 +295,27 @@ static int read_chuukei_prf(cptr prf_name)
 
        if (!fp) return (-1);
 
-       /* ½é´ü²½ */
+       /* 初期化 */
        server_port = -1;
        server_name[0] = 0;
        browse_delay = DEFAULT_DELAY;
 
        while (0 == my_fgets(fp, buf, sizeof(buf)))
        {
-               /* ¥µ¡¼¥Ð̾ */
+               /* サーバ名 */
                if (!strncmp(buf, "server:", 7))
                {
                        strncpy(server_name, buf + 7, MAX_HOSTNAME - 1);
                        server_name[MAX_HOSTNAME - 1] = '\0';
                }
 
-               /* ¥Ý¡¼¥ÈÈÖ¹æ */
+               /* ポート番号 */
                if (!strncmp(buf, "port:", 5))
                {
                        server_port = atoi(buf + 5);
                }
 
-               /* ¥Ç¥£¥ì¥¤ */
+               /* ã\83\87ã\82£ã\83¬ã\82¤ */
                if (!strncmp(buf, "delay:", 6))
                {
                        browse_delay = atoi(buf + 6);
@@ -283,7 +324,7 @@ static int read_chuukei_prf(cptr prf_name)
 
        my_fclose(fp);
 
-       /* prf¥Õ¥¡¥¤¥ë¤¬´°Á´¤Ç¤Ê¤¤ */
+       /* prfファイルが完全でない */
        if (server_port == -1 || server_name[0] == 0) return (-1);
 
        return (0);
@@ -307,7 +348,7 @@ int connect_chuukei_server(char *prf_name)
                return (-1);
        }
 
-       if (init_chuukei() < 0)
+       if (init_buffer() < 0)
        {
                printf("Malloc error\n");
                return (-1);
@@ -357,8 +398,6 @@ int connect_chuukei_server(char *prf_name)
                return (-1);
        }
 
-       epoch_time = get_current_time();
-
        return (0);
 #else  /* MACINTOSH */
        OSStatus err;
@@ -374,7 +413,7 @@ int connect_chuukei_server(char *prf_name)
                return (-1);
        }
        
-       init_chuukei();
+       init_buffer();
        
        printf("server = %s\nport = %d\n", server_name, server_port);
 
@@ -418,11 +457,11 @@ int connect_chuukei_server(char *prf_name)
                        
                        sndCall.addr.len        = sizeof(InetAddress);                          
                        sndCall.addr.buf        = (unsigned char*) &inAddr;
-                       sndCall.opt.buf         = nil;        /* no connection options */
+                       sndCall.opt.buf         = nil;          /* no connection options */
                        sndCall.opt.len         = 0;
-                       sndCall.udata.buf       = nil;        /* no connection data */
+                       sndCall.udata.buf       = nil;          /* no connection data */
                        sndCall.udata.len       = 0;
-                       sndCall.sequence        = 0;          /* ignored by OTConnect */
+                       sndCall.sequence        = 0;            /* ignored by OTConnect */
                        
                        err = OTConnect(ep, &sndCall, NULL);
                        
@@ -458,9 +497,9 @@ int connect_chuukei_server(char *prf_name)
 
 #endif
 }
+#endif /* CHUUKEI */
 
-
-/* str¤¬Æ±¤¸Ê¸»ú¤Î·«¤êÊÖ¤·¤«¤É¤¦¤«Ä´¤Ù¤ë */
+/* strが同じ文字の繰り返しかどうか調べる */
 static bool string_is_repeat(char *str, int len)
 {
        char c = str[0];
@@ -483,13 +522,11 @@ static bool string_is_repeat(char *str, int len)
        return (TRUE);
 }
 
-void send_text_to_chuukei_server(int x, int y, int len, int col, char *str)
+static errr send_text_to_chuukei_server(TERM_LEN x, TERM_LEN y, int len, TERM_COLOR col, concptr str)
 {
        char buf[1024];
        char buf2[1024];
 
-       if (!chuukei_server || Term != angband_term[0]) return;
-
        strncpy(buf2, str, len);
        buf2[len] = '\0';
 
@@ -499,115 +536,330 @@ void send_text_to_chuukei_server(int x, int y, int len, int col, char *str)
        }
        else if(string_is_repeat(buf2, len))
        {
-               sprintf(buf, "n%c%c%c%c%c", x+1, y+1, len, col, buf2[0]);
+               int i;
+               for (i = len; i > 0; i -= 127)
+               {
+                       sprintf(buf, "n%c%c%c%c%c", x+1, y+1, MIN(i, 127), col, buf2[0]);
+               }
        }
        else
        {
-#ifdef SJIS
+#if defined(SJIS) && defined(JP)
                sjis2euc(buf2);
 #endif
                sprintf(buf, "t%c%c%c%c%s", x+1, y+1, len, col, buf2);
        }
 
        insert_ringbuf(buf);
+
+       return (*old_text_hook)(x, y, len, col, str);
 }
 
-void send_wipe_to_chuukei_server(int x, int y, int len)
+static errr send_wipe_to_chuukei_server(int x, int y, int len)
 {
        char buf[1024];
 
-       if (!chuukei_server || Term != angband_term[0]) return;
-
        sprintf(buf, "w%c%c%c", x+1, y+1, len);
 
        insert_ringbuf(buf);
+
+       return (*old_wipe_hook)(x, y, len);
 }
 
-void send_xtra_to_chuukei_server(int n)
+static errr send_xtra_to_chuukei_server(int n, int v)
 {
        char buf[1024];
 
-       if (!chuukei_server || Term != angband_term[0]) return;
-       sprintf(buf, "x%c", n+1);
-
-       insert_ringbuf(buf);
-
-       if (n == TERM_XTRA_FRESH)
+       if (n == TERM_XTRA_CLEAR || n == TERM_XTRA_FRESH || n == TERM_XTRA_SHAPE)
        {
-               sprintf(buf, "d%ld", get_current_time() - epoch_time);
+               sprintf(buf, "x%c", n+1);
+               
                insert_ringbuf(buf);
+               
+               if (n == TERM_XTRA_FRESH)
+               {
+                       sprintf(buf, "d%ld", get_current_time() - epoch_time);
+                       insert_ringbuf(buf);
+               }
        }
+
+       /* Verify the hook */
+       if (!old_xtra_hook) return -1;
+
+       return (*old_xtra_hook)(n, v);
 }
 
-void send_curs_to_chuukei_server(int x, int y)
+static errr send_curs_to_chuukei_server(int x, int y)
 {
        char buf[1024];
 
-       if (!chuukei_server || Term != angband_term[0]) return;
        sprintf(buf, "c%c%c", x+1, y+1);
 
        insert_ringbuf(buf);
+
+       return (*old_curs_hook)(x, y);
 }
 
-static int read_sock(void)
+static errr send_bigcurs_to_chuukei_server(int x, int y)
 {
        char buf[1024];
-       int i;
 
-       for (i = 0;; i++)
-       {
-               if (recv(sd, buf+i, 1, 0) <= 0) 
-                       return -1;
+       sprintf(buf, "C%c%c", x+1, y+1);
 
-               if (buf[i] == '\0')
+       insert_ringbuf(buf);
+
+       return (*old_bigcurs_hook)(x, y);
+}
+
+
+/*
+ * Prepare z-term hooks to call send_*_to_chuukei_server()'s
+ */
+void prepare_chuukei_hooks(void)
+{
+       term *t0 = angband_term[0];
+
+       /* Save original z-term hooks */
+       old_xtra_hook = t0->xtra_hook;
+       old_curs_hook = t0->curs_hook;
+       old_bigcurs_hook = t0->bigcurs_hook;
+       old_wipe_hook = t0->wipe_hook;
+       old_text_hook = t0->text_hook;
+
+       /* Prepare z-term hooks */
+       t0->xtra_hook = send_xtra_to_chuukei_server;
+       t0->curs_hook = send_curs_to_chuukei_server;
+       t0->bigcurs_hook = send_bigcurs_to_chuukei_server;
+       t0->wipe_hook = send_wipe_to_chuukei_server;
+       t0->text_hook = send_text_to_chuukei_server;
+}
+
+
+/*
+ * Prepare z-term hooks to call send_*_to_chuukei_server()'s
+ */
+void prepare_movie_hooks(void)
+{
+       char buf[1024];
+       char tmp[80];
+
+       if (movie_mode)
+       {
+               movie_mode = 0;
+#ifdef CHUUKEI
+               if (!chuukei_server) disable_chuukei_server();
+#else
+               disable_chuukei_server();
+#endif
+               fd_close(movie_fd);
+               msg_print(_("録画を終了しました。", "Stopped recording."));
+       }
+       else
+       {
+               sprintf(tmp, "%s.amv", player_base);
+               if (get_string(_("ムービー記録ファイル: ", "Movie file name: "), tmp, 80))
                {
-                       if (buf[0] == 'd')
+                       int fd;
+
+                       path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
+
+                       fd = fd_open(buf, O_RDONLY);
+
+                       /* Existing file */
+                       if (fd >= 0)
+                       {
+                               char out_val[160];
+                               (void)fd_close(fd);
+
+                               /* Build query */
+                               (void)sprintf(out_val, _("現存するファイルに上書きしますか? (%s)", "Replace existing file %s? "), buf);
+
+                               /* Ask */
+                               if (!get_check(out_val)) return;
+
+                               movie_fd = fd_open(buf, O_WRONLY | O_TRUNC);
+                       }
+                       else
                        {
-                               int timestamp = atoi(buf + 1);
-                               long current_time = get_current_time();
-
-                               /* ºÇ½é¤Î»þ´Ö¤òÊݸ¤·¤Æ¤ª¤¯ */
-                               if (!fresh_queue.time[0])
-                               {
-                                       epoch_time = current_time;
-                                       epoch_time += browse_delay;
-                                       epoch_time -= timestamp;
-                                       time_diff = current_time - timestamp;
-                               }
-
-                               fresh_queue.time[fresh_queue.tail] = timestamp;
-                               fresh_queue.tail ++;
-
-                               if (fresh_queue.tail == FRESH_QUEUE_SIZE)
-                                       fresh_queue.tail = 0;
-
-                               /* ¥×¥ì¥¤Â¦¤È¤Î¥Ç¥£¥ì¥¤¤òÄ´À° */
-                               if (time_diff > current_time - timestamp)
-                               {
-                                       long old_time_diff = time_diff;
-                                       time_diff = current_time - timestamp;
-                                       epoch_time -= (old_time_diff - time_diff);
-                               }
-
-                               if (fresh_queue.tail == fresh_queue.next)
-                               {
-                                       /* queue°î¤ì */
-                                       close(sd);
-                                       exit(1);
-                               }
+                               movie_fd = fd_make(buf, 0644);
+                       }
 
+                       if (!movie_fd)
+                       {
+                               msg_print(_("ファイルを開けません!", "Can not open file."));
+                               return;
                        }
 
-                       if (insert_ringbuf(buf) < 0) 
+                       movie_mode = 1;
+#ifdef CHUUKEI
+                       if (!chuukei_server) prepare_chuukei_hooks();
+#else
+                       prepare_chuukei_hooks();
+#endif
+                       do_cmd_redraw();
+               }
+       }
+}
+
+#ifdef CHUUKEI
+static int handle_timestamp_data(int timestamp)
+{
+       long current_time = get_current_time();
+
+       /* 描画キューは空かどうか? */
+       if (fresh_queue.tail == fresh_queue.next)
+       {
+               /* バッファリングし始めの時間を保存しておく */
+               epoch_time = current_time;
+               epoch_time += browse_delay;
+               epoch_time -= timestamp;
+               time_diff = current_time - timestamp;
+       }
+
+       /* 描画キューに保存し、保存位置を進める */
+       fresh_queue.time[fresh_queue.tail] = timestamp;
+       fresh_queue.tail ++;
+
+       /* キューの最後尾に到達したら先頭に戻す */
+       fresh_queue.tail %= FRESH_QUEUE_SIZE;
+
+       if (fresh_queue.tail == fresh_queue.next)
+       {
+               /* 描画キュー溢れ */
+               prt("描画タイミングキューが溢れました。サーバとの接続を切断します。", 0, 0);
+               inkey();
+               close(sd);
+
+               return -1;
+       }
+
+       /* プレイ側とのディレイを調整 */
+       if (time_diff != current_time - timestamp)
+       {
+               long old_time_diff = time_diff;
+               time_diff = current_time - timestamp;
+               epoch_time -= (old_time_diff - time_diff);
+       }
+
+       /* Success */
+       return 0;
+}
+#endif /* CHUUKEI */
+
+static int handle_movie_timestamp_data(int timestamp)
+{
+       static int initialized = FALSE;
+
+       /* 描画キューは空かどうか? */
+       if (!initialized)
+       {
+               /* バッファリングし始めの時間を保存しておく */
+               epoch_time = get_current_time();
+               epoch_time += browse_delay;
+               epoch_time -= timestamp;
+               //time_diff = current_time - timestamp;
+               initialized = TRUE;
+       }
+
+       /* 描画キューに保存し、保存位置を進める */
+       fresh_queue.time[fresh_queue.tail] = timestamp;
+       fresh_queue.tail ++;
+
+       /* キューの最後尾に到達したら先頭に戻す */
+       fresh_queue.tail %= FRESH_QUEUE_SIZE;
+
+       /* Success */
+       return 0;
+}
+
+#ifdef CHUUKEI
+static int read_sock(void)
+{
+       static char recv_buf[RECVBUF_SIZE];
+       static int remain_bytes = 0;
+       int recv_bytes;
+       int i;
+
+       /* 前回残ったデータの後につづけて配信サーバからデータ受信 */
+       recv_bytes = recv(sd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes, 0);
+
+       if (recv_bytes <= 0)
+               return -1;
+
+       /* 前回残ったデータ量に今回読んだデータ量を追加 */
+       remain_bytes += recv_bytes;
+
+       for (i = 0; i < remain_bytes; i ++)
+       {
+               /* データのくぎり('\0')を探す */
+               if (recv_buf[i] == '\0')
+               {
+                       /* 'd'で始まるデータ(タイムスタンプ)の場合は
+                          描画キューに保存する処理を呼ぶ */
+                       if ((recv_buf[0] == 'd') &&
+                           (handle_timestamp_data(atoi(recv_buf + 1)) < 0))
+                               return -1;
+
+                       /* 受信データを保存 */
+                       if (insert_ringbuf(recv_buf) < 0) 
+                               return -1;
+
+                       /* 次のデータ移行をrecv_bufの先頭に移動 */
+                       memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
+
+                       remain_bytes -= (i+1);
+                       i = 0;
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static int read_movie_file(void)
+{
+       static char recv_buf[RECVBUF_SIZE];
+       static int remain_bytes = 0;
+       int recv_bytes;
+       int i;
+
+       recv_bytes = read(movie_fd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes);
+
+       if (recv_bytes <= 0)
+               return -1;
+
+       /* 前回残ったデータ量に今回読んだデータ量を追加 */
+       remain_bytes += recv_bytes;
+
+       for (i = 0; i < remain_bytes; i ++)
+       {
+               /* データのくぎり('\0')を探す */
+               if (recv_buf[i] == '\0')
+               {
+                       /* 'd'で始まるデータ(タイムスタンプ)の場合は
+                          描画キューに保存する処理を呼ぶ */
+                       if ((recv_buf[0] == 'd') &&
+                           (handle_movie_timestamp_data(atoi(recv_buf + 1)) < 0))
+                               return -1;
+
+                       /* 受信データを保存 */
+                       if (insert_ringbuf(recv_buf) < 0) 
                                return -1;
-                       return (i);
+
+                       /* 次のデータ移行をrecv_bufの先頭に移動 */
+                       memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
+
+                       remain_bytes -= (i+1);
+                       i = 0;
                }
        }
+
+       return 0;
 }
 
 
 #ifndef WINDOWS
-/* WinÈǤÎÃæÅÀ¤ÈÊɤÎƦÉå¤ò¥Ô¥ê¥ª¥É¤È¥·¥ã¡¼¥×¤Ë¤¹¤ë¡£ */
+/* Win版の床の中点と壁の豆腐をピリオドとシャープにする。*/
 static void win2unix(int col, char *buf)
 {
        char kabe;
@@ -647,23 +899,41 @@ static bool get_nextbuf(char *buf)
        return (TRUE);
 }
 
+/* プレイホストのマップが大きいときクライアントのマップもリサイズする */
+static void update_term_size(int x, int y, int len)
+{
+       int ox, oy;
+       int nx, ny;
+       Term_get_size(&ox, &oy);
+       nx = ox;
+       ny = oy;
+
+       /* 横方向のチェック */
+       if (x + len > ox) nx = x + len;
+       /* 縦方向のチェック */
+       if (y + 1 > oy) ny = y + 1;
+
+       if (nx != ox || ny != oy) Term_resize(nx, ny);
+}
+
 static bool flush_ringbuf_client(void)
 {
        char buf[1024];
 
-       /* ½ñ¤¯¥Ç¡¼¥¿¤Ê¤· */
+       /* 書くデータなし */
        if (fresh_queue.next == fresh_queue.tail) return (FALSE);
 
-       /* ¤Þ¤À½ñ¤¯¤Ù¤­»þ¤Ç¤Ê¤¤ */
+       /* まだ書くべき時でない */
        if (fresh_queue.time[fresh_queue.next] > get_current_time() - epoch_time) return (FALSE);
 
-       /* »þ´Ö¾ðÊó(¶èÀÚ¤ê)¤¬ÆÀ¤é¤ì¤ë¤Þ¤Ç½ñ¤¯ */
+       /* 時間情報(区切り)が得られるまで書く */
        while (get_nextbuf(buf))
        {
                char id;
-               int x, y, len, col;
+               int x, y, len;
+               TERM_COLOR col;
                int i;
-               char tmp1, tmp2, tmp3, tmp4;
+               unsigned char tmp1, tmp2, tmp3, tmp4;
                char *mesg;
 
                sscanf(buf, "%c%c%c%c%c", &id, &tmp1, &tmp2, &tmp3, &tmp4);
@@ -680,10 +950,11 @@ static bool flush_ringbuf_client(void)
 
                switch (id)
                {
-               case 't': /* Ä̾ï */
-#ifdef SJIS
+               case 't': /* 通常 */
+#if defined(SJIS) && defined(JP)
                        euc2sjis(mesg);
 #endif
+                       update_term_size(x, y, len);
                        (void)((*angband_term[0]->text_hook)(x, y, len, (byte)col, mesg));
                        strncpy(&Term->scr->c[y][x], mesg, len);
                        for (i = x; i < x+len; i++)
@@ -692,12 +963,13 @@ static bool flush_ringbuf_client(void)
                        }
                        break;
 
-               case 'n': /* ·«¤êÊÖ¤· */
+               case 'n': /* 繰り返し */
                        for (i = 1; i < len; i++)
                        {
                                mesg[i] = mesg[0];
                        }
                        mesg[i] = '\0';
+                       update_term_size(x, y, len);
                        (void)((*angband_term[0]->text_hook)(x, y, len, (byte)col, mesg));
                        strncpy(&Term->scr->c[y][x], mesg, len);
                        for (i = x; i < x+len; i++)
@@ -706,13 +978,15 @@ static bool flush_ringbuf_client(void)
                        }
                        break;
 
-               case 's': /* °ìʸ»ú */
+               case 's': /* 一文字 */
+                       update_term_size(x, y, 1);
                        (void)((*angband_term[0]->text_hook)(x, y, 1, (byte)col, mesg));
                        strncpy(&Term->scr->c[y][x], mesg, 1);
                        Term->scr->a[y][x] = col;
                        break;
 
                case 'w':
+                       update_term_size(x, y, len);
                        (void)((*angband_term[0]->wipe_hook)(x, y, len));
                        break;
 
@@ -722,8 +996,13 @@ static bool flush_ringbuf_client(void)
                        break;
 
                case 'c':
+                       update_term_size(x, y, 1);
                        (void)((*angband_term[0]->curs_hook)(x, y));
                        break;
+               case 'C':
+                       update_term_size(x, y, 1);
+                       (void)((*angband_term[0]->bigcurs_hook)(x, y));
+                       break;
                }
        }
 
@@ -732,6 +1011,7 @@ static bool flush_ringbuf_client(void)
        return (TRUE);
 }
 
+#ifdef CHUUKEI
 void browse_chuukei()
 {
 #ifndef MACINTOSH
@@ -758,7 +1038,7 @@ void browse_chuukei()
                tmp_fdset = fdset;
                tmp_tv = tv;
 
-               /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤¬Íè¤Æ¤¤¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
+               /* ソケットにデータが来ているかどうか調べる */
                select(sd+1, &tmp_fdset, (fd_set *)NULL, (fd_set *)NULL, &tmp_tv);
                if (FD_ISSET(sd, &tmp_fdset) == 0)
                {
@@ -771,31 +1051,23 @@ void browse_chuukei()
                        chuukei_client = FALSE;
                }
 
-               /* Àܳ¤¬Àڤ줿¾õÂ֤ǽñ¤¯¤Ù¤­¥Ç¡¼¥¿¤¬¤Ê¤¯¤Ê¤Ã¤Æ¤¤¤¿¤é½ªÎ» */
+               /* 接続が切れた状態で書くべきデータがなくなっていたら終了 */
                if (!chuukei_client && fresh_queue.next == fresh_queue.tail ) break;
        }
 #else
-       struct timeval tv;
-
-       tv.tv_sec = 0;
-       tv.tv_usec = WAIT;
-
        Term_clear();
        Term_fresh();
        Term_xtra(TERM_XTRA_REACT, 0);
 
        while (1)
        {
-               struct timeval tmp_tv;
                UInt32  unreadData = 0;
                int n;
-               
+
                if (flush_ringbuf_client()) continue;
 
-               tmp_tv = tv;
+               /* ソケットにデータが来ているかどうか調べる */
 
-               /* ¥½¥±¥Ã¥È¤Ë¥Ç¡¼¥¿¤¬Íè¤Æ¤¤¤ë¤«¤É¤¦¤«Ä´¤Ù¤ë */
-               
                OTCountDataBytes(ep, &unreadData);
                if(unreadData <= 0 ){
                        Term_xtra(TERM_XTRA_FLUSH, 0);
@@ -806,10 +1078,51 @@ void browse_chuukei()
                        chuukei_client = FALSE;
                }
 
-               /* Àܳ¤¬Àڤ줿¾õÂ֤ǽñ¤¯¤Ù¤­¥Ç¡¼¥¿¤¬¤Ê¤¯¤Ê¤Ã¤Æ¤¤¤¿¤é½ªÎ» */
+               /* 接続が切れた状態で書くべきデータがなくなっていたら終了 */
                if (!chuukei_client && fresh_queue.next == fresh_queue.tail ) break;
        }
 #endif /*MACINTOSH*/
 }
-
 #endif /* CHUUKEI */
+
+void prepare_browse_movie_aux(concptr filename)
+{
+       movie_fd = fd_open(filename, O_RDONLY);
+       
+       browsing_movie = TRUE;
+
+       init_buffer();
+}
+
+void prepare_browse_movie(concptr filename)
+{
+       char buf[1024];
+       path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
+
+       prepare_browse_movie_aux(buf);
+}
+
+void browse_movie(void)
+{
+       Term_clear();
+       Term_fresh();
+       Term_xtra(TERM_XTRA_REACT, 0);
+
+       while (read_movie_file() == 0)
+       {
+               while (fresh_queue.next != fresh_queue.tail)
+               {
+                       if (!flush_ringbuf_client())
+                       {
+                               Term_xtra(TERM_XTRA_FLUSH, 0);
+
+                               /* ソケットにデータが来ているかどうか調べる */
+#ifdef WINDOWS
+                               Sleep(WAIT);
+#else
+                               usleep(WAIT);
+#endif
+                       }
+               }
+       }
+}