• R/O
  • SSH
  • HTTPS

Commit

Frequently used words (click to add to your profile)

javaandroidc++linuxc#objective-ccocoa誰得qtrubypythongamewindowsbathyscaphephpguic翻訳omegattwitterframeworktestbtronarduinovb.net計画中(planning stage)directxpreviewerゲームエンジンdom

密猟オンラインサーバープログラム


Commit MetaInfo

Revision1 (tree)
Time2016-01-16 19:40:14
Authormanjihq

Log Message

base version

Change Summary

Incremental Difference

--- trunk/ctlsock.c (nonexistent)
+++ trunk/ctlsock.c (revision 1)
@@ -0,0 +1,85 @@
1+#include <string.h>
2+
3+#include "port.h"
4+#include "ctlsock.h"
5+
6+SOCKET
7+makesocket (int port, unsigned long addr, int socktype)
8+{
9+ SOCKET hsock;
10+ struct sockaddr_in sockin;
11+
12+ memset (&sockin, 0, sizeof (sockin));
13+ sockin.sin_family = AF_INET;
14+ sockin.sin_addr.s_addr = htonl (addr);
15+ sockin.sin_port = htons (port);
16+ hsock = socket (PF_INET, socktype, DEFAULT_PROTOCOL);
17+ if (hsock != INVALID_SOCKET)
18+ {
19+ int n = 1;
20+ setsockopt (hsock, SOL_SOCKET, SO_REUSEADDR, (void *) &n, sizeof (n));
21+#ifdef TCP_MAXSEG
22+ n = REQ_SEGMENT_SIZE;
23+ setsockopt (hsock, SOL_TCP, TCP_MAXSEG, (void *) &n, sizeof (n));
24+#endif
25+ if (bind (hsock, (struct sockaddr *) &sockin, sizeof (sockin)) != 0)
26+ {
27+ closesocket (hsock);
28+ hsock = INVALID_SOCKET;
29+ }
30+ }
31+ return hsock;
32+}
33+
34+
35+int
36+cutsocket (SOCKET handle)
37+{
38+ shutdown (handle, 2);
39+ return closesocket (handle);
40+}
41+
42+
43+int
44+waitconnect (SOCKET handle, SESSION * psession)
45+{
46+ int ret = -1;
47+ struct sockaddr_in sockin;
48+ socklen_t socklen = sizeof (sockin);
49+ SOCKET newhandle = accept (handle, (struct sockaddr *) &sockin,
50+ &socklen);
51+ psession->handle = INVALID_SOCKET;
52+ if (newhandle != INVALID_SOCKET)
53+ {
54+ psession->handle = newhandle;
55+ psession->addr = sockin.sin_addr.s_addr;
56+ psession->port = sockin.sin_port;
57+ ret = 0;
58+ }
59+ return ret;
60+}
61+
62+SOCKET
63+connectsocket (int port, unsigned long addr, int socktype)
64+{
65+ SOCKET hsock;
66+ struct sockaddr_in sockin;
67+
68+ memset (&sockin, 0, sizeof (sockin));
69+ sockin.sin_family = AF_INET;
70+ sockin.sin_addr.s_addr = htonl (addr);
71+ sockin.sin_port = htons (port);
72+ hsock = socket (PF_INET, socktype, DEFAULT_PROTOCOL);
73+ if (hsock != INVALID_SOCKET)
74+ {
75+ if (connect (hsock, (struct sockaddr *) &sockin, sizeof (sockin)) != 0)
76+ {
77+ closesocket (hsock);
78+ hsock = INVALID_SOCKET;
79+ }
80+ }
81+ return hsock;
82+}
83+
84+
85+/* EOF */
--- trunk/hunt.h (nonexistent)
+++ trunk/hunt.h (revision 1)
@@ -0,0 +1,128 @@
1+/* h-online */
2+
3+#define PACKET_DATA_MAX 1024
4+#define PACKET_HEADER_MAX 2
5+#define PACKET_MAX (PACKET_DATA_MAX+PACKET_HEADER_MAX)
6+
7+#define SENDMAP_CHUNK 1000
8+
9+#define DEFAULT_PORT 10001
10+
11+#define USERNAME_LEN 16
12+#define PASSWORD_LEN 16
13+#define SCORE_LIMIT 999999999L
14+#define ANIMALNAME_LEN 16
15+#define WEAPON_MAX 2
16+#define WEAPONNAME_LEN 32
17+#define ITEM_MAX 4
18+#define ITEMNAME_LEN 32
19+#define VIEW_LIMIT 5
20+#define VIEW_WIDTH 5
21+#define HIGEMESG_LEN 255
22+#define HIREABLE_NPC_TYPE 3
23+#define HPROTOCOL_VERSION 5
24+
25+/* from Server packet ID */
26+#define HSERV_RESULT 0x00
27+#define HSERV_STATUS 0x03
28+#define HSERV_MAP 0x04
29+#define HSERV_MAPANDSTATUS 0x06
30+#define HSERV_MESG 0x10
31+#define HSERV_SYSMESG 0x11
32+#define HSERV_WHO 0x20
33+#define HSERV_BBS_HEADER 0x28
34+#define HSERV_BBS_BODY 0x29
35+#define HSERV_BBS_BODYEND 0x2a
36+#define HSERV_EFFECT_DAMAGE 0x30
37+#define HSERV_EFFECT_DEATH 0x31
38+#define HSERV_EFFECT_DIGGING 0x32
39+#define HSERV_EFFECT_FALL 0x33
40+#define HSERV_TRANSMAP_START 0x38
41+#define HSERV_TRANSMAP_CHUNK 0x39
42+#define HSERV_SENDMAIL 0x3a
43+#define HSERV_SENDMAILBODY 0x3b
44+#define HSERV_SENDEND 0x3c
45+
46+/* from Client packet ID */
47+#define HCLIT_LOGIN 0x00
48+#define HCLIT_MOVE 0x01
49+#define HCLIT_CHDIR 0x02
50+#define HCLIT_FIRE 0x03
51+#define HCLIT_ITEM 0x04
52+#define HCLIT_PICK 0x05
53+#define HCLIT_PAY 0x06
54+#define HCLIT_BUY 0x07
55+#define HCLIT_MESG 0x10
56+#define HCLIT_MESG2U 0x11
57+#define HCLIT_MESG2ALL 0x12
58+#define HCLIT_WHO 0x20
59+#define HCLIT_REQWEAPON 0x21
60+#define HCLIT_REQITEM 0x22
61+#define HCLIT_WRITEMESG 0x23
62+#define HCLIT_DROPOBJ 0x24
63+#define HCLIT_CHANGEANIMAL 0x25
64+#define HCLIT_STOREANIMAL 0x28
65+#define HCLIT_STOREOBJ 0x29
66+#define HCLIT_CHANGEMYSHOP 0x2a
67+#define HCLIT_DISCARDMYSHOPOBJ 0x2b
68+#define HCLIT_DESTROYMYSHOP 0x2c
69+#define HCLIT_LISTMYSHOP 0x2d
70+#define HCLIT_REQANIMAL 0x2e
71+#define HCLIT_LISTLIVEANIMAL 0x2f
72+#define HCLIT_TRANSFERSCORE 0x30
73+#define HCLIT_BBS_POST 0x31
74+#define HCLIT_BBS_LIST 0x32
75+#define HCLIT_BBS_READ 0x33
76+#define HCLIT_SENDMAIL 0x34
77+#define HCLIT_SENDMAILBODY 0x35
78+#define HCLIT_SENDEND 0x36
79+#define HCLIT_LISTMAIL 0x37
80+#define HCLIT_READMAIL 0x38
81+#define HCLIT_DELETEMAIL 0x39
82+#define HCLIT_LOGOFF 0x3a
83+#define HCLIT_NEWUSER 0x3b
84+#define HCLIT_DELUSER 0x3c
85+
86+/* map data */
87+#define HCLIT_MAP_INVALID '?'
88+#define HCLIT_MAP_ROAD ' '
89+#define HCLIT_MAP_TREE '!'
90+#define HCLIT_MAP_ROCK '*'
91+#define HCLIT_MAP_ITEM '$'
92+#define HCLIT_MAP_SHOP '@'
93+#define HCLIT_MAP_USERSHOP '+'
94+#define HCLIT_MAP_WALL '#'
95+#define HCLIT_MAP_ANIMAL 'a'
96+#define HCLIT_MAP_DEADANIMAL '%'
97+
98+/* player on map data */
99+#define HCLIT_PLAYER_N 'A'
100+#define HCLIT_PLAYER_S 'V'
101+#define HCLIT_PLAYER_W '<'
102+#define HCLIT_PLAYER_E '>'
103+#define HCLIT_PLAYER_NONE ' '
104+
105+#define HCLIT_GUARD_N '^'
106+#define HCLIT_GUARD_S 'v'
107+#define HCLIT_GUARD_W 'd'
108+#define HCLIT_GUARD_E 'b'
109+
110+#define HCLIT_NPC_N 'N'
111+#define HCLIT_NPC_S 'S'
112+#define HCLIT_NPC_W 'W'
113+#define HCLIT_NPC_E 'E'
114+
115+/* direction */
116+#define DIRECTION_N 0
117+#define DIRECTION_W 1
118+#define DIRECTION_E 2
119+#define DIRECTION_S 3
120+
121+/* moving */
122+#define MOVE_FORWARD 0
123+#define MOVE_BACKWARD 1
124+#define MOVE_LEFT 2
125+#define MOVE_RIGHT 3
126+
127+
128+/* EOF */
--- trunk/pktio.c (nonexistent)
+++ trunk/pktio.c (revision 1)
@@ -0,0 +1,265 @@
1+#include "port.h"
2+#include "ctlsock.h"
3+#include <stdlib.h>
4+#include <string.h>
5+#include <errno.h>
6+#include "hunt.h"
7+#include "pktio.h"
8+
9+
10+/* compress data */
11+static int
12+compress (const unsigned char *pin, unsigned char *pout, int n)
13+{
14+ int ret = 0;
15+ int count = 1;
16+ unsigned char c = *pin++;
17+ while (--n > 0)
18+ {
19+ if (*pin == c)
20+ {
21+ if (count == 16)
22+ {
23+ *pout++ = 0xff;
24+ *pout++ = c;
25+ ret += 2;
26+ count = 1;
27+ }
28+ else
29+ {
30+ count++;
31+ }
32+ }
33+ else
34+ {
35+ if (count > 2 || (c & 0xf0) == 0xf0)
36+ {
37+ *pout++ = 0xf0 | (count - 1);
38+ *pout++ = c;
39+ ret += 2;
40+ }
41+ else
42+ {
43+ while (count--)
44+ {
45+ *pout++ = c;
46+ ret++;
47+ }
48+ }
49+ count = 1;
50+ c = *pin;
51+ }
52+ pin++;
53+ }
54+ if (count > 2 || (c & 0xf0) == 0xf0)
55+ {
56+ *pout++ = 0xf0 | (count - 1);
57+ *pout++ = c;
58+ ret += 2;
59+ }
60+ else
61+ {
62+ while (count--)
63+ {
64+ *pout++ = c;
65+ ret++;
66+ }
67+ }
68+ return ret;
69+}
70+
71+/* uncompress data */
72+static int
73+uncompress (const unsigned char *pin, unsigned char *pout, int n)
74+{
75+ int ret = 0;
76+ while (n-- > 0)
77+ {
78+ unsigned char c = *pin++;
79+ if ((c & 0xf0) == 0xf0)
80+ {
81+ int count = (int) (c & 0x0f) + 1;
82+ c = *pin++;
83+ if (n-- <= 0)
84+ {
85+ break;
86+ }
87+ while (count-- > 0)
88+ {
89+ *pout++ = c;
90+ ret++;
91+ }
92+ }
93+ else
94+ {
95+ *pout++ = c;
96+ ret++;
97+ }
98+ }
99+ return ret;
100+}
101+
102+/* send compress packet */
103+int
104+send_packet_c (SOCKET handle, unsigned char *ppacket, int nsize)
105+{
106+ int ret = -1;
107+ unsigned char sendbuffer[PACKET_MAX];
108+ int sendsize = 0;
109+ if (nsize > 0)
110+ {
111+ int compress_size;
112+ compress_size = compress (ppacket + 2, sendbuffer + 2, nsize);
113+ if (compress_size)
114+ {
115+ sendsize = 2 + compress_size;
116+ sendbuffer[0] = *ppacket;
117+ *(ppacket + 1) = sendbuffer[1] = compress_size & 0xff;
118+ sendbuffer[0] &= 0x3f;
119+ sendbuffer[0] |= (compress_size & 0x300) >> 2;
120+ *ppacket = sendbuffer[0];
121+ /* for send sendbuffer */
122+ ppacket = sendbuffer;
123+ }
124+ else
125+ {
126+ return -1;
127+ }
128+ }
129+ else
130+ {
131+ sendsize = 2;
132+ *(ppacket + 1) = 0;
133+ *ppacket &= 0x3f;
134+ }
135+ while (sendsize > 0)
136+ {
137+ int result;
138+ fd_set wfds;
139+ struct timeval tmout;
140+ tmout.tv_sec = 1;
141+ tmout.tv_usec = 0;
142+ FD_ZERO (&wfds);
143+ FD_SET (handle, &wfds);
144+ result = select (handle + 1, NULL, &wfds, NULL, &tmout);
145+ if (result > 0)
146+ {
147+ int n = send (handle, ppacket, sendsize, 0);
148+ if (n == -1)
149+ {
150+ if (errno == EINTR)
151+ {
152+ continue;
153+ }
154+ break;
155+ }
156+ if (sendsize == n)
157+ {
158+ ret = 0;
159+ break;
160+ }
161+ if (!n)
162+ {
163+ break;
164+ }
165+ sendsize -= n;
166+ ppacket += n;
167+ }
168+ else
169+ {
170+ if (result < 0 && errno == EINTR)
171+ {
172+ continue;
173+ }
174+ break;
175+ }
176+ }
177+ return ret;
178+}
179+
180+/* low level receive */
181+static int
182+receive_data (SOCKET handle, unsigned char *p, int nsize)
183+{
184+ while (nsize > 0)
185+ {
186+ int result;
187+ fd_set rfds;
188+ struct timeval tmout;
189+ tmout.tv_sec = 1;
190+ tmout.tv_usec = 0;
191+ FD_ZERO (&rfds);
192+ FD_SET (handle, &rfds);
193+ result = select (handle + 1, &rfds, NULL, NULL, &tmout);
194+ if (result > 0)
195+ {
196+ int n = recv (handle, p, nsize, 0);
197+ if (n == -1)
198+ {
199+ if (errno == EINTR)
200+ {
201+ continue;
202+ }
203+ break;
204+ }
205+ if (!n)
206+ {
207+ break;
208+ }
209+ p += n;
210+ nsize -= n;
211+ }
212+ else
213+ {
214+ if (result < 0 && errno == EINTR)
215+ {
216+ continue;
217+ }
218+ break;
219+ }
220+ }
221+ return nsize ? -1 : 0;
222+}
223+
224+/* receive compress packet */
225+int
226+receive_packet_c (SOCKET handle, unsigned char *ppacket, int nsize)
227+{
228+ int ret = -1;
229+ unsigned char recvbuffer[PACKET_DATA_MAX];
230+ unsigned char uncompbuffer[PACKET_DATA_MAX];
231+ unsigned char buf[2];
232+ if (receive_data (handle, buf, 2) == 0)
233+ {
234+ int n = buf[1];
235+ n += (int) (buf[0] & 0xc0) << 2;
236+ if (n)
237+ {
238+ if (receive_data (handle, recvbuffer, n) == 0)
239+ {
240+ int nwk;
241+ nwk = uncompress (recvbuffer, uncompbuffer, n);
242+ if (nwk > nsize)
243+ {
244+ nwk = nsize;
245+ }
246+ memcpy (ppacket + 2, uncompbuffer, nwk);
247+ *(ppacket + 1) = nwk & 0xff;
248+ *ppacket = buf[0] & 0x3f;
249+ *ppacket |= (nwk & 0x300) >> 2;
250+ ret = 0;
251+ }
252+ }
253+ else
254+ {
255+ *ppacket = buf[0];
256+ *(ppacket + 1) = buf[1];
257+ ret = 0;
258+ }
259+ }
260+ return ret;
261+}
262+
263+
264+
265+/* EOF */
--- trunk/ctlsock.h (nonexistent)
+++ trunk/ctlsock.h (revision 1)
@@ -0,0 +1,19 @@
1+#ifndef CONTROL_SOCKET_HEADER
2+#define CONTROL_SOCKET_HEADER
3+
4+typedef struct session_data
5+ { /* server session data */
6+ SOCKET handle; /* socket handle */
7+ unsigned long addr; /* client address */
8+ unsigned short port; /* client port */
9+ }
10+SESSION;
11+
12+/* prototypes */
13+extern SOCKET makesocket (int port, unsigned long addr, int socktype);
14+extern int cutsocket (SOCKET handle);
15+extern int waitconnect (SOCKET handle, SESSION * psession);
16+extern SOCKET connectsocket (int port, unsigned long addr, int socktype);
17+
18+#endif
19+/* EOF */
--- trunk/port.h (nonexistent)
+++ trunk/port.h (revision 1)
@@ -0,0 +1,67 @@
1+#ifndef PORT_HEADER
2+#define PORT_HEADER
3+
4+#if defined(UNIX)
5+#ifdef __linux__
6+#define LINUX
7+#define HAVE_SIGACTION
8+#define HAVE_SIGALRM
9+#define USE_FORK
10+#endif
11+
12+#include <unistd.h>
13+#include <sys/types.h>
14+#include <sys/time.h>
15+#include <sys/socket.h>
16+#include <netinet/in.h>
17+#include <netinet/tcp.h>
18+#include <arpa/inet.h>
19+#include <netdb.h>
20+
21+#define init_socket_interface()
22+#define cleanup_socket_interface()
23+
24+#define closesocket close
25+typedef int SOCKET;
26+#define INVALID_SOCKET (-1)
27+
28+#ifdef TCP_MAXSEG
29+/* minimum segment size */
30+#define REQ_SEGMENT_SIZE 512
31+#endif
32+
33+#elif defined(MAKEWIN32)
34+#define STRICT
35+#include <windows.h>
36+#include <stdio.h>
37+#include <mbstring.h>
38+#include <process.h>
39+
40+/* if your compiler hasn't _beginthread,you define MAKETHREAD by your hand */
41+/* here ! */
42+
43+/* default setting */
44+#ifndef MAKETHREAD
45+#define MAKETHREAD(f,a) _beginthread ((f),64 * 1024,(a))
46+#endif
47+#ifndef ENDTHREAD
48+#define ENDTHREAD() _endthread ()
49+#endif
50+
51+#define init_socket_interface() {\
52+ WSADATA sockdata;\
53+ if(WSAStartup(MAKEWORD(1,1),&sockdata)) {\
54+ fputs("EVAC:winsock fail\n",stderr); exit(255); }\
55+ }
56+#define cleanup_socket_interface() {\
57+ WSACleanup(); }
58+#else
59+#error NEED enviroment-type!
60+#endif
61+
62+#ifndef DEFAULT_PROTOCOL
63+#define DEFAULT_PROTOCOL 0
64+#endif
65+
66+#endif
67+/* EOF */
--- trunk/pktio.h (nonexistent)
+++ trunk/pktio.h (revision 1)
@@ -0,0 +1,8 @@
1+
2+
3+extern int send_packet_c (SOCKET handle, unsigned char *ppacket, int nsize);
4+extern int receive_packet_c (SOCKET handle,
5+ unsigned char *ppacket, int nsize);
6+
7+
8+/* EOF */
--- trunk/Makefile (nonexistent)
+++ trunk/Makefile (revision 1)
@@ -0,0 +1,30 @@
1+##Makefile for Hunter-online
2+CC=gcc
3+DEFINES=-DUNIX
4+#CFLAGS=-Wall -g $(DEFINES)
5+CFLAGS=-Wall -O $(DEFINES)
6+
7+SRCS=huntserv.c ctlsock.c pktio.c hunt.h pltio.h ctlsock.h port.h
8+
9+all: huntserv
10+
11+clean:
12+ -rm *~ core *.o
13+
14+distclean:
15+ -rm *~ core *.o
16+ -rm h-user h-bbs h-map h-mail.* huntserv
17+
18+huntserv : huntserv.o ctlsock.o pktio.o
19+ $(CC) $(CFLAGS) -o huntserv huntserv.o ctlsock.o pktio.o
20+
21+
22+ctlsock.o : ctlsock.c ctlsock.h port.h
23+
24+pktio.o : pktio.c hunt.h pktio.h ctlsock.h port.h
25+
26+huntserv.o : huntserv.c hunt.h pktio.h ctlsock.h port.h
27+
28+
29+
30+#EOF
--- trunk/huntserv.c (nonexistent)
+++ trunk/huntserv.c (revision 1)
@@ -0,0 +1,11491 @@
1+#include "port.h"
2+#include <stdio.h>
3+#include <stdlib.h>
4+#include <string.h>
5+#include <signal.h>
6+#include <time.h>
7+#include <errno.h>
8+#ifdef USE_FORK
9+#include <sys/wait.h>
10+#endif
11+#include "ctlsock.h"
12+#include "hunt.h"
13+#include "pktio.h"
14+
15+/* Game feature */
16+#define USE_SAVEMAP
17+#define USE_AUTOSAVE
18+#define USE_MAIL
19+#define USE_BBS
20+#define USE_STRONGANIMAL
21+
22+/* defines */
23+#define PATCH_LEVEL_STRING ""
24+#ifndef SERVERPOLL_MSEC
25+#define SERVERPOLL_MSEC 100
26+#endif
27+#ifndef DATA_DIR
28+#define DATA_DIR "./"
29+#endif
30+#define USER_DATA_FILE "h-user"
31+#define WEAPON_DATA_FILE "h-weapon"
32+#define ITEM_DATA_FILE "h-item"
33+#define ANIMAL_DATA_FILE "h-animal"
34+#define INIT_DATA_FILE "h-setup"
35+#ifdef USE_SAVEMAP
36+#define SYSMAP_DATA_FILE "h-map"
37+#endif
38+#ifdef USE_BBS
39+#define BBS_DATA_FILE "h-bbs"
40+#endif
41+#ifndef HEARNEAR_DISTANCE
42+#define HEARNEAR_DISTANCE 10
43+#endif
44+#ifndef SELLINSHOP_LIMIT
45+#define SELLINSHOP_LIMIT 8
46+#endif
47+#ifndef USERSHOP_LIMIT
48+#define USERSHOP_LIMIT 10
49+#endif
50+#ifndef ANIMAL_SLOT_MAX
51+#define ANIMAL_SLOT_MAX 10
52+#endif
53+#ifndef HUNTER_SPEAK_RATE
54+#define HUNTER_SPEAK_RATE 10
55+#endif
56+#ifndef OBSERVER_SPEAK_RATE
57+#define OBSERVER_SPEAK_RATE 10
58+#endif
59+#ifndef HIRENPC_SPEAK_RATE
60+#define HIRENPC_SPEAK_RATE 10
61+#endif
62+#ifndef ANIMAL_MORAL_PANIC
63+#define ANIMAL_MORAL_PANIC 50
64+#endif
65+#ifndef ANIMAL_MORAL_NORMAL
66+#define ANIMAL_MORAL_NORMAL 100
67+#endif
68+#ifndef ANIMAL_MORAL_LIMIT
69+#define ANIMAL_MORAL_LIMIT 200
70+#endif
71+#ifndef ANIMAL_RATE_ANGRY
72+#define ANIMAL_RATE_ANGRY 50
73+#endif
74+#ifndef ANIMAL_MORAL_WHENKILL
75+#define ANIMAL_MORAL_WHENKILL 10
76+#endif
77+#ifndef ANIMAL_SEARCH_RANGE
78+#define ANIMAL_SEARCH_RANGE 10
79+#endif
80+#ifndef ANIMAL_RECOVER_COUNT
81+#define ANIMAL_RECOVER_COUNT 1800
82+#endif
83+#ifndef NPC_COUNTERATTACK_COUNT
84+#define NPC_COUNTERATTACK_COUNT 300
85+#endif
86+#ifndef ARREST_LIMIT
87+#define ARREST_LIMIT 20
88+#endif
89+#ifdef USE_STRONGANIMAL
90+#ifndef ANIMAL_HP_LIMIT
91+#define ANIMAL_HP_LIMIT 1000000L
92+#endif
93+#ifndef ANIMAL_MORAL_LIMIT
94+#define ANIMAL_MORAL_LIMIT 10000
95+#endif
96+#ifndef ANIMAL_FIRE_LIMIT
97+#define ANIMAL_FIRE_LIMIT 10000
98+#endif
99+#endif /* USE_STRONGANIMAL */
100+
101+#ifdef MAKEWIN32
102+/* Win32 enviroment feature */
103+#define USE_W32THREAD
104+#endif
105+
106+#ifdef USE_FORK
107+#define SENDPACKET(u,p,s) send_pipe ((u),(p),(s))
108+#endif
109+#ifdef USE_W32THREAD
110+#define SENDPACKET(u,p,s) send_thread ((u),(p),(s))
111+#endif
112+#ifndef SENDPACKET
113+#define SENDPACKET(u,p,s) send_packet_c (User[(u)].session.handle,(p),(s))
114+#endif
115+
116+#define CUTTAIL(s) cut_tail(s,USERNAME_LEN)
117+
118+#define ALLOCATE_CHUNK 16
119+#define BUFFER_SIZE 256
120+#define MESG_BUFFER 256
121+#ifdef USE_FORK
122+#define SENDPIPE_QUEUE_MAX 200
123+#endif
124+
125+/*********************************/
126+static const char ServerInfo[] =
127+ "[Hunter-online Version 3.00 alpha" PATCH_LEVEL_STRING "]";
128+static int NowRunning = 0;
129+static SOCKET mainSocket = INVALID_SOCKET;
130+static fd_set mainFDS;
131+#ifdef MAKEWIN32
132+static HANDLE hEnd;
133+static HANDLE hThread;
134+#endif
135+
136+struct location
137+{
138+ int x;
139+ int y;
140+};
141+
142+enum target_type
143+{
144+ TargetUser,
145+ TargetNpc,
146+ TargetAnimal,
147+ TargetNone
148+};
149+
150+typedef struct animal_data
151+{
152+ int n;
153+ char name[ANIMALNAME_LEN];
154+ unsigned long hp;
155+ unsigned moral;
156+ unsigned speed;
157+ unsigned value;
158+ unsigned rate;
159+ unsigned w_power;
160+ unsigned w_rate;
161+ int forsell_item;
162+ int eatmeat;
163+ int pattern;
164+ int charm_rate;
165+}
166+ANIMALDATA;
167+
168+#ifdef USE_MAIL
169+#define MAIL_BOX_LIMIT 20
170+#define MAIL_LINE_LIMIT 50
171+typedef struct mail_data
172+{
173+ int readflag;
174+ int fromuser;
175+ int line;
176+ time_t timestamp;
177+ char subject[PACKET_DATA_MAX];
178+ char message[MAIL_LINE_LIMIT][PACKET_DATA_MAX];
179+}
180+MAILDATA;
181+#endif
182+
183+#ifdef USE_W32THREAD
184+#define W32MSG_QUEUE_MAX 200
185+typedef struct w32msg_queue
186+{
187+ int read_pos;
188+ int write_pos;
189+ int count;
190+ HANDLE hend;
191+ unsigned char data[W32MSG_QUEUE_MAX][PACKET_DATA_MAX];
192+}
193+W32MSG_QUEUE;
194+#endif
195+
196+typedef struct user_info
197+{
198+ char name[USERNAME_LEN];
199+ char password[PASSWORD_LEN];
200+ enum usertype_t
201+ {
202+ Hunter,
203+ Observer,
204+ TypeMax
205+ }
206+ c_type;
207+ SESSION session;
208+ unsigned long idletimer;
209+ unsigned long score;
210+ unsigned long hp;
211+ unsigned long hungry;
212+ int speed;
213+ int speed_count;
214+ unsigned char weapon[WEAPON_MAX];
215+ unsigned short bullette[WEAPON_MAX];
216+ int reload[WEAPON_MAX];
217+ unsigned char item[ITEM_MAX];
218+ unsigned short itemcount[ITEM_MAX];
219+ int lastuser;
220+ enum target_type lastuser_type;
221+ unsigned char direction;
222+ struct location pos;
223+ unsigned char wk_direction;
224+ struct location wk_pos;
225+ unsigned long maybearrest;
226+ unsigned crime_level;
227+ unsigned arrest_count;
228+ enum move_t
229+ {
230+ NoMove,
231+ MoveForward,
232+ MoveBackward,
233+ MoveLeft,
234+ MoveRight,
235+ MoveMax
236+ }
237+ move;
238+ enum move_t move_bkup;
239+ enum action_t
240+ {
241+ NoAction,
242+ Fire1,
243+ Fire2,
244+ UseItem1,
245+ UseItem2,
246+ UseItem3,
247+ UseItem4,
248+ PickUp,
249+ Pay,
250+ BuyWeapon,
251+ BuyItem,
252+ Who,
253+ RequestWeapon,
254+ RequestItem,
255+ StoreAnimal,
256+ StoreWeapon,
257+ StoreItem,
258+ DiscardWeapon,
259+ DiscardItem,
260+ ListMyShop,
261+ DropWeapon,
262+ DropItem,
263+ ListMyAnimal,
264+ DoSay,
265+ DoTell,
266+ DoBroadcast,
267+ DoWriteMesg,
268+ DoChangeShopName,
269+ DoChangeAnimalName,
270+ DoDestroyShop,
271+ ListLiveAnimal,
272+#ifdef USE_MAIL
273+ ListMyMail,
274+ ReadMyMail,
275+ DeleteMyMail,
276+#ifdef USE_BBS
277+ ListBBS,
278+ ReadBBS,
279+#endif
280+#endif
281+ ActionMax
282+ }
283+ action;
284+ int wk_for_action;
285+ unsigned long lwk_for_action;
286+ char mesg_for_action[PACKET_DATA_MAX];
287+ enum status_t
288+ {
289+ Healthy,
290+ Arrested,
291+ Shopping
292+ }
293+ status;
294+ int cloak_count; /* count of cloaking */
295+ int hold_count; /* count of no moving */
296+ struct myshop_t
297+ { /* shop data */
298+ int build;
299+ char name[USERNAME_LEN];
300+ struct location pos;
301+ unsigned char list[2][SELLINSHOP_LIMIT];
302+ unsigned leftuse[2][SELLINSHOP_LIMIT];
303+ unsigned count[2][SELLINSHOP_LIMIT];
304+ unsigned long cost[2][SELLINSHOP_LIMIT];
305+ }
306+ myshop[USERSHOP_LIMIT];
307+ int animal_slot;
308+ ANIMALDATA *lastPickupAnimal[ANIMAL_SLOT_MAX];
309+ int ride_pattern;
310+ char higemesg[HIGEMESG_LEN];
311+ unsigned char statusinfo[PACKET_MAX]; /* backup for status info */
312+ int statusinfosize;
313+ unsigned char mapdata[PACKET_MAX]; /* backup for map data */
314+ int mapdatasize;
315+#ifdef USE_FORK
316+ pid_t send_pid;
317+ int send_handle;
318+#endif
319+#ifdef USE_W32THREAD
320+ HANDLE w32thread;
321+ W32MSG_QUEUE *w32queue;
322+#endif
323+#ifdef USE_MAIL
324+ int t_target; /* transaction of send */
325+ MAILDATA *t_mail; /* transaction of send */
326+ MAILDATA *mail[MAIL_BOX_LIMIT]; /* mailbox */
327+#endif
328+}
329+USERINFO;
330+
331+typedef struct npc_t
332+{ /* NPC */
333+ enum npctype_t
334+ {
335+ NpcHunter,
336+ NpcObserver,
337+ NpcHige
338+ }
339+ c_type;
340+ char name[USERNAME_LEN];
341+ int number;
342+ int owner_user;
343+ unsigned long hp;
344+ int speed;
345+ int weapon;
346+ unsigned bullette;
347+ int reload;
348+ int search;
349+ int attack;
350+ struct location pos;
351+ int direction;
352+ int ntarget_user;
353+ enum target_type t_type;
354+ int nochangelock_count;
355+ int speed_count;
356+ int hold_count;
357+ int moral_limit;
358+}
359+NPCINFO;
360+
361+typedef struct animal_info
362+{
363+ ANIMALDATA *pdata;
364+ char name[USERNAME_LEN];
365+ unsigned long hp;
366+ unsigned moral;
367+ unsigned w_power;
368+ int speed;
369+#ifdef USE_STRONGANIMAL
370+ unsigned long hp_org;
371+ unsigned moral_org;
372+ unsigned w_power_org;
373+ int speed_org;
374+#endif
375+ struct location pos;
376+ int reload;
377+ enum charm_type
378+ {
379+ CharmPosition,
380+ CharmUser,
381+ CharmNpc,
382+ CharmAnimal
383+ }
384+ charm;
385+ unsigned charmcount;
386+ struct location charm_pos;
387+ int ntarget;
388+ int search;
389+ int ntime;
390+ int hold_count;
391+ int recover_count;
392+ int owner_user;
393+}
394+ANIMALINFO;
395+
396+enum bullet_type
397+{
398+ BulletNormal,
399+ BulletCharm,
400+ BulletAP,
401+ BulletTypeMax
402+};
403+
404+typedef struct weapon_info
405+{
406+ char name[WEAPONNAME_LEN];
407+ unsigned firepower;
408+ unsigned moral;
409+ unsigned range;
410+ unsigned rate;
411+ unsigned reduce;
412+ unsigned speed;
413+ unsigned bullette;
414+ unsigned long cost;
415+ unsigned forhunter;
416+ unsigned npc_rate;
417+ enum bullet_type b_type;
418+}
419+WEAPONINFO;
420+
421+typedef struct item_info
422+{
423+ char name[ITEMNAME_LEN];
424+ enum item_type
425+ {
426+ Noeffect,
427+ Heal,
428+ Tree,
429+ Charm,
430+ Score,
431+ Damage,
432+ AnimalRadar,
433+ HumanRadar,
434+ Invisible,
435+ BuildShop,
436+ DigHole,
437+ Vehicle,
438+ Food,
439+ HireNpc,
440+ ItemTypeMax
441+ }
442+ id;
443+ unsigned effect;
444+ unsigned count;
445+ unsigned long cost;
446+ unsigned forhunter;
447+ unsigned pattern;
448+}
449+ITEMINFO;
450+
451+/* in game data */
452+static USERINFO *User;
453+static NPCINFO *Npc;
454+static ANIMALINFO *Animal;
455+static ANIMALDATA *AnimalData = NULL;
456+static int AnimalDataLimit = 0;
457+static WEAPONINFO *Weapon = NULL;
458+static int WeaponLimit = 0;
459+static ITEMINFO *Item = NULL;
460+static int ItemLimit = 0;
461+
462+static int *AnimalTypeTable = NULL;
463+static int AnimalTypeTotal;
464+static int *ForHunterWeapon;
465+static int ForHunterWeaponLimit;
466+static int *ForObserverWeapon;
467+static int ForObserverWeaponLimit;
468+static int *ForHunterItem;
469+static int ForHunterItemLimit;
470+static int *ForObserverItem;
471+static int ForObserverItemLimit;
472+static int *NpcHunterWeaponTable;
473+static int NpcHunterWeaponTotal;
474+static int *NpcObserverWeaponTable;
475+static int NpcObserverWeaponTotal;
476+
477+#if defined(USE_MAIL) && defined(USE_BBS)
478+#define BBS_BOX_LIMIT 40
479+
480+static MAILDATA *BBSdata[BBS_BOX_LIMIT];
481+#endif
482+
483+/* system variable */
484+static int MapWidth = 50;
485+static int MapHeight = 50;
486+static int UserSpeed = 7;
487+static int MaxTimeoutValue = 18000;
488+static int TreeHP = 210;
489+static unsigned long HpLimit = 2000L;
490+static unsigned long HpBase = 1000L;
491+static unsigned long HungryLimit = 1000L;
492+static unsigned long HungryBase = 100L;
493+static int TurnPerHungry = 100;
494+static unsigned DamageWhenHungry = 100;
495+static int RateRoad = 70;
496+static int RateBoxInItem = 50;
497+static int TurnPerSpawnAnimal = 3000;
498+static int TurnPerSpawnNpc = 6000;
499+static int JailPositionX = 0;
500+static int JailPositionY = 0;
501+static int ShopLimit = 25;
502+static unsigned long TurnPerSpawnTree = 12 * 36000;
503+static int TreasureLimit = 10;
504+static unsigned CrimeMurder = 3000;
505+static unsigned CrimeNpcMurder = 1000;
506+static unsigned ArrestPass = 1000;
507+static unsigned ArrestAnyone = 10000;
508+static int DigCount = 20;
509+static int HoldCount = 100;
510+static int CharmCount = 300;
511+static int AngryCount = 100;
512+static int TurnPerSend = 4;
513+static int UserLimit = 100;
514+static int AnimalLimit = 50;
515+static int AnimalInitLimit = 20;
516+static int NpcLimit = 50;
517+static int NpcLimitForSystem = 10;
518+static int NpcInitLimit = 3;
519+static int NpcRateHunter = 50;
520+static int NpcRateAverageSpeed = 70;
521+static int NpcAverageSpeed = 10;
522+static int NpcSpeedBase = 6;
523+static int NpcSpeedMin = 1;
524+static int NpcSpeedMax = 5;
525+static int NpcHpMin = 500;
526+static int NpcHpMax = 1500;
527+static int NpcSearchMin = 6;
528+static int NpcSearchMax = 10;
529+static int NpcAttackMin = 3;
530+static int NpcAttackMax = 6;
531+static int TurnPerDecArrest = 50;
532+static int DecArrest = 50;
533+static unsigned long TurnPerJailCount = 6000;
534+#ifdef USE_AUTOSAVE
535+static unsigned long TurnPerSave = 24 * 36000;
536+#endif
537+static int TurnPerAnimalHeal = 300;
538+static int HireableNpcType = HIREABLE_NPC_TYPE;
539+static char makeUserKey[PASSWORD_LEN] = "HUNTER1234567890";
540+static char rootPassword[PASSWORD_LEN] = "HunterMasterCode";
541+
542+/* map data */
543+struct map_block
544+{
545+ unsigned char id;
546+#define MAP_INVALID 0x00
547+#define MAP_ROAD 0x01
548+#define MAP_ID_FIRST 0x02
549+#define MAP_TREE 0x02
550+#define MAP_ROCK 0x03
551+#define MAP_ID_LAST 0x03
552+#define MAP_MASK 0x03
553+#define MAP_THERE_ITEM 0x80
554+#define MAP_THERE_SHOP 0x40
555+#define MAP_THERE_ANIMAL 0x20
556+#define MAP_THERE_WALL 0x10
557+#define MAP_THERE_HOLE 0x08
558+#define MAP_THERE_NPC 0x04
559+#define MAP_HIGH_MASK 0xfc
560+#define MAP_NOT_MOVE (MAP_THERE_ANIMAL|MAP_THERE_NPC|MAP_THERE_WALL)
561+#define MAP_NOT_SAVE ~(MAP_THERE_ANIMAL|MAP_THERE_NPC)
562+ unsigned char player;
563+ unsigned char animal;
564+ unsigned char owner;
565+};
566+static struct map_block *Map = NULL;
567+
568+#define MAP(x,y) (Map+(x)+(y)*MapWidth)
569+#define INVALID_MAP(x,y) (Map+(x)+(y)*MapWidth)->id &= ~MAP_MASK
570+
571+/* for bullette movement */
572+struct bullet_t
573+{
574+ struct bullet_t *pnext;
575+ struct bullet_t *pprev;
576+ WEAPONINFO *pweapon;
577+ struct location pos;
578+ int direction;
579+ int nuser;
580+ enum target_type t_type;
581+ int ndamage;
582+ int ndistance;
583+ int ntime;
584+ struct location fire_pos;
585+};
586+static struct bullet_t *pBullet = NULL;
587+
588+/* for usermade itembox */
589+struct itembox_t
590+{ /* itembox made by user */
591+ struct itembox_t *pprev;
592+ struct itembox_t *pnext;
593+ struct location pos;
594+ int isitem;
595+ int n;
596+ unsigned left;
597+ char message[PACKET_DATA_MAX];
598+};
599+static struct itembox_t *UserMadeItem = NULL;
600+
601+/* movement vector */
602+static int FWVectorX[] = {
603+ 0, -1, 1, 0
604+};
605+
606+static int FWVectorY[] = {
607+ -1, 0, 0, 1
608+};
609+
610+static int RGVectorX[] = {
611+ 1, 0, 0, -1
612+};
613+
614+static int RGVectorY[] = {
615+ 0, -1, 1, 0
616+};
617+
618+/* relatively direction */
619+#define REL_DIRECTION_HERE 0
620+#define REL_DIRECTION_N 1
621+#define REL_DIRECTION_NE 2
622+#define REL_DIRECTION_E 3
623+#define REL_DIRECTION_SE 4
624+#define REL_DIRECTION_S 5
625+#define REL_DIRECTION_SW 6
626+#define REL_DIRECTION_W 7
627+#define REL_DIRECTION_NW 8
628+
629+static const char *RelDirection[] = {
630+ "Here", "North", "NorthEast", "East", "SouthEast", "South",
631+ "SouthWest", "West", "NorthWest"
632+};
633+
634+static const int RelDirectionValue[] = {
635+ DIRECTION_N,
636+ DIRECTION_N,
637+ DIRECTION_E,
638+ DIRECTION_E,
639+ DIRECTION_E,
640+ DIRECTION_S,
641+ DIRECTION_W,
642+ DIRECTION_W,
643+ DIRECTION_W,
644+};
645+
646+static const int RelDirectionValue2[] = {
647+ DIRECTION_N,
648+ DIRECTION_N,
649+ DIRECTION_N,
650+ DIRECTION_E,
651+ DIRECTION_S,
652+ DIRECTION_S,
653+ DIRECTION_S,
654+ DIRECTION_W,
655+ DIRECTION_N,
656+};
657+
658+static unsigned char TargetDirection[][4] = {
659+ {HCLIT_PLAYER_N, HCLIT_PLAYER_W, HCLIT_PLAYER_E, HCLIT_PLAYER_S},
660+ {HCLIT_GUARD_N, HCLIT_GUARD_W, HCLIT_GUARD_E, HCLIT_GUARD_S},
661+ {HCLIT_NPC_N, HCLIT_NPC_W, HCLIT_NPC_E, HCLIT_NPC_S}
662+};
663+
664+/* for NPC name */
665+static const char NpcHunters[][USERNAME_LEN] = {
666+ "Hunter Red ",
667+ "Hunter Blue ",
668+ "Hunter Green ",
669+ "Hunter Yellow ",
670+ "Hunter Pink ",
671+ "Hunter Black ",
672+ "Hunter Richard ",
673+ "Hunter Jones ",
674+ "Hunter Okita ",
675+ "Hunter Big bear "
676+};
677+
678+static int NpcHuntersN = sizeof (NpcHunters) / USERNAME_LEN;
679+
680+static const char NpcGuards[][USERNAME_LEN] = {
681+ "Guard Red ",
682+ "Guard Blue ",
683+ "Guard Green ",
684+ "Guard Yellow ",
685+ "Guard Pink ",
686+ "Guard Black ",
687+ "Guard Gates ",
688+ "Guard Deathler ",
689+ "Guard Kodai ",
690+ "Guard Shark "
691+};
692+
693+static int NpcGuardsN = sizeof (NpcGuards) / USERNAME_LEN;
694+
695+static const char NpcHiges[][USERNAME_LEN] = {
696+ "Private Saito ",
697+ "NAV Sima ",
698+ "Pilot Katou ",
699+ "Pilot Yamamoto ",
700+ "COM Aihara ",
701+ "Medic Sado ",
702+ "Commander Domel ",
703+ "Commander Okita ",
704+ "Warrior Zero ",
705+ "Captain Harlock "
706+};
707+
708+static int NpcHigesN = sizeof (NpcHiges) / USERNAME_LEN;
709+
710+
711+/************************************************/
712+#ifdef MAKEWIN32
713+/* convert Shift-jis to EUC-JP */
714+static const char *
715+convertC2H (char *p, int nlen)
716+{
717+ int i;
718+ const char *pret = p;
719+ for (i = 0; i < nlen && *p != '\0'; i++)
720+ {
721+ unsigned char c = *p++;
722+ if (_ismbblead (c))
723+ {
724+ /* first byte of KANJI */
725+ unsigned char c2 = *p++;
726+ unsigned int njis = _mbcjmstojis (((unsigned int) c << 8) | c2);
727+ njis |= 0x8080; /* MBS up */
728+ *(p - 2) = (unsigned char) (njis >> 8);
729+ *(p - 1) = (unsigned char) njis;
730+ i++;
731+ }
732+ }
733+ return pret;
734+}
735+
736+/* convert EUC-JP to Shift-jis */
737+static const char *
738+convertH2C (char *p, int nlen)
739+{
740+ int i;
741+ const char *pret = p;
742+ for (i = 0; i < nlen && *p != '\0'; i++)
743+ {
744+ unsigned char c = *p++;
745+ if (c & 0x80)
746+ {
747+ /* first byte of KANJI */
748+ unsigned char c2 = *p++;
749+ unsigned int neuc = ((unsigned int) c << 8) | c2;
750+ unsigned int nsjis = _mbcjistojms (neuc & 0x7f7f);
751+ *(p - 2) = (unsigned char) (nsjis >> 8);
752+ *(p - 1) = (unsigned char) nsjis;
753+ i++;
754+ }
755+ }
756+ return pret;
757+}
758+
759+#endif /* MAKEWIN32 */
760+
761+/* search item for name */
762+static int
763+SearchItemForName (const char *p)
764+{
765+ int i;
766+ for (i = 0; i < ItemLimit; i++)
767+ {
768+ if (!strncmp (Item[i].name, p, ITEMNAME_LEN))
769+ {
770+ return i;
771+ }
772+ }
773+ return 0;
774+}
775+
776+/* cut tail space (this use fixed single buffer!) */
777+static const char *
778+cut_tail (const char *p, int n)
779+{
780+ static char work[MESG_BUFFER];
781+ int i;
782+ for (i = 0; i < n && *p != '\0'; i++)
783+ {
784+ work[i] = *p++;
785+ }
786+ for (i--; i >= 0; i--)
787+ {
788+ if (work[i] != ' ')
789+ {
790+ break;
791+ }
792+ }
793+ work[i + 1] = '\0';
794+ return work;
795+}
796+
797+#ifdef USE_MAIL
798+/* make new mail */
799+static MAILDATA *
800+NewMail (void)
801+{
802+ MAILDATA *ret = malloc (sizeof (MAILDATA));
803+ if (ret == NULL)
804+ {
805+ perror ("malloc");
806+ fputs ("EVAC:not enoght to mail memory!", stderr);
807+ exit (2);
808+ }
809+ memset (ret, 0, sizeof (MAILDATA));
810+ ret->timestamp = time (NULL);
811+ return ret;
812+}
813+
814+/* free mail */
815+static void
816+FreeMail (MAILDATA * p)
817+{
818+ free (p);
819+ return;
820+}
821+
822+/* add message to mail */
823+static int
824+AddMessageMail (MAILDATA * p, char *packet)
825+{
826+ int ret = -1;
827+ if (p->line < MAIL_LINE_LIMIT)
828+ {
829+ int n = *packet;
830+ memcpy (p->message[p->line++], packet, n + 1);
831+ ret = 0;
832+ }
833+ return ret;
834+}
835+
836+/* reorder user mail box */
837+static void
838+ReorderMailbox (int nuser)
839+{
840+ int i;
841+ for (i = 0; i < MAIL_BOX_LIMIT - 1; i++)
842+ {
843+ if (User[nuser].mail[i] == NULL)
844+ {
845+ int j;
846+ for (j = i + 1; j < MAIL_BOX_LIMIT; j++)
847+ {
848+ if (User[nuser].mail[j] != NULL)
849+ {
850+ break;
851+ }
852+ }
853+ if (j == MAIL_BOX_LIMIT)
854+ {
855+ /* no more mail */
856+ break;
857+ }
858+ User[nuser].mail[i] = User[nuser].mail[j];
859+ User[nuser].mail[j] = NULL;
860+ }
861+ else if (User[User[nuser].mail[i]->fromuser].name[0] == '\0')
862+ {
863+ /* this user is vanished */
864+ int j;
865+ FreeMail (User[nuser].mail[i]);
866+ for (j = i + 1; j < MAIL_BOX_LIMIT; j++)
867+ {
868+ if (User[nuser].mail[j] != NULL)
869+ {
870+ break;
871+ }
872+ }
873+ if (j == MAIL_BOX_LIMIT)
874+ {
875+ /* no more mail */
876+ break;
877+ }
878+ User[nuser].mail[i] = User[nuser].mail[j];
879+ User[nuser].mail[j] = NULL;
880+ }
881+ }
882+ return;
883+}
884+
885+/* add mail to user */
886+static int
887+AddMailUser (int nuser, MAILDATA * p)
888+{
889+ int ret = -1;
890+ int i;
891+ for (i = 0; i < MAIL_BOX_LIMIT; i++)
892+ {
893+ if (User[nuser].mail[i] == NULL)
894+ {
895+ break;
896+ }
897+ }
898+ if (i < MAIL_BOX_LIMIT)
899+ {
900+ User[nuser].mail[i] = p;
901+ ret = 0;
902+ }
903+ return ret;
904+}
905+
906+/* check new mail */
907+static int
908+CheckNewMail (int nuser)
909+{
910+ int i;
911+ for (i = 0; i < MAIL_BOX_LIMIT; i++)
912+ {
913+ if (User[nuser].mail[i] != NULL && User[nuser].mail[i]->readflag == 0)
914+ {
915+ return 1;
916+ }
917+ }
918+ return 0;
919+}
920+
921+#ifdef USE_BBS
922+/* reorder bbs box */
923+static void
924+ReorderBBSbox (void)
925+{
926+ int i;
927+ for (i = 0; i < BBS_BOX_LIMIT - 1; i++)
928+ {
929+ if (BBSdata[i] == NULL)
930+ {
931+ int j;
932+ for (j = i + 1; j < BBS_BOX_LIMIT; j++)
933+ {
934+ if (BBSdata[j] != NULL)
935+ {
936+ break;
937+ }
938+ }
939+ if (j == BBS_BOX_LIMIT)
940+ {
941+ /* no more mail */
942+ break;
943+ }
944+ BBSdata[i] = BBSdata[j];
945+ BBSdata[j] = NULL;
946+ }
947+ else if (User[BBSdata[i]->fromuser].name[0] == '\0')
948+ {
949+ /* this user is vanished */
950+ int j;
951+ FreeMail (BBSdata[i]);
952+ for (j = i + 1; j < BBS_BOX_LIMIT; j++)
953+ {
954+ if (BBSdata[j] != NULL)
955+ {
956+ break;
957+ }
958+ }
959+ if (j == BBS_BOX_LIMIT)
960+ {
961+ /* no more mail */
962+ break;
963+ }
964+ BBSdata[i] = BBSdata[j];
965+ BBSdata[j] = NULL;
966+ }
967+ }
968+ return;
969+}
970+#endif /* USE_BBS */
971+#endif /* USE_MAIL */
972+
973+#ifdef USE_SAVEMAP
974+/* search weapon for name */
975+static int
976+SearchWeaponForName (const char *p)
977+{
978+ int i;
979+ for (i = 0; i < WeaponLimit; i++)
980+ {
981+ if (!strncmp (Weapon[i].name, p, WEAPONNAME_LEN))
982+ {
983+ return i;
984+ }
985+ }
986+ return 0;
987+}
988+#endif /* USE_SAVEMAP */
989+
990+/* search weapon for name and user_type */
991+static int
992+SearchWeaponForNameType (const char *p, enum usertype_t c_type)
993+{
994+ int i;
995+ for (i = 0; i < WeaponLimit; i++)
996+ {
997+ if (c_type == Hunter && Weapon[i].forhunter == 0)
998+ {
999+ continue;
1000+ }
1001+ else if (c_type == Observer && Weapon[i].forhunter == 1)
1002+ {
1003+ continue;
1004+ }
1005+ if (!strncmp (Weapon[i].name, p, WEAPONNAME_LEN))
1006+ {
1007+ return i;
1008+ }
1009+ }
1010+ return 0;
1011+}
1012+
1013+/* tiny random generator */
1014+static int
1015+getrand (int nmin, int nmax)
1016+{
1017+ int n = nmax - nmin + 1;
1018+ /* too simple random value. it need more better code.;) */
1019+ int nbase = RAND_MAX / n;
1020+ int nceil = nbase * n;
1021+ int r;
1022+ do
1023+ {
1024+ r = rand ();
1025+ }
1026+ while (r >= nceil);
1027+ return r / nbase + nmin;
1028+}
1029+
1030+/* get relative direction */
1031+static int
1032+rel_dir (int n)
1033+{
1034+ return (getrand (1, 10) & 1) ? RelDirectionValue[n] : RelDirectionValue2[n];
1035+}
1036+
1037+#ifdef USE_FORK
1038+/* signal handler for send process */
1039+static void
1040+sighandler_send (int nsig)
1041+{
1042+ switch (nsig)
1043+ {
1044+ case SIGINT:
1045+#ifdef SIGHUP
1046+ case SIGHUP:
1047+#endif
1048+ case SIGTERM:
1049+ case SIGUSR1:
1050+ _exit (1);
1051+#ifdef SIGPIPE
1052+ case SIGPIPE:
1053+ break;
1054+#endif
1055+ }
1056+ return;
1057+}
1058+
1059+/* send process main */
1060+static void
1061+send_process (int handle, SOCKET hsock)
1062+{
1063+ unsigned char *packet_queue;
1064+ int queue_max = SENDPIPE_QUEUE_MAX;
1065+ int count = 0;
1066+ int wp = 0;
1067+ int rp = 0;
1068+ packet_queue = malloc (queue_max * PACKET_MAX);
1069+ if (packet_queue == NULL)
1070+ {
1071+ fputs ("EVAC CHILD:not enough to queue memory\n", stderr);
1072+ return;
1073+ }
1074+ /* receive from pipe,send to socket handle */
1075+ for (;;)
1076+ {
1077+ int result;
1078+ fd_set fds;
1079+ struct timeval tmout;
1080+ if (count == queue_max)
1081+ {
1082+ /* full queue */
1083+ fputs ("EVAC CHILD:full queue\n", stderr);
1084+ return;
1085+ }
1086+ if (count)
1087+ {
1088+ tmout.tv_sec = 0;
1089+ tmout.tv_usec = 100000;
1090+ }
1091+ else
1092+ {
1093+ tmout.tv_sec = 0;
1094+ tmout.tv_usec = 0;
1095+ }
1096+ FD_ZERO (&fds);
1097+ FD_SET (handle, &fds);
1098+ result = select (handle + 1, &fds, NULL, NULL, &tmout);
1099+ if (result > 0 || count == 0)
1100+ {
1101+ int n = 0;
1102+ unsigned char *packet = packet_queue + wp * PACKET_MAX;
1103+ while (n < PACKET_MAX)
1104+ {
1105+ int nread = read (handle, packet + n, PACKET_MAX - n);
1106+ if (nread == -1)
1107+ {
1108+ if (errno == EINTR)
1109+ {
1110+ continue;
1111+ }
1112+ /* error ! */
1113+ perror ("read");
1114+ fputs ("EVAC CHILD:occur error while reading pipe\n",
1115+ stderr);
1116+ return;
1117+ }
1118+ if (!nread)
1119+ {
1120+ /* uhmm. what's happen? */
1121+ fputs ("EVAC CHILD:can't read pipe\n", stderr);
1122+ return;
1123+ }
1124+ n += nread;
1125+ }
1126+ wp = (wp + 1) % queue_max;
1127+ count++;
1128+ }
1129+ else
1130+ {
1131+ if (result < 0)
1132+ {
1133+ if (errno == EINTR)
1134+ {
1135+ continue;
1136+ }
1137+ fputs ("EVAC CHILD:occur error while wait for pipe\n", stderr);
1138+ return;
1139+ }
1140+ }
1141+ while (count)
1142+ {
1143+ tmout.tv_sec = 0;
1144+ tmout.tv_usec = 100000;
1145+ FD_ZERO (&fds);
1146+ FD_SET (hsock, &fds);
1147+ result = select (hsock + 1, NULL, &fds, NULL, &tmout);
1148+ if (result > 0)
1149+ {
1150+ unsigned char *packet = packet_queue + rp * PACKET_MAX;
1151+ int n = packet[1];
1152+ n += (int) (packet[0] & 0xc0) << 2;
1153+ if (send_packet_c (hsock, packet, n))
1154+ {
1155+ /* occur error! */
1156+ fputs ("EVAC CHILD:occur error while sending data\n",
1157+ stderr);
1158+ return;
1159+ }
1160+ rp = (rp + 1) % queue_max;
1161+ count--;
1162+ }
1163+ else
1164+ {
1165+ if (result < 0)
1166+ {
1167+ if (errno == EINTR)
1168+ {
1169+ continue;
1170+ }
1171+ fputs ("EVAC CHILD:occur error while wait for send\n",
1172+ stderr);
1173+ return;
1174+ }
1175+ /* timeout. queue packet */
1176+ break;
1177+ }
1178+ }
1179+ }
1180+ return;
1181+}
1182+
1183+/* create send process */
1184+static void
1185+create_send_process (int nuser, SOCKET hsock)
1186+{
1187+ pid_t child;
1188+ int handle[2];
1189+ if (pipe (handle))
1190+ {
1191+ perror ("pipe");
1192+ fputs ("EVAC:create send pipe fail!\n", stderr);
1193+ exit (1);
1194+ }
1195+ if ((child = fork ()) == 0)
1196+ {
1197+ /* this is child process */
1198+#ifdef HAVE_SIGACTION
1199+ struct sigaction sa;
1200+ sa.sa_handler = sighandler_send;
1201+ sa.sa_flags = 0;
1202+ sigemptyset (&sa.sa_mask);
1203+ sigaction (SIGINT, &sa, NULL);
1204+#ifdef SIGHUP
1205+ sigaction (SIGHUP, &sa, NULL);
1206+#endif
1207+ sigaction (SIGTERM, &sa, NULL);
1208+#ifdef SIGPIPE
1209+ sigaction (SIGPIPE, &sa, NULL);
1210+#endif
1211+ sigaction (SIGUSR1, &sa, NULL);
1212+#else /* HAVE_SIGACTION */
1213+ signal (SIGINT, sighandler_send);
1214+#ifdef SIGHUP
1215+ signal (SIGHUP, sighandler_send);
1216+#endif
1217+ signal (SIGTERM, sighandler_send);
1218+#ifdef SIGPIPE
1219+ signal (SIGPIPE, sighandler_send);
1220+#endif
1221+ signal (SIGUSR1, sighandler_send);
1222+#endif /* HAVE_SIGACTION */
1223+ send_process (handle[0], hsock);
1224+ _exit (0);
1225+ }
1226+ else
1227+ {
1228+ close (handle[0]);
1229+ User[nuser].send_pid = child;
1230+ User[nuser].send_handle = handle[1];
1231+ }
1232+ return;
1233+}
1234+
1235+/* delete send_process */
1236+static void
1237+delete_send_process (int nuser)
1238+{
1239+ if (User[nuser].send_handle != -1)
1240+ {
1241+ close (User[nuser].send_handle);
1242+ kill (User[nuser].send_pid, SIGUSR1);
1243+ waitpid (User[nuser].send_pid, NULL, 0);
1244+ User[nuser].send_pid = 0;
1245+ User[nuser].send_handle = -1;
1246+ }
1247+ return;
1248+}
1249+
1250+/* send via fork_process */
1251+static int
1252+send_pipe (int nuser, unsigned char *packet, int n)
1253+{
1254+ int death_counter = 10; /* counter for death */
1255+ for (;;)
1256+ {
1257+ int result;
1258+ fd_set wfds;
1259+ struct timeval tmout;
1260+ tmout.tv_sec = 0;
1261+ tmout.tv_usec = 50000;
1262+ FD_ZERO (&wfds);
1263+ FD_SET (User[nuser].send_handle, &wfds);
1264+ result =
1265+ select (User[nuser].send_handle + 1, NULL, &wfds, NULL, &tmout);
1266+ if (result > 0)
1267+ {
1268+ unsigned char buffer[PACKET_MAX];
1269+ int i;
1270+ memcpy (buffer, packet, n + 2);
1271+ buffer[1] = n % 256;
1272+ buffer[0] &= 0x3f;
1273+ buffer[0] |= (n & 0x300) >> 2;
1274+ i = 0;
1275+ while (i < PACKET_MAX)
1276+ {
1277+ int nwrite =
1278+ write (User[nuser].send_handle, buffer + i, PACKET_MAX - i);
1279+ if (nwrite == -1)
1280+ {
1281+ if (errno == EINTR)
1282+ {
1283+ if (--death_counter == 0)
1284+ {
1285+ /* death time ! */
1286+ return -1;
1287+ }
1288+ continue;
1289+ }
1290+ /* uhmm. perhaps network error */
1291+ return -1;
1292+ }
1293+ if (!nwrite)
1294+ {
1295+ /* uhmm. perhaps child process died */
1296+ return -1;
1297+ }
1298+ i += nwrite;
1299+ }
1300+ return 0;
1301+ }
1302+ else
1303+ {
1304+ /* uhmm. perhaps network error */
1305+ if (result < 0 && errno == EINTR)
1306+ {
1307+ if (--death_counter == 0)
1308+ {
1309+ /* death time ! */
1310+ return -1;
1311+ }
1312+ continue;
1313+ }
1314+ }
1315+ return -1;
1316+ }
1317+}
1318+
1319+#endif /* USE_FORK */
1320+
1321+#ifdef USE_W32THREAD
1322+/* send message thread */
1323+static void
1324+send_message_queue_thread (void *arg)
1325+{
1326+ USERINFO *user = (USERINFO *) arg;
1327+ W32MSG_QUEUE *queue = user->w32queue;
1328+ SOCKET hsock = user->session.handle;
1329+ while (WaitForSingleObject (queue->hend, 0) == WAIT_TIMEOUT)
1330+ {
1331+ if (queue->count)
1332+ {
1333+ int result;
1334+ fd_set fds;
1335+ struct timeval tmout;
1336+ while (queue->count)
1337+ {
1338+ tmout.tv_sec = 0;
1339+ tmout.tv_usec = 100000;
1340+ FD_ZERO (&fds);
1341+ FD_SET (hsock, &fds);
1342+ result = select (hsock + 1, NULL, &fds, NULL, &tmout);
1343+ if (result > 0)
1344+ {
1345+ unsigned char *packet = queue->data[queue->read_pos];
1346+ int n = packet[1];
1347+ n += (int) (packet[0] & 0xc0) << 2;
1348+ if (send_packet_c (hsock, packet, n))
1349+ {
1350+ /* occur error! */
1351+ fputs ("EVAC CHILD:occur error while sending data\n",
1352+ stderr);
1353+ ENDTHREAD ();
1354+ }
1355+ queue->read_pos = (queue->read_pos + 1) % W32MSG_QUEUE_MAX;
1356+ queue->count--;
1357+ }
1358+ else
1359+ {
1360+ if (result < 0)
1361+ {
1362+ if (errno == EINTR)
1363+ {
1364+ continue;
1365+ }
1366+ fputs ("EVAC THREAD:occur error while wait for send\n",
1367+ stderr);
1368+ ENDTHREAD ();
1369+ }
1370+ /* timeout. queue packet */
1371+ break;
1372+ }
1373+ }
1374+ }
1375+ else
1376+ {
1377+ Sleep (1);
1378+ }
1379+ }
1380+ ENDTHREAD ();
1381+}
1382+
1383+/* create send thread */
1384+static void
1385+create_send_message_queue_thread (int nuser)
1386+{
1387+ User[nuser].w32queue = malloc (sizeof (W32MSG_QUEUE));
1388+ if (User[nuser].w32queue == NULL)
1389+ {
1390+ perror ("malloc");
1391+ fputs ("EVAC:not enough to queue thread memory\n", stderr);
1392+ exit (1);
1393+ }
1394+ User[nuser].w32queue->count = 0;
1395+ User[nuser].w32queue->read_pos = 0;
1396+ User[nuser].w32queue->write_pos = 0;
1397+ User[nuser].w32queue->hend = CreateEvent (NULL, TRUE, FALSE, NULL);
1398+ if (User[nuser].w32queue->hend == NULL)
1399+ {
1400+ fputs ("EVAC:can't create event handle for queue thread\n", stderr);
1401+ exit (1);
1402+ }
1403+ User[nuser].w32thread =
1404+ (HANDLE) MAKETHREAD (send_message_queue_thread, &User[nuser]);
1405+ return;
1406+}
1407+
1408+/* delete send thread */
1409+static void
1410+delete_send_message_queue_thread (int nuser)
1411+{
1412+ SetEvent (User[nuser].w32queue->hend);
1413+ WaitForSingleObject (User[nuser].w32thread, INFINITE);
1414+ CloseHandle (User[nuser].w32thread);
1415+ User[nuser].w32thread = NULL;
1416+ CloseHandle (User[nuser].w32queue->hend);
1417+ free (User[nuser].w32queue);
1418+ User[nuser].w32queue = NULL;
1419+ return;
1420+}
1421+
1422+/* send via message queue thread */
1423+static int
1424+send_thread (int nuser, unsigned char *packet, int n)
1425+{
1426+ int death_counter = 10; /* counter for death */
1427+ W32MSG_QUEUE *queue = User[nuser].w32queue;
1428+ while (WaitForSingleObject (User[nuser].w32thread, 0))
1429+ {
1430+ if (queue->count < W32MSG_QUEUE_MAX)
1431+ {
1432+ unsigned char *buffer = queue->data[queue->write_pos];
1433+ int i;
1434+ for (i = 0; i < n + 2; i++)
1435+ {
1436+ buffer[i] = packet[i];
1437+ }
1438+ buffer[1] = n % 256;
1439+ buffer[0] &= 0x3f;
1440+ buffer[0] |= (n & 0x300) >> 2;
1441+ queue->write_pos = (queue->write_pos + 1) % W32MSG_QUEUE_MAX;
1442+ queue->count++;
1443+ return 0;
1444+ }
1445+ else
1446+ {
1447+ /* uhmm. full queue */
1448+ if (--death_counter == 0)
1449+ {
1450+ /* death! */
1451+ break;
1452+ }
1453+ }
1454+ }
1455+ return -1;
1456+}
1457+
1458+/* kill all thread */
1459+static void
1460+kill_all_send_message_queue_thread (void)
1461+{
1462+ int i;
1463+ for (i = 0; i < UserLimit; i++)
1464+ {
1465+ if (User[i].name[0] != '\0')
1466+ {
1467+ if (User[i].w32thread != NULL)
1468+ {
1469+ SetEvent (User[i].w32queue->hend);
1470+ }
1471+ }
1472+ }
1473+ return;
1474+}
1475+
1476+#endif /* USE_W32THREAD */
1477+
1478+#ifdef USE_SAVEMAP
1479+
1480+/* save map data and shop data */
1481+static int
1482+SaveMapData (const char *p)
1483+{
1484+ int ret = -1;
1485+ FILE *optr = fopen (p, "w");
1486+ if (optr != NULL)
1487+ {
1488+ int i;
1489+ fputs ("#SNAP0000--This is Hunter-online data file. DO NOT MODIFY!\n",
1490+ optr);
1491+ fprintf (optr, "%d,%d,%d,%d,%d,%d,%d\n",
1492+ MapWidth, MapHeight, UserLimit,
1493+ USERSHOP_LIMIT, SELLINSHOP_LIMIT, JailPositionX,
1494+ JailPositionY);
1495+ for (i = 0; i < MapWidth * MapHeight; i++)
1496+ {
1497+ fprintf (optr, "%02X %02X %02X\n",
1498+ Map[i].id & MAP_NOT_SAVE, Map[i].player, Map[i].owner);
1499+ }
1500+ for (i = 1; i < UserLimit; i++)
1501+ {
1502+ int j;
1503+ if (User[i].name[0] == '\0')
1504+ {
1505+ fputs ("0\n", optr);
1506+ for (j = 0; j < USERSHOP_LIMIT; j++)
1507+ {
1508+ fputs ("0,0,0, \n", optr);
1509+ }
1510+ }
1511+ else
1512+ {
1513+ fprintf (optr, "%d\n", User[i].crime_level);
1514+ for (j = 0; j < USERSHOP_LIMIT; j++)
1515+ {
1516+ char namebuf[BUFFER_SIZE];
1517+ memcpy (namebuf, User[i].myshop[j].name, USERNAME_LEN);
1518+#ifdef MAKEWIN32
1519+ convertH2C (namebuf, USERNAME_LEN);
1520+#endif
1521+ fprintf (optr, "%d,%d,%d,%-.16s\n",
1522+ User[i].myshop[j].build,
1523+ User[i].myshop[j].pos.x, User[i].myshop[j].pos.y,
1524+ namebuf);
1525+ if (User[i].myshop[j].build)
1526+ {
1527+ int k;
1528+ for (k = 0; k < SELLINSHOP_LIMIT; k++)
1529+ {
1530+ memcpy (namebuf,
1531+ Weapon[User[i].myshop[j].list[0][k]].name,
1532+ WEAPONNAME_LEN);
1533+#ifdef MAKEWIN32
1534+ convertH2C (namebuf, WEAPONNAME_LEN);
1535+#endif
1536+ fprintf (optr, "%-.32s,%u,%u,%lu\n",
1537+ namebuf,
1538+ User[i].myshop[j].leftuse[0][k],
1539+ User[i].myshop[j].count[0][k],
1540+ User[i].myshop[j].cost[0][k]);
1541+ }
1542+ for (k = 0; k < SELLINSHOP_LIMIT; k++)
1543+ {
1544+ memcpy (namebuf,
1545+ Item[User[i].myshop[j].list[1][k]].name,
1546+ ITEMNAME_LEN);
1547+#ifdef MAKEWIN32
1548+ convertH2C (namebuf, ITEMNAME_LEN);
1549+#endif
1550+ fprintf (optr, "%-.32s,%u,%u,%lu\n",
1551+ namebuf,
1552+ User[i].myshop[j].leftuse[1][k],
1553+ User[i].myshop[j].count[1][k],
1554+ User[i].myshop[j].cost[1][k]);
1555+ }
1556+ }
1557+ }
1558+ }
1559+ }
1560+ ret = 0;
1561+ fclose (optr);
1562+ }
1563+ return ret;
1564+}
1565+
1566+/* load map data */
1567+static int
1568+load_sys_map (FILE * iptr)
1569+{
1570+ char work[BUFFER_SIZE];
1571+ int i;
1572+ puts ("load map data...");
1573+ for (i = 0; i < MapWidth * MapHeight; i++)
1574+ {
1575+ unsigned c[3];
1576+ if (fgets (work, sizeof (work), iptr) == NULL ||
1577+ sscanf (work, "%02X %02X %02X", &c[0], &c[1], &c[2]) != 3)
1578+ {
1579+ /* error */
1580+ return -1;
1581+ }
1582+ Map[i].id = c[0];
1583+ Map[i].player = 0;
1584+ Map[i].animal = 0;
1585+ Map[i].owner = c[2];
1586+ }
1587+ return 0;
1588+}
1589+
1590+/* load one user-shop-data */
1591+static int
1592+load_sys_user_one (FILE * iptr, int nuser)
1593+{
1594+ int i;
1595+ char work[BUFFER_SIZE];
1596+ if (fgets (work, sizeof (work), iptr) == NULL ||
1597+ sscanf (work, "%d", &User[nuser].crime_level) != 1)
1598+ {
1599+ return -1;
1600+ }
1601+ for (i = 0; i < USERSHOP_LIMIT; i++)
1602+ {
1603+ int j;
1604+ char namebuf[BUFFER_SIZE];
1605+ if (fgets (work, sizeof (work), iptr) == NULL ||
1606+ sscanf (work, "%d,%d,%d,%[^\n\r]",
1607+ &User[nuser].myshop[i].build,
1608+ &User[nuser].myshop[i].pos.x, &User[nuser].myshop[i].pos.y,
1609+ namebuf) != 4)
1610+ {
1611+ return -1;
1612+ }
1613+#ifdef MAKEWIN32
1614+ convertC2H (namebuf, USERNAME_LEN);
1615+#endif
1616+ for (j = 0; j < USERNAME_LEN && namebuf[0] != '\0'; j++)
1617+ {
1618+ User[nuser].myshop[i].name[j] = namebuf[j];
1619+ }
1620+ for (; j < USERNAME_LEN; j++)
1621+ {
1622+ User[nuser].myshop[i].name[j] = ' ';
1623+ }
1624+ if (User[nuser].myshop[i].build)
1625+ {
1626+ for (j = 0; j < SELLINSHOP_LIMIT; j++)
1627+ {
1628+ if (fgets (work, sizeof (work), iptr) == NULL ||
1629+ sscanf (work, "%[^,],%u,%u,%lu",
1630+ namebuf,
1631+ &User[nuser].myshop[i].leftuse[0][j],
1632+ &User[nuser].myshop[i].count[0][j],
1633+ &User[nuser].myshop[i].cost[0][j]) != 4)
1634+ {
1635+ return -1;
1636+ }
1637+#ifdef MAKEWIN32
1638+ convertC2H (namebuf, WEAPONNAME_LEN);
1639+#endif
1640+ User[nuser].myshop[i].list[0][j] =
1641+ SearchWeaponForName (namebuf);
1642+ if (User[nuser].myshop[i].list[0][j] == 0)
1643+ {
1644+ User[nuser].myshop[i].count[0][j] = 0;
1645+ }
1646+ }
1647+ for (j = 0; j < SELLINSHOP_LIMIT; j++)
1648+ {
1649+ if (fgets (work, sizeof (work), iptr) == NULL ||
1650+ sscanf (work, "%[^,],%u,%u,%lu",
1651+ namebuf,
1652+ &User[nuser].myshop[i].leftuse[1][j],
1653+ &User[nuser].myshop[i].count[1][j],
1654+ &User[nuser].myshop[i].cost[1][j]) != 4)
1655+ {
1656+ return -1;
1657+ }
1658+#ifdef MAKEWIN32
1659+ convertC2H (namebuf, ITEMNAME_LEN);
1660+#endif
1661+ User[nuser].myshop[i].list[1][j] = SearchItemForName (namebuf);
1662+ if (User[nuser].myshop[i].list[1][j] == 0)
1663+ {
1664+ User[nuser].myshop[i].count[1][j] = 0;
1665+ }
1666+ }
1667+ }
1668+ }
1669+ return 0;
1670+}
1671+
1672+/* load user-shop data */
1673+static int
1674+load_sys_user (FILE * iptr)
1675+{
1676+ int i;
1677+ puts ("load user-shop data...");
1678+ for (i = 1; i < UserLimit; i++)
1679+ {
1680+ if (User[i].name[0] != '\0')
1681+ {
1682+ if (load_sys_user_one (iptr, i))
1683+ {
1684+ /* can't read user info */
1685+ memset (User[i].myshop, 0, sizeof (User[i].myshop));
1686+ User[i].crime_level = 0;
1687+ return -1;
1688+ }
1689+ }
1690+ }
1691+ return 0;
1692+}
1693+
1694+/* load map data and shop data */
1695+static int
1696+LoadMapData (const char *p)
1697+{
1698+ int ret = -1;
1699+ FILE *iptr = fopen (p, "r");
1700+ if (iptr != NULL)
1701+ {
1702+ char work[BUFFER_SIZE];
1703+ if (fgets (work, sizeof (work), iptr) == NULL ||
1704+ memcmp (work, "#SNAP0000", 9))
1705+ {
1706+ /* mismatch version */
1707+ fputs ("Warning:system data file version mismatch\n", stderr);
1708+ }
1709+ else
1710+ {
1711+ int width;
1712+ int height;
1713+ int usermax;
1714+ int usershop_max;
1715+ int sell_max;
1716+ int jailx;
1717+ int jaily;
1718+ if (fgets (work, sizeof (work), iptr) != NULL &&
1719+ sscanf (work, "%d,%d,%d,%d,%d,%d,%d",
1720+ &width, &height, &usermax,
1721+ &usershop_max, &sell_max, &jailx, &jaily) == 7)
1722+ {
1723+ if (width != MapWidth || height != MapHeight ||
1724+ usermax != UserLimit || usershop_max != USERSHOP_LIMIT ||
1725+ sell_max != SELLINSHOP_LIMIT ||
1726+ jailx != JailPositionX || jaily != JailPositionY)
1727+ {
1728+ /* uhmm. mismatch paramater */
1729+ fputs ("Warnning: this system data can't load!\n", stderr);
1730+ }
1731+ else
1732+ {
1733+ if (load_sys_map (iptr) || load_sys_user (iptr))
1734+ {
1735+ /* cannot load data */
1736+ fputs ("Warnning: this system data is broken!\n",
1737+ stderr);
1738+ }
1739+ else
1740+ {
1741+ ret = 0;
1742+ }
1743+ }
1744+ }
1745+ }
1746+ fclose (iptr);
1747+ }
1748+ return ret;
1749+}
1750+
1751+#endif /* USE_SAVEMAP */
1752+
1753+/* adjust position */
1754+static void
1755+adjust_pos (int *px, int *py)
1756+{
1757+ int x = *px;
1758+ int y = *py;
1759+ if (x < 0)
1760+ {
1761+ x = MapWidth + x;
1762+ }
1763+ else if (x >= MapWidth)
1764+ {
1765+ x -= MapWidth;
1766+ }
1767+ if (y < 0)
1768+ {
1769+ y = MapHeight + y;
1770+ }
1771+ else if (y >= MapHeight)
1772+ {
1773+ y -= MapHeight;
1774+ }
1775+ *px = x;
1776+ *py = y;
1777+ return;
1778+}
1779+
1780+/* calculate delta x */
1781+static void
1782+calculate_delta_x (int x, int gx, int *dx1, int *dx2)
1783+{
1784+ if (gx > x)
1785+ {
1786+ *dx1 = gx - x;
1787+ *dx2 = x + MapWidth - gx;
1788+ }
1789+ else if (gx < x)
1790+ {
1791+ *dx1 = gx + MapWidth - x;
1792+ *dx2 = x - gx;
1793+ }
1794+ else
1795+ {
1796+ *dx1 = *dx2 = 0;
1797+ }
1798+ return;
1799+}
1800+
1801+/* calculate delta y */
1802+static void
1803+calculate_delta_y (int y, int gy, int *dy1, int *dy2)
1804+{
1805+ if (gy > y)
1806+ {
1807+ *dy1 = gy - y;
1808+ *dy2 = y + MapHeight - gy;
1809+ }
1810+ else if (gy < y)
1811+ {
1812+ *dy1 = gy + MapHeight - y;
1813+ *dy2 = y - gy;
1814+ }
1815+ else
1816+ {
1817+ *dy1 = *dy2 = 0;
1818+ }
1819+ return;
1820+}
1821+
1822+/* get relative position */
1823+static int
1824+get_rel_position_in (int dx1, int dx2, int dy1, int dy2)
1825+{
1826+ if (dx1 < dx2)
1827+ {
1828+ /* is east ... */
1829+ if (dy1 < dy2)
1830+ {
1831+ /* is south */
1832+ return REL_DIRECTION_SE;
1833+ }
1834+ else if (dy1 > dy2)
1835+ {
1836+ /* is north */
1837+ return REL_DIRECTION_NE;
1838+ }
1839+ else
1840+ {
1841+ return REL_DIRECTION_E;
1842+ }
1843+ }
1844+ else if (dx1 > dx2)
1845+ {
1846+ /* is west ... */
1847+ if (dy1 < dy2)
1848+ {
1849+ /* is south */
1850+ return REL_DIRECTION_SW;
1851+ }
1852+ else if (dy1 > dy2)
1853+ {
1854+ /* is north */
1855+ return REL_DIRECTION_NW;
1856+ }
1857+ else
1858+ {
1859+ return REL_DIRECTION_W;
1860+ }
1861+ }
1862+ else
1863+ {
1864+ if (dy1 < dy2)
1865+ {
1866+ /* is south */
1867+ return REL_DIRECTION_S;
1868+ }
1869+ else if (dy1 > dy2)
1870+ {
1871+ /* is north */
1872+ return REL_DIRECTION_N;
1873+ }
1874+ else
1875+ {
1876+ return REL_DIRECTION_HERE;
1877+ }
1878+ }
1879+}
1880+
1881+/* calculate target distance(not precise) */
1882+static int
1883+get_rel_distance_in (int dx1, int dx2, int dy1, int dy2)
1884+{
1885+ if (dx1 > dx2)
1886+ {
1887+ dx1 = dx2;
1888+ }
1889+ if (dy1 > dy2)
1890+ {
1891+ dy1 = dy2;
1892+ }
1893+ return dx1 + dy1;
1894+}
1895+
1896+static int
1897+get_rel_distance (int x, int y, int gx, int gy)
1898+{
1899+ int dx1;
1900+ int dx2;
1901+ int dy1;
1902+ int dy2;
1903+ calculate_delta_x (x, gx, &dx1, &dx2);
1904+ calculate_delta_y (y, gy, &dy1, &dy2);
1905+ return get_rel_distance_in (dx1, dx2, dy1, dy2);
1906+}
1907+
1908+/* get animal-slot */
1909+static ANIMALDATA *
1910+get_animal_slot (int nuser)
1911+{
1912+ ANIMALDATA *ret = User[nuser].lastPickupAnimal[0];
1913+ int i;
1914+ if (User[nuser].animal_slot > 1)
1915+ {
1916+ for (i = 1; i < User[nuser].animal_slot; i++)
1917+ {
1918+ User[nuser].lastPickupAnimal[i - 1] =
1919+ User[nuser].lastPickupAnimal[i];
1920+ }
1921+ }
1922+ User[nuser].lastPickupAnimal[User[nuser].animal_slot - 1] = NULL;
1923+ return ret;
1924+}
1925+
1926+/* put animal_slot */
1927+static void
1928+put_animal_slot (int nuser, ANIMALDATA * p)
1929+{
1930+ int i;
1931+ for (i = User[nuser].animal_slot - 1; i > 0; i--)
1932+ {
1933+ User[nuser].lastPickupAnimal[i] = User[nuser].lastPickupAnimal[i - 1];
1934+ }
1935+ User[nuser].lastPickupAnimal[0] = p;
1936+ return;
1937+}
1938+
1939+/* clear animal slot */
1940+static void
1941+clear_animal_slot (int nuser)
1942+{
1943+ int i;
1944+ for (i = 0; i < User[nuser].animal_slot; i++)
1945+ {
1946+ User[nuser].lastPickupAnimal[i] = NULL;
1947+ }
1948+ return;
1949+}
1950+
1951+/* get npc weapon */
1952+static int
1953+get_npc_weapon (enum npctype_t c_type)
1954+{
1955+ int *table;
1956+ int *list;
1957+ int nlimit;
1958+ int total;
1959+ int n;
1960+ int i;
1961+ switch (c_type)
1962+ {
1963+ case NpcHunter:
1964+ table = NpcHunterWeaponTable;
1965+ total = NpcHunterWeaponTotal;
1966+ list = ForHunterWeapon;
1967+ nlimit = ForHunterWeaponLimit;
1968+ break;
1969+ case NpcObserver:
1970+ table = NpcObserverWeaponTable;
1971+ total = NpcObserverWeaponTotal;
1972+ list = ForObserverWeapon;
1973+ nlimit = ForObserverWeaponLimit;
1974+ break;
1975+ default:
1976+ return 0;
1977+ }
1978+ n = getrand (1, total);
1979+ for (i = 0; i < nlimit; i++)
1980+ {
1981+ if (table[i] >= n)
1982+ {
1983+ return list[i];
1984+ }
1985+ }
1986+ return 0;
1987+}
1988+
1989+/* make new map data */
1990+static unsigned char
1991+make_newmapdata (void)
1992+{
1993+ if (getrand (1, 100) <= RateRoad)
1994+ {
1995+ return MAP_ROAD;
1996+ }
1997+ else
1998+ {
1999+ return getrand (MAP_ID_FIRST, MAP_ID_LAST);
2000+ }
2001+}
2002+
2003+/* new itembox */
2004+static void
2005+addUserItemBox (int x, int y, int isitem, int n, unsigned left,
2006+ const char *pstr)
2007+{
2008+ struct itembox_t *p = malloc (sizeof (struct itembox_t));
2009+ if (p == NULL)
2010+ {
2011+ /* oh,no. */
2012+ perror ("malloc");
2013+ fputs ("EVAC:not enough to itembox memory", stderr);
2014+ exit (1);
2015+ }
2016+ p->pprev = UserMadeItem;
2017+ p->pnext = NULL;
2018+ p->pos.x = x;
2019+ p->pos.y = y;
2020+ p->isitem = isitem;
2021+ p->n = n;
2022+ p->left = left;
2023+ if (pstr != NULL)
2024+ {
2025+ strncpy (p->message, pstr, sizeof (p->message));
2026+ }
2027+ else
2028+ {
2029+ memset (p->message, 0, sizeof (p->message));
2030+ }
2031+ if (UserMadeItem != NULL)
2032+ {
2033+ UserMadeItem->pnext = p;
2034+ }
2035+ UserMadeItem = p;
2036+ return;
2037+}
2038+
2039+/* get itembox */
2040+struct itembox_t *
2041+getUserItemBox (int x, int y)
2042+{
2043+ struct itembox_t *p = UserMadeItem;
2044+ while (p != NULL)
2045+ {
2046+ if (p->pos.x == x && p->pos.y == y)
2047+ {
2048+ /* found */
2049+ if (p == UserMadeItem)
2050+ {
2051+ UserMadeItem = p->pprev;
2052+ }
2053+ else
2054+ {
2055+ if (p->pprev != NULL)
2056+ {
2057+ p->pprev->pnext = p->pnext;
2058+ }
2059+ if (p->pnext != NULL)
2060+ {
2061+ p->pnext->pprev = p->pprev;
2062+ }
2063+ }
2064+ return p;
2065+ }
2066+ p = p->pprev;
2067+ }
2068+ return NULL;
2069+}
2070+
2071+/* Make new map */
2072+static void
2073+MakeNewMap (void)
2074+{
2075+ int i;
2076+ for (i = 0; i < MapWidth * MapHeight; i++)
2077+ {
2078+ if (Map[i].id & MAP_HIGH_MASK)
2079+ {
2080+ Map[i].id |= MAP_ROAD;
2081+ }
2082+ else
2083+ {
2084+ Map[i].id |= make_newmapdata ();
2085+ }
2086+ }
2087+ return;
2088+}
2089+
2090+/* create root user */
2091+static void
2092+makeRootUser (void)
2093+{
2094+ int i;
2095+ i = 0;
2096+ User[0].name[i++] = 'r';
2097+ User[0].name[i++] = 'o';
2098+ User[0].name[i++] = 'o';
2099+ User[0].name[i++] = 't';
2100+ for (; i < USERNAME_LEN; i++)
2101+ {
2102+ User[0].name[i] = ' ';
2103+ }
2104+ memcpy (User[0].password, rootPassword, PASSWORD_LEN);
2105+ User[0].c_type = Observer;
2106+ return;
2107+}
2108+
2109+/* initialize user information */
2110+static void
2111+InitializeUser (void)
2112+{
2113+ int i;
2114+ for (i = 0; i < UserLimit; i++)
2115+ {
2116+ int j;
2117+ User[i].session.handle = INVALID_SOCKET;
2118+ User[i].session.addr = 0;
2119+ User[i].session.port = 0;
2120+ User[i].idletimer = 0;
2121+ memset (User[i].name, 0, sizeof (User[i].name));
2122+ memset (User[i].password, 0, sizeof (User[i].password));
2123+ for (j = 0; j < USERSHOP_LIMIT; j++)
2124+ {
2125+ User[i].myshop[j].build = 0;
2126+ }
2127+#ifdef USE_MAIL
2128+ User[i].t_mail = NULL;
2129+ for (j = 0; j < MAIL_BOX_LIMIT; j++)
2130+ {
2131+ User[i].mail[j] = NULL;
2132+ }
2133+#endif
2134+ }
2135+ makeRootUser ();
2136+ return;
2137+}
2138+
2139+/* clear user */
2140+static void
2141+ClearUser (int userno)
2142+{
2143+ int x;
2144+ int y;
2145+
2146+ x = User[userno].pos.x;
2147+ y = User[userno].pos.y;
2148+ if (MAP (x, y)->player == userno + 1)
2149+ {
2150+ MAP (x, y)->player = 0;
2151+ }
2152+ return;
2153+}
2154+
2155+/* disconnect */
2156+static int
2157+DisconnectUser (int userno)
2158+{
2159+#if DEBUG
2160+ if (!(userno > 0 && userno < UserLimit))
2161+ {
2162+ return -1;
2163+ }
2164+#endif
2165+ if (User[userno].session.handle != INVALID_SOCKET)
2166+ {
2167+ char work[USERNAME_LEN];
2168+#ifdef USE_FORK
2169+ delete_send_process (userno);
2170+#endif
2171+#ifdef USE_W32THREAD
2172+ delete_send_message_queue_thread (userno);
2173+#endif
2174+ cutsocket (User[userno].session.handle);
2175+ FD_CLR (User[userno].session.handle, &mainFDS);
2176+ User[userno].session.handle = INVALID_SOCKET;
2177+ User[userno].session.addr = 0;
2178+ User[userno].session.port = 0;
2179+ memset (User[userno].statusinfo, 0, PACKET_MAX);
2180+ memset (User[userno].mapdata, 0, PACKET_MAX);
2181+ memcpy (work, User[userno].name, USERNAME_LEN);
2182+#ifdef MAKEWIN32
2183+ convertH2C (work, USERNAME_LEN);
2184+#endif
2185+ printf ("user(%d)[%-16.16s] logoff.\n", userno, work);
2186+ User[userno].idletimer = 0;
2187+ }
2188+ ClearUser (userno);
2189+ return 0;
2190+}
2191+
2192+/* search user */
2193+static int
2194+SearchUser (const char *pname)
2195+{
2196+ int i;
2197+ char work[USERNAME_LEN];
2198+ for (i = 0; i < USERNAME_LEN; i++)
2199+ {
2200+ if (*(pname + i) == '\0')
2201+ {
2202+ break;
2203+ }
2204+ work[i] = *(pname + i);
2205+ }
2206+ for (; i < USERNAME_LEN; i++)
2207+ {
2208+ work[i] = ' ';
2209+ }
2210+ for (i = 0; i < UserLimit; i++)
2211+ {
2212+ if (!memcmp (User[i].name, work, USERNAME_LEN))
2213+ {
2214+ return i;
2215+ }
2216+ }
2217+ return -1;
2218+}
2219+
2220+/* new user */
2221+static int
2222+NewUser (const char *pname)
2223+{
2224+ int i;
2225+ char work[USERNAME_LEN];
2226+ for (i = 0; i < USERNAME_LEN; i++)
2227+ {
2228+ if (*(pname + i) == '\0')
2229+ {
2230+ break;
2231+ }
2232+ work[i] = *(pname + i);
2233+ }
2234+ for (; i < USERNAME_LEN; i++)
2235+ {
2236+ work[i] = ' ';
2237+ }
2238+ for (i = 0; i < UserLimit; i++)
2239+ {
2240+ if (!memcmp (User[i].name, work, USERNAME_LEN))
2241+ {
2242+ /* double user */
2243+ return -2;
2244+ }
2245+ if (User[i].name[0] == '\0')
2246+ {
2247+ /* new user */
2248+ int j;
2249+ memcpy (User[i].name, work, USERNAME_LEN);
2250+ for (j = 0; j < USERSHOP_LIMIT; j++)
2251+ {
2252+ memcpy (User[i].myshop[j].name, User[i].name, USERNAME_LEN);
2253+ User[i].myshop[j].build = 0;
2254+ }
2255+ memset (User[i].password, 0, PASSWORD_LEN);
2256+ User[i].session.handle = INVALID_SOCKET;
2257+ User[i].idletimer = 0;
2258+ User[i].hp = 0;
2259+ User[i].score = 100;
2260+ User[i].speed = UserSpeed;
2261+ User[i].speed_count = 0;
2262+ memset (User[i].weapon, 0, sizeof (User[i].weapon));
2263+ memset (User[i].bullette, 0, sizeof (User[i].bullette));
2264+ memset (User[i].reload, 0, sizeof (User[i].reload));
2265+ memset (User[i].item, 0, sizeof (User[i].item));
2266+ memset (User[i].itemcount, 0, sizeof (User[i].itemcount));
2267+ User[i].direction = 0;
2268+ User[i].pos.x = 0;
2269+ User[i].pos.y = 0;
2270+ User[i].move = NoMove;
2271+ User[i].action = NoAction;
2272+ User[i].status = Healthy;
2273+ User[i].maybearrest = 0;
2274+ User[i].crime_level = 0;
2275+ User[i].arrest_count = 0;
2276+ User[i].cloak_count = 0;
2277+ User[i].animal_slot = 1;
2278+ for (j = 0; j < ANIMAL_SLOT_MAX; j++)
2279+ {
2280+ User[i].lastPickupAnimal[j] = NULL;
2281+ }
2282+ User[i].ride_pattern = 0;
2283+ memset (User[i].higemesg, 0, sizeof (User[i].higemesg));
2284+ memset (User[i].statusinfo, 0, PACKET_MAX);
2285+ memset (User[i].mapdata, 0, PACKET_MAX);
2286+#ifdef USE_MAIL
2287+ User[i].t_mail = NULL;
2288+ for (j = 0; j < MAIL_BOX_LIMIT; j++)
2289+ {
2290+ User[i].mail[j] = NULL;
2291+ }
2292+#endif
2293+#ifdef USE_FORK
2294+ User[i].send_pid = 0;
2295+ User[i].send_handle = -1;
2296+#endif
2297+#ifdef USE_W32THREAD
2298+ User[i].w32thread = NULL;
2299+ User[i].w32queue = NULL;
2300+#endif
2301+ return i;
2302+ }
2303+ }
2304+ /* no user */
2305+ return -1;
2306+}
2307+
2308+/* delete user */
2309+static int
2310+DeleteUser (int userno)
2311+{
2312+#if DEBUG
2313+ if (!(userno > 0 && userno < UserLimit))
2314+ {
2315+ return -1;
2316+ }
2317+#endif
2318+ if (userno == 0)
2319+ {
2320+ /* can't delete root user */
2321+ return -1;
2322+ }
2323+ if (User[userno].session.handle != INVALID_SOCKET)
2324+ {
2325+ DisconnectUser (userno);
2326+ }
2327+ memset (User[userno].name, 0, sizeof (User[userno].name));
2328+ memset (User[userno].password, 0, sizeof (User[userno].password));
2329+ return 0;
2330+}
2331+
2332+/* set activate information */
2333+static int
2334+ActivateUser (int userno)
2335+{
2336+ int x;
2337+ int y;
2338+ int need_repos = 0;
2339+#if DEBUG
2340+ if (!(userno > 0 && userno < UserLimit) || User[userno].name[0] == '\0')
2341+ {
2342+ return -1;
2343+ }
2344+#endif
2345+ if (User[userno].hp == 0)
2346+ {
2347+ /* reborn */
2348+ int j;
2349+ User[userno].hp = (userno == 0) ? HpLimit : HpBase;
2350+ User[userno].hungry = (userno == 0) ? HungryLimit : HungryBase;
2351+ memset (User[userno].weapon, 0, sizeof (User[userno].weapon));
2352+ memset (User[userno].bullette, 0, sizeof (User[userno].bullette));
2353+ memset (User[userno].item, 0, sizeof (User[userno].item));
2354+ memset (User[userno].itemcount, 0, sizeof (User[userno].itemcount));
2355+ User[userno].maybearrest = 0;
2356+ User[userno].crime_level = 0;
2357+ User[userno].arrest_count = 0;
2358+ User[userno].cloak_count = 0;
2359+ User[userno].hold_count = 0;
2360+ User[userno].speed = (userno == 0) ? 1 : UserSpeed;
2361+ User[userno].status = Healthy;
2362+ User[userno].animal_slot = (userno == 0) ? ANIMAL_SLOT_MAX : 1;
2363+ for (j = 0; j < ANIMAL_SLOT_MAX; j++)
2364+ {
2365+ User[userno].lastPickupAnimal[j] = NULL;
2366+ }
2367+ User[userno].ride_pattern = 0;
2368+ need_repos = 1;
2369+ }
2370+ x = User[userno].pos.x;
2371+ y = User[userno].pos.y;
2372+ if (User[userno].status != Arrested)
2373+ {
2374+ if (!need_repos &&
2375+ ((MAP (x, y)->id & MAP_NOT_MOVE) || MAP (x, y)->player))
2376+ {
2377+ need_repos = 1;
2378+ }
2379+ }
2380+ if (need_repos)
2381+ {
2382+ int i;
2383+ int posmax = 0;
2384+ int posx[USERSHOP_LIMIT];
2385+ int posy[USERSHOP_LIMIT];
2386+ for (i = 0; i < USERSHOP_LIMIT; i++)
2387+ {
2388+ if (User[userno].myshop[i].build)
2389+ {
2390+ x = User[userno].myshop[i].pos.x;
2391+ y = User[userno].myshop[i].pos.y;
2392+ if (MAP (x, y)->player == 0 && !(MAP (x, y)->id & MAP_NOT_MOVE))
2393+ {
2394+ /* ok */
2395+ posx[posmax] = x;
2396+ posy[posmax] = y;
2397+ posmax++;
2398+ }
2399+ }
2400+ }
2401+ if (posmax)
2402+ {
2403+ int n = 0;
2404+ if (posmax > 1)
2405+ {
2406+ n = getrand (0, posmax - 1);
2407+ }
2408+ x = posx[n];
2409+ y = posy[n];
2410+ need_repos = 0;
2411+ }
2412+ if (need_repos)
2413+ {
2414+ do
2415+ {
2416+ x = getrand (0, MapWidth - 1);
2417+ y = getrand (0, MapHeight - 1);
2418+ }
2419+ while (MAP (x, y)->player ||
2420+ (MAP (x, y)->id & (MAP_NOT_MOVE | MAP_THERE_SHOP)) ||
2421+ ((MAP (x, y)->id & MAP_MASK) == MAP_ROCK));
2422+ }
2423+ User[userno].pos.x = x;
2424+ User[userno].pos.y = y;
2425+ User[userno].direction = DIRECTION_N;
2426+ }
2427+ if (User[userno].status != Arrested)
2428+ {
2429+ MAP (x, y)->player = userno + 1;
2430+ }
2431+ if (MAP (x, y)->id & MAP_THERE_SHOP)
2432+ {
2433+ User[userno].status = Shopping;
2434+ }
2435+ User[userno].wk_direction = User[userno].direction;
2436+ memset (User[userno].reload, 0, sizeof (User[userno].reload));
2437+ User[userno].move = NoMove;
2438+ User[userno].action = NoAction;
2439+ User[userno].idletimer = 0;
2440+ User[userno].speed_count = 0;
2441+ User[userno].lastuser = -1;
2442+ User[userno].lastuser_type = TargetNone;
2443+ memset (User[userno].statusinfo, 0, PACKET_MAX);
2444+ memset (User[userno].mapdata, 0, PACKET_MAX);
2445+ return 0;
2446+}
2447+
2448+#ifdef USE_MAIL
2449+/* make mail prefix */
2450+static void
2451+make_mail_prefix (const char *puser, char *outbuffer)
2452+{
2453+ int i;
2454+ strncpy (outbuffer, puser, USERNAME_LEN);
2455+#ifdef MAKEWIN32
2456+ convertH2C (outbuffer, USERNAME_LEN);
2457+#endif
2458+ for (i = USERNAME_LEN - 1; i >= 0; i--)
2459+ {
2460+ if (outbuffer[i] != ' ')
2461+ {
2462+ break;
2463+ }
2464+ }
2465+ outbuffer[i + 1] = '\0';
2466+ return;
2467+}
2468+
2469+/* load mail data */
2470+static int
2471+LoadMail (int nuser, const char *prefix)
2472+{
2473+ FILE *iptr;
2474+ char fname[BUFFER_SIZE];
2475+ sprintf (fname, "%s/h-mail.%s", DATA_DIR, prefix);
2476+ iptr = fopen (fname, "r");
2477+ if (iptr != NULL)
2478+ {
2479+ unsigned nmax;
2480+ char work[BUFFER_SIZE];
2481+ if (fgets (work, sizeof (work), iptr) == NULL)
2482+ {
2483+ /* error */
2484+ fputs ("Warnning: can't read mail data!\n", stderr);
2485+ }
2486+ else if (!memcmp (work, "#M0100", 6))
2487+ {
2488+ if (fgets (work, sizeof (work), iptr) == NULL ||
2489+ sscanf (work, "%u", &nmax) != 1 || nmax > MAIL_BOX_LIMIT)
2490+ {
2491+ /* this file is broken */
2492+ fputs ("mail data file is broken.\n", stderr);
2493+ fclose (iptr);
2494+ return -1;
2495+ }
2496+ else
2497+ {
2498+ int i;
2499+ char namebuf[BUFFER_SIZE];
2500+ for (i = 0; i < nmax; i++)
2501+ {
2502+ MAILDATA *pmail = NewMail ();
2503+ unsigned long tstamp;
2504+ unsigned n;
2505+ int j;
2506+ if (fgets (work, sizeof (work), iptr) == NULL ||
2507+ sscanf (work, "%d,%d,%lu",
2508+ &pmail->readflag, &pmail->line, &tstamp) != 3)
2509+ {
2510+ FreeMail (pmail);
2511+ break;
2512+ }
2513+ pmail->timestamp = tstamp;
2514+ if (fgets (work, sizeof (work), iptr) == NULL ||
2515+ sscanf (work, "%[^\n\r]", namebuf) != 1)
2516+ {
2517+ FreeMail (pmail);
2518+ break;
2519+ }
2520+#ifdef MAKEWIN32
2521+ convertC2H (namebuf, USERNAME_LEN);
2522+#endif
2523+ pmail->fromuser = SearchUser (namebuf);
2524+ if (pmail->fromuser == -1)
2525+ {
2526+ FreeMail (pmail);
2527+ break;
2528+ }
2529+ if (fgets (work, sizeof (work), iptr) == NULL)
2530+ {
2531+ FreeMail (pmail);
2532+ break;
2533+ }
2534+ namebuf[0] = '\0';
2535+ sscanf (work, "%[^\n\r]", namebuf);
2536+ n = strlen (namebuf);
2537+ if (n > PACKET_DATA_MAX - 1)
2538+ {
2539+ n = PACKET_DATA_MAX - 1;
2540+ }
2541+#ifdef MAKEWIN32
2542+ convertC2H (namebuf, n);
2543+#endif
2544+ pmail->subject[0] = n;
2545+ if (n)
2546+ {
2547+ strncpy (&pmail->subject[1], namebuf, n);
2548+ }
2549+ for (j = 0; j < pmail->line; j++)
2550+ {
2551+ if (fgets (work, sizeof (work), iptr) == NULL)
2552+ {
2553+ FreeMail (pmail);
2554+ break;
2555+ }
2556+ namebuf[0] = '\0';
2557+ sscanf (work, "%[^\n\r]", namebuf);
2558+ n = strlen (namebuf);
2559+ if (n > PACKET_DATA_MAX - 1)
2560+ {
2561+ n = PACKET_DATA_MAX - 1;
2562+ }
2563+#ifdef MAKEWIN32
2564+ convertC2H (namebuf, n);
2565+#endif
2566+ pmail->message[j][0] = n;
2567+ if (n)
2568+ {
2569+ strncpy (&pmail->message[j][1], namebuf, n);
2570+ }
2571+ }
2572+ if (j < pmail->line)
2573+ {
2574+ /* occur error */
2575+ break;
2576+ }
2577+ User[nuser].mail[i] = pmail;
2578+ }
2579+ }
2580+ }
2581+ else
2582+ {
2583+ fputs ("Warnning: mismatch mail data version\n", stderr);
2584+ }
2585+ fclose (iptr);
2586+ }
2587+ return (iptr != NULL) ? 0 : -1;
2588+}
2589+
2590+/* save mail data */
2591+static int
2592+SaveMail (int nuser, const char *prefix)
2593+{
2594+ FILE *optr;
2595+ char fname[BUFFER_SIZE];
2596+ sprintf (fname, "%s/h-mail.%s", DATA_DIR, prefix);
2597+ optr = fopen (fname, "w");
2598+ if (optr != NULL)
2599+ {
2600+ int i;
2601+ fprintf (optr, "#M0100 Hunter-online mail file -DO NOT MODIFY!-\n%u\n",
2602+ MAIL_BOX_LIMIT);
2603+ ReorderMailbox (nuser);
2604+ for (i = 0; i < MAIL_BOX_LIMIT; i++)
2605+ {
2606+ int j;
2607+ unsigned n;
2608+ char work[BUFFER_SIZE];
2609+ char namebuf[BUFFER_SIZE];
2610+ MAILDATA *pmail = User[nuser].mail[i];
2611+ if (pmail == NULL)
2612+ {
2613+ break;
2614+ }
2615+ strncpy (namebuf, User[pmail->fromuser].name, USERNAME_LEN);
2616+ namebuf[USERNAME_LEN] = '\0';
2617+#ifdef MAKEWIN32
2618+ convertH2C (namebuf, USERNAME_LEN);
2619+#endif
2620+ fprintf (optr, "%d,%d,%lu\n%-.16s\n",
2621+ pmail->readflag, pmail->line, pmail->timestamp, namebuf);
2622+ n = (unsigned char) (pmail->subject[0]);
2623+ if (n)
2624+ {
2625+ memcpy (work, &pmail->subject[1], n);
2626+ }
2627+ work[n] = '\0';
2628+#ifdef MAKEWIN32
2629+ convertH2C (work, n);
2630+#endif
2631+ fprintf (optr, "%s\n", work);
2632+ for (j = 0; j < pmail->line; j++)
2633+ {
2634+ n = (unsigned char) (pmail->message[j][0]);
2635+ if (n)
2636+ {
2637+ memcpy (work, &pmail->message[j][1], n);
2638+ }
2639+ work[n] = '\0';
2640+#ifdef MAKEWIN32
2641+ convertH2C (work, n);
2642+#endif
2643+ fprintf (optr, "%s\n", work);
2644+ }
2645+ }
2646+ fclose (optr);
2647+ }
2648+ return (optr != NULL) ? 0 : -1;
2649+}
2650+
2651+/* load mail for all user */
2652+static int
2653+LoadAllMail (void)
2654+{
2655+ int ret = 0;
2656+ int i;
2657+ for (i = 0; i < UserLimit; i++)
2658+ {
2659+ if (User[i].name[0] != '\0')
2660+ {
2661+ char namebuf[USERNAME_LEN + 1];
2662+ make_mail_prefix (User[i].name, namebuf);
2663+ if (LoadMail (i, namebuf))
2664+ {
2665+ ret = -1;
2666+ break;
2667+ }
2668+ }
2669+ }
2670+ return ret;
2671+}
2672+
2673+/* save mail for all user */
2674+static int
2675+SaveAllMail (void)
2676+{
2677+ int ret = 0;
2678+ int i;
2679+ for (i = 0; i < UserLimit; i++)
2680+ {
2681+ if (User[i].name[0] != '\0')
2682+ {
2683+ char namebuf[USERNAME_LEN + 1];
2684+ make_mail_prefix (User[i].name, namebuf);
2685+ if (SaveMail (i, namebuf))
2686+ {
2687+ ret = -1;
2688+ break;
2689+ }
2690+ }
2691+ }
2692+ return ret;
2693+}
2694+
2695+#ifdef USE_BBS
2696+/* load BBS data */
2697+static int
2698+LoadBBS (void)
2699+{
2700+ FILE *iptr;
2701+ char fname[BUFFER_SIZE];
2702+ sprintf (fname, "%s/%s", DATA_DIR, BBS_DATA_FILE);
2703+ iptr = fopen (fname, "r");
2704+ if (iptr != NULL)
2705+ {
2706+ unsigned nmax;
2707+ char work[BUFFER_SIZE];
2708+ if (fgets (work, sizeof (work), iptr) == NULL)
2709+ {
2710+ /* error */
2711+ fputs ("Warnning: can't read bbs data!\n", stderr);
2712+ }
2713+ else if (!memcmp (work, "#B0100", 6))
2714+ {
2715+ if (fgets (work, sizeof (work), iptr) == NULL ||
2716+ sscanf (work, "%u", &nmax) != 1 || nmax > BBS_BOX_LIMIT)
2717+ {
2718+ /* this file is broken */
2719+ fputs ("bbs data file is broken.\n", stderr);
2720+ fclose (iptr);
2721+ return -1;
2722+ }
2723+ else
2724+ {
2725+ int i;
2726+ char namebuf[BUFFER_SIZE];
2727+ for (i = 0; i < nmax; i++)
2728+ {
2729+ MAILDATA *pmail = NewMail ();
2730+ unsigned long tstamp;
2731+ unsigned n;
2732+ int j;
2733+ if (fgets (work, sizeof (work), iptr) == NULL ||
2734+ sscanf (work, "%d,%d,%lu",
2735+ &pmail->readflag, &pmail->line, &tstamp) != 3)
2736+ {
2737+ FreeMail (pmail);
2738+ break;
2739+ }
2740+ pmail->timestamp = tstamp;
2741+ if (fgets (work, sizeof (work), iptr) == NULL ||
2742+ sscanf (work, "%[^\n\r]", namebuf) != 1)
2743+ {
2744+ FreeMail (pmail);
2745+ break;
2746+ }
2747+#ifdef MAKEWIN32
2748+ convertC2H (namebuf, USERNAME_LEN);
2749+#endif
2750+ pmail->fromuser = SearchUser (namebuf);
2751+ if (pmail->fromuser == -1)
2752+ {
2753+ FreeMail (pmail);
2754+ break;
2755+ }
2756+ if (fgets (work, sizeof (work), iptr) == NULL)
2757+ {
2758+ FreeMail (pmail);
2759+ break;
2760+ }
2761+ namebuf[0] = '\0';
2762+ sscanf (work, "%[^\n\r]", namebuf);
2763+ n = strlen (namebuf);
2764+ if (n > PACKET_DATA_MAX - 1)
2765+ {
2766+ n = PACKET_DATA_MAX - 1;
2767+ }
2768+#ifdef MAKEWIN32
2769+ convertC2H (namebuf, n);
2770+#endif
2771+ pmail->subject[0] = n;
2772+ if (n)
2773+ {
2774+ strncpy (&pmail->subject[1], namebuf, n);
2775+ }
2776+ for (j = 0; j < pmail->line; j++)
2777+ {
2778+ if (fgets (work, sizeof (work), iptr) == NULL)
2779+ {
2780+ FreeMail (pmail);
2781+ break;
2782+ }
2783+ namebuf[0] = '\0';
2784+ sscanf (work, "%[^\n\r]", namebuf);
2785+ n = strlen (namebuf);
2786+ if (n > PACKET_DATA_MAX - 1)
2787+ {
2788+ n = PACKET_DATA_MAX - 1;
2789+ }
2790+#ifdef MAKEWIN32
2791+ convertC2H (namebuf, n);
2792+#endif
2793+ pmail->message[j][0] = n;
2794+ if (n)
2795+ {
2796+ strncpy (&pmail->message[j][1], namebuf, n);
2797+ }
2798+ }
2799+ if (j < pmail->line)
2800+ {
2801+ /* occur error */
2802+ break;
2803+ }
2804+ BBSdata[i] = pmail;
2805+ }
2806+ }
2807+ }
2808+ else
2809+ {
2810+ fputs ("Warnning: mismatch bbs data version\n", stderr);
2811+ }
2812+ fclose (iptr);
2813+ }
2814+ return (iptr != NULL) ? 0 : -1;
2815+}
2816+
2817+/* save bbs data */
2818+static int
2819+SaveBBS (void)
2820+{
2821+ FILE *optr;
2822+ char fname[BUFFER_SIZE];
2823+ sprintf (fname, "%s/%s", DATA_DIR, BBS_DATA_FILE);
2824+ optr = fopen (fname, "w");
2825+ if (optr != NULL)
2826+ {
2827+ int i;
2828+ fprintf (optr, "#B0100 Hunter-online bbs file -DO NOT MODIFY!-\n%u\n",
2829+ BBS_BOX_LIMIT);
2830+ ReorderBBSbox ();
2831+ for (i = 0; i < BBS_BOX_LIMIT; i++)
2832+ {
2833+ int j;
2834+ unsigned n;
2835+ char work[BUFFER_SIZE];
2836+ char namebuf[BUFFER_SIZE];
2837+ MAILDATA *pmail = BBSdata[i];
2838+ if (pmail == NULL)
2839+ {
2840+ break;
2841+ }
2842+ strncpy (namebuf, User[pmail->fromuser].name, USERNAME_LEN);
2843+ namebuf[USERNAME_LEN] = '\0';
2844+#ifdef MAKEWIN32
2845+ convertH2C (namebuf, USERNAME_LEN);
2846+#endif
2847+ fprintf (optr, "%d,%d,%lu\n%-.16s\n",
2848+ pmail->readflag, pmail->line, pmail->timestamp, namebuf);
2849+ n = (unsigned char) (pmail->subject[0]);
2850+ if (n)
2851+ {
2852+ memcpy (work, &pmail->subject[1], n);
2853+ }
2854+ work[n] = '\0';
2855+#ifdef MAKEWIN32
2856+ convertH2C (work, n);
2857+#endif
2858+ fprintf (optr, "%s\n", work);
2859+ for (j = 0; j < pmail->line; j++)
2860+ {
2861+ n = (unsigned char) (pmail->message[j][0]);
2862+ if (n)
2863+ {
2864+ memcpy (work, &pmail->message[j][1], n);
2865+ }
2866+ work[n] = '\0';
2867+#ifdef MAKEWIN32
2868+ convertH2C (work, n);
2869+#endif
2870+ fprintf (optr, "%s\n", work);
2871+ }
2872+ }
2873+ fclose (optr);
2874+ }
2875+ return (optr != NULL) ? 0 : -1;
2876+}
2877+#endif /* USE_BBS */
2878+#endif /* USE_MAIL */
2879+
2880+/* load user information */
2881+static int
2882+LoadUser (const char *pfilename)
2883+{
2884+ int ret = -1;
2885+ FILE *iptr = fopen (pfilename, "r");
2886+ if (iptr != NULL)
2887+ {
2888+ char work[BUFFER_SIZE];
2889+ if (fgets (work, sizeof (work), iptr) != NULL)
2890+ {
2891+ int ver = 0;
2892+ if (!memcmp (work, "#H0105", 6))
2893+ {
2894+ ver = 5;
2895+ }
2896+ else if (!memcmp (work, "#H0106", 6))
2897+ {
2898+ ver = 6;
2899+ }
2900+ if (ver == 0)
2901+ {
2902+ /* mismatch version */
2903+ fputs ("Warning:User data file version mismatch\n", stderr);
2904+ }
2905+ else
2906+ {
2907+ int nusermax;
2908+ if (fgets (work, sizeof (work), iptr) == NULL ||
2909+ sscanf (work, "%d", &nusermax) != 1 ||
2910+ nusermax > UserLimit - 1)
2911+ {
2912+ /* modify? */
2913+ fputs ("Warnning:User data file is broken\n", stderr);
2914+ }
2915+ else
2916+ {
2917+ int i;
2918+ printf ("%d users in data-file\n", nusermax);
2919+ nusermax++;
2920+ for (i = 1; i < nusermax; i++)
2921+ {
2922+ int j;
2923+ unsigned long nwk;
2924+ memset (User[i].myshop, 0, sizeof (User[i].myshop));
2925+ memset (User[i].higemesg, 0, sizeof (User[i].higemesg));
2926+ if (fgets (work, sizeof (work), iptr) == NULL)
2927+ {
2928+ break;
2929+ }
2930+#ifdef MAKEWIN32
2931+ convertC2H (work, strlen (work));
2932+#endif
2933+ for (j = 0; work[j] != '\0' && j < USERNAME_LEN; j++)
2934+ {
2935+ User[i].name[j] = work[j];
2936+ }
2937+ for (; j < USERNAME_LEN; j++)
2938+ {
2939+ User[i].name[j] = ' ';
2940+ }
2941+ for (j = 0; j < USERSHOP_LIMIT; j++)
2942+ {
2943+ memcpy (User[i].myshop[j].name,
2944+ User[i].name, USERNAME_LEN);
2945+ User[i].myshop[j].build = 0;
2946+ }
2947+ if (fgets (work, sizeof (work), iptr) == NULL)
2948+ {
2949+ break;
2950+ }
2951+#ifdef MAKEWIN32
2952+ convertC2H (work, strlen (work));
2953+#endif
2954+ for (j = 0; work[j] != '\0' && j < PASSWORD_LEN; j++)
2955+ {
2956+ User[i].password[j] = work[j];
2957+ }
2958+ for (; j < USERNAME_LEN; j++)
2959+ {
2960+ User[i].password[j] = ' ';
2961+ }
2962+ if (fgets (work, sizeof (work), iptr) == NULL)
2963+ {
2964+ break;
2965+ }
2966+ if (sscanf (work, "%lu", &User[i].score) != 1)
2967+ {
2968+ break;
2969+ }
2970+ if (fgets (work, sizeof (work), iptr) == NULL)
2971+ {
2972+ break;
2973+ }
2974+ if (ver == 5)
2975+ {
2976+ if (sscanf (work, "%lu,%d,%d,%d,%d,%d", &nwk,
2977+ &j, &User[i].pos.x, &User[i].pos.y,
2978+ &User[i].speed,
2979+ &User[i].animal_slot) != 6)
2980+ {
2981+ break;
2982+ }
2983+ User[i].ride_pattern = 0;
2984+ }
2985+ else
2986+ {
2987+ if (sscanf (work, "%lu,%d,%d,%d,%d,%d,%d", &nwk,
2988+ &j, &User[i].pos.x, &User[i].pos.y,
2989+ &User[i].speed,
2990+ &User[i].animal_slot,
2991+ &User[i].ride_pattern) != 7)
2992+ {
2993+ break;
2994+ }
2995+ }
2996+ User[i].c_type = nwk ? Observer : Hunter;
2997+ User[i].direction = j;
2998+ for (j = 0; j < WEAPON_MAX; j++)
2999+ {
3000+ char namebuf[BUFFER_SIZE];
3001+ if (fgets (work, sizeof (work), iptr) == NULL)
3002+ {
3003+ break;
3004+ }
3005+ if (sscanf (work, "%[^,],%lu", namebuf, &nwk) != 2)
3006+ {
3007+ break;
3008+ }
3009+#ifdef MAKEWIN32
3010+ convertC2H (namebuf, strlen (namebuf));
3011+#endif
3012+ User[i].weapon[j] =
3013+ SearchWeaponForNameType (namebuf, User[i].c_type);
3014+ if (User[i].weapon[j])
3015+ {
3016+ User[i].bullette[j] = nwk;
3017+ }
3018+ else
3019+ {
3020+ User[i].bullette[j] = 0;
3021+ }
3022+ }
3023+ if (j < WEAPON_MAX)
3024+ {
3025+ break;
3026+ }
3027+ for (j = 0; j < ITEM_MAX; j++)
3028+ {
3029+ char namebuf[BUFFER_SIZE];
3030+ if (fgets (work, sizeof (work), iptr) == NULL)
3031+ {
3032+ break;
3033+ }
3034+ if (sscanf (work, "%[^,],%lu", namebuf, &nwk) != 2)
3035+ {
3036+ break;
3037+ }
3038+#ifdef MAKEWIN32
3039+ convertC2H (namebuf, strlen (namebuf));
3040+#endif
3041+ User[i].item[j] = SearchItemForName (namebuf);
3042+ if (User[i].item[j])
3043+ {
3044+ User[i].itemcount[j] = nwk;
3045+ }
3046+ else
3047+ {
3048+ User[i].itemcount[j] = 0;
3049+ }
3050+ }
3051+ if (j < ITEM_MAX)
3052+ {
3053+ break;
3054+ }
3055+ User[i].hp = HpBase;
3056+ User[i].hungry = HungryBase;
3057+ User[i].maybearrest = 0;
3058+ User[i].crime_level = 0;
3059+ User[i].arrest_count = 0;
3060+ for (j = 0; j < ANIMAL_SLOT_MAX; j++)
3061+ {
3062+ User[i].lastPickupAnimal[j] = NULL;
3063+ }
3064+#ifdef USE_FORK
3065+ User[i].send_pid = 0;
3066+ User[i].send_handle = -1;
3067+#endif
3068+#ifdef USE_W32THREAD
3069+ User[i].w32thread = NULL;
3070+ User[i].w32queue = NULL;
3071+#endif
3072+ }
3073+ printf ("%d users loaded\n", i);
3074+ if (i < nusermax)
3075+ {
3076+ /* perhaps error. clear last user data */
3077+ memset (User[i].name, 0, USERNAME_LEN);
3078+ memset (User[i].password, 0, PASSWORD_LEN);
3079+ User[i].score = 0;
3080+ fputs ("Warnning: possible to error loading userdata\n",
3081+ stderr);
3082+ }
3083+ }
3084+ }
3085+ }
3086+ fclose (iptr);
3087+ ret = 0;
3088+ }
3089+ return ret;
3090+}
3091+
3092+/* save user information */
3093+static int
3094+SaveUser (const char *pfilename)
3095+{
3096+ int ret = -1;
3097+ FILE *optr = fopen (pfilename, "w");
3098+ if (optr != NULL)
3099+ {
3100+ int i;
3101+ int nusermax = 0;
3102+ fputs ("#H0106 Hunter-Online USER DATA FILE - Do not modify!\n", optr);
3103+ for (i = 1; i < UserLimit; i++)
3104+ {
3105+ if (User[i].name[0] != '\0')
3106+ {
3107+ nusermax++;
3108+ }
3109+ }
3110+ fprintf (optr, "%d\n", nusermax);
3111+ for (i = 1; i < UserLimit; i++)
3112+ {
3113+ if (User[i].name[0] != '\0')
3114+ {
3115+ int j;
3116+ char work[BUFFER_SIZE];
3117+ memcpy (work, User[i].name, USERNAME_LEN);
3118+ work[USERNAME_LEN] = '\0';
3119+#ifdef MAKEWIN32
3120+ convertH2C (work, USERNAME_LEN);
3121+#endif
3122+ fprintf (optr, "%-*s\n", USERNAME_LEN, work);
3123+ memcpy (work, User[i].password, PASSWORD_LEN);
3124+ work[PASSWORD_LEN] = '\0';
3125+#ifdef MAKEWIN32
3126+ convertH2C (work, PASSWORD_LEN);
3127+#endif
3128+ fprintf (optr, "%-*s\n", PASSWORD_LEN, work);
3129+ fprintf (optr, "%lu\n", User[i].score);
3130+ fprintf (optr, "%d,%d,%d,%d,%d,%d,%d\n", User[i].c_type,
3131+ User[i].direction, User[i].pos.x, User[i].pos.y,
3132+ User[i].speed, User[i].animal_slot,
3133+ User[i].ride_pattern);
3134+ for (j = 0; j < WEAPON_MAX; j++)
3135+ {
3136+ memcpy (work, Weapon[User[i].weapon[j]].name,
3137+ WEAPONNAME_LEN);
3138+ work[WEAPONNAME_LEN] = '\0';
3139+#ifdef MAKEWIN32
3140+ convertH2C (work, WEAPONNAME_LEN);
3141+#endif
3142+ fprintf (optr, "%s,%u\n", work, User[i].bullette[j]);
3143+ }
3144+ for (j = 0; j < ITEM_MAX; j++)
3145+ {
3146+ memcpy (work, Item[User[i].item[j]].name, ITEMNAME_LEN);
3147+ work[ITEMNAME_LEN] = '\0';
3148+#ifdef MAKEWIN32
3149+ convertH2C (work, ITEMNAME_LEN);
3150+#endif
3151+ fprintf (optr, "%s,%u\n", work, User[i].itemcount[j]);
3152+ }
3153+ }
3154+ }
3155+ fclose (optr);
3156+ ret = 0;
3157+ }
3158+ return ret;
3159+}
3160+
3161+/* load animal information */
3162+static int
3163+LoadAnimal (const char *pfilename)
3164+{
3165+ int ret = -1;
3166+ FILE *iptr;
3167+ iptr = fopen (pfilename, "r");
3168+ if (iptr != NULL)
3169+ {
3170+ int n = 0;
3171+ char lbuf[BUFFER_SIZE];
3172+ char namebuf[BUFFER_SIZE];
3173+ char inamebuf[BUFFER_SIZE];
3174+ ret = 0;
3175+ while (fgets (lbuf, sizeof (lbuf), iptr) != NULL)
3176+ {
3177+ int i;
3178+ ANIMALDATA *p;
3179+ if (lbuf[0] == '#')
3180+ {
3181+ /* this line is comment */
3182+ continue;
3183+ }
3184+ if (n >= AnimalDataLimit)
3185+ {
3186+ /* need expand */
3187+ p = realloc (AnimalData, sizeof (ANIMALDATA) *
3188+ (AnimalDataLimit + ALLOCATE_CHUNK));
3189+ if (p == NULL)
3190+ {
3191+ /* ??can't allocate memory */
3192+ free (AnimalData);
3193+ AnimalData = NULL;
3194+ n = 0;
3195+ ret = 1;
3196+ break;
3197+ }
3198+ AnimalData = p;
3199+ AnimalDataLimit += ALLOCATE_CHUNK;
3200+ }
3201+ p = AnimalData + n;
3202+ p->n = n;
3203+ if (sscanf (lbuf, "%[^,],%lu,%u,%u,%u,%u,%u,%u,%d,%d,%d,%[^\n\r]",
3204+ namebuf,
3205+ &p->hp, &p->moral, &p->speed,
3206+ &p->value, &p->rate, &p->w_power, &p->w_rate,
3207+ &p->eatmeat, &p->pattern, &p->charm_rate,
3208+ inamebuf) != 12)
3209+ {
3210+ /* can't read data */
3211+ break;
3212+ }
3213+#ifdef MAKEWIN32
3214+ convertC2H (namebuf, strlen (namebuf));
3215+#endif
3216+ for (i = 0; namebuf[i] != '\0' && i < ANIMALNAME_LEN; i++)
3217+ {
3218+ p->name[i] = namebuf[i];
3219+ }
3220+ for (; i < ANIMALNAME_LEN; i++)
3221+ {
3222+ p->name[i] = ' ';
3223+ }
3224+#ifdef MAKEWIN32
3225+ convertC2H (inamebuf, strlen (inamebuf));
3226+#endif
3227+ p->forsell_item = SearchItemForName (inamebuf);
3228+ n++;
3229+ }
3230+ AnimalDataLimit = n;
3231+ fclose (iptr);
3232+ }
3233+ return ret;
3234+}
3235+
3236+/* create new Animal */
3237+static int
3238+NewAnimal (ANIMALDATA * pdata)
3239+{
3240+ int i;
3241+ for (i = 0; i < AnimalLimit; i++)
3242+ {
3243+ if (Animal[i].pdata == NULL)
3244+ {
3245+ int x;
3246+ int y;
3247+ Animal[i].pdata = pdata;
3248+ memcpy (Animal[i].name, pdata->name, USERNAME_LEN);
3249+ Animal[i].hp = pdata->hp;
3250+ Animal[i].moral = pdata->moral;
3251+ Animal[i].speed = pdata->speed;
3252+ Animal[i].w_power = pdata->w_power;
3253+#ifdef USE_STRONGANIMAL
3254+ Animal[i].hp_org = Animal[i].hp;
3255+ Animal[i].moral_org = Animal[i].moral;
3256+ Animal[i].speed_org = Animal[i].speed;
3257+ Animal[i].w_power_org = Animal[i].w_power;
3258+#endif
3259+ do
3260+ {
3261+ x = getrand (0, MapWidth - 1);
3262+ y = getrand (0, MapHeight - 1);
3263+ }
3264+ while (MAP (x, y)->player || (MAP (x, y)->id & MAP_HIGH_MASK));
3265+ Animal[i].pos.x = x;
3266+ Animal[i].pos.y = y;
3267+ Animal[i].reload = 0;
3268+ Animal[i].charmcount = 0;
3269+ Animal[i].ntarget = -1;
3270+ Animal[i].search = ANIMAL_SEARCH_RANGE;
3271+ Animal[i].ntime = 0;
3272+ Animal[i].hold_count = 0;
3273+ Animal[i].recover_count = ANIMAL_RECOVER_COUNT;
3274+ Animal[i].owner_user = -1;
3275+ return i;
3276+ }
3277+ }
3278+ return -1;
3279+}
3280+
3281+/* delete animal */
3282+static void
3283+DeleteAnimal (int nanimal)
3284+{
3285+ Animal[nanimal].pdata = NULL;
3286+ Animal[nanimal].hp = 0;
3287+ Animal[nanimal].moral = 0;
3288+ return;
3289+}
3290+
3291+/* Initialize animal type table */
3292+static void
3293+InitializeAnimalType (void)
3294+{
3295+ int i;
3296+ int total = 0;
3297+ AnimalTypeTable = malloc (sizeof (int) * AnimalDataLimit);
3298+ if (AnimalTypeTable == NULL)
3299+ {
3300+ perror ("malloc");
3301+ fputs ("EVAC:not enought to animal-type memory\n", stderr);
3302+ exit (1);
3303+ }
3304+ for (i = 0; i < AnimalDataLimit; i++)
3305+ {
3306+ total += AnimalData[i].rate;
3307+ AnimalTypeTable[i] = total;
3308+ }
3309+ AnimalTypeTotal = total;
3310+ return;
3311+}
3312+
3313+/* select animal type */
3314+static ANIMALDATA *
3315+GetAnimalType (void)
3316+{
3317+ int n = getrand (1, AnimalTypeTotal);
3318+ int i;
3319+ for (i = 0; i < AnimalDataLimit; i++)
3320+ {
3321+ if (AnimalTypeTable[i] >= n)
3322+ {
3323+ return AnimalData + i;
3324+ }
3325+ }
3326+ return NULL;
3327+}
3328+
3329+
3330+/* load weapon information */
3331+static int
3332+LoadWeapon (const char *pfilename)
3333+{
3334+ int ret = -1;
3335+ FILE *iptr;
3336+ iptr = fopen (pfilename, "r");
3337+ if (iptr != NULL)
3338+ {
3339+ int n = 0;
3340+ char lbuf[BUFFER_SIZE];
3341+ char namebuf[BUFFER_SIZE];
3342+ ret = 0;
3343+ while (fgets (lbuf, sizeof (lbuf), iptr) != NULL)
3344+ {
3345+ WEAPONINFO *p;
3346+ int b_type;
3347+ if (lbuf[0] == '#')
3348+ {
3349+ /* this line is comment */
3350+ continue;
3351+ }
3352+ if (n >= WeaponLimit)
3353+ {
3354+ /* need expand */
3355+ p = realloc (Weapon, sizeof (WEAPONINFO) *
3356+ (WeaponLimit + ALLOCATE_CHUNK));
3357+ if (p == NULL)
3358+ {
3359+ /* ??can't allocate memory */
3360+ free (Weapon);
3361+ Weapon = NULL;
3362+ n = 0;
3363+ ret = 1;
3364+ break;
3365+ }
3366+ Weapon = p;
3367+ WeaponLimit += ALLOCATE_CHUNK;
3368+ }
3369+ p = Weapon + n;
3370+ if (sscanf (lbuf, "%[^,],%u,%u,%u,%u,%u,%u,%u,%lu,%u,%u,%d",
3371+ namebuf,
3372+ &p->firepower, &p->moral, &p->range,
3373+ &p->rate, &p->reduce, &p->speed, &p->bullette,
3374+ &p->cost, &p->forhunter, &p->npc_rate, &b_type) != 12)
3375+ {
3376+ /* can't read data */
3377+ break;
3378+ }
3379+#ifdef MAKEWIN32
3380+ convertC2H (namebuf, strlen (namebuf));
3381+#endif
3382+ strncpy (p->name, namebuf, WEAPONNAME_LEN);
3383+ p->b_type = (enum bullet_type) b_type;
3384+ n++;
3385+ }
3386+ WeaponLimit = n;
3387+ fclose (iptr);
3388+ }
3389+ return ret;
3390+}
3391+
3392+/* load item information */
3393+static int
3394+LoadItem (const char *pfilename)
3395+{
3396+ int ret = -1;
3397+ FILE *iptr;
3398+ iptr = fopen (pfilename, "r");
3399+ if (iptr != NULL)
3400+ {
3401+ int n = 0;
3402+ char lbuf[BUFFER_SIZE];
3403+ char namebuf[BUFFER_SIZE];
3404+ ret = 0;
3405+ while (fgets (lbuf, sizeof (lbuf), iptr) != NULL)
3406+ {
3407+ ITEMINFO *p;
3408+ int ntype;
3409+ int neffect;
3410+ int ncount;
3411+ int ncost;
3412+ int nforhunter;
3413+ int npattern;
3414+ if (lbuf[0] == '#')
3415+ {
3416+ /* this line is comment */
3417+ continue;
3418+ }
3419+ if (n >= ItemLimit)
3420+ {
3421+ /* need expand */
3422+ p = realloc (Item, sizeof (ITEMINFO) *
3423+ (ItemLimit + ALLOCATE_CHUNK));
3424+ if (p == NULL)
3425+ {
3426+ /* ??can't allocate memory */
3427+ free (Item);
3428+ Item = NULL;
3429+ n = 0;
3430+ ret = 1;
3431+ break;
3432+ }
3433+ Item = p;
3434+ ItemLimit += ALLOCATE_CHUNK;
3435+ }
3436+ p = Item + n;
3437+ if (sscanf (lbuf, "%[^,],%d,%d,%d,%d,%d,%d",
3438+ namebuf, &ntype, &neffect, &ncount,
3439+ &ncost, &nforhunter, &npattern) != 7)
3440+ {
3441+ /* can't read data */
3442+ break;
3443+ }
3444+#ifdef MAKEWIN32
3445+ convertC2H (namebuf, strlen (namebuf));
3446+#endif
3447+ strncpy (p->name, namebuf, ITEMNAME_LEN);
3448+ p->id = ntype;
3449+ p->effect = neffect;
3450+ p->count = ncount;
3451+ p->cost = ncost;
3452+ p->forhunter = nforhunter;
3453+ p->pattern = npattern;
3454+ n++;
3455+ }
3456+ ItemLimit = n;
3457+ fclose (iptr);
3458+ }
3459+ return ret;
3460+}
3461+
3462+/* initialize map data */
3463+static void
3464+InitializeMap (void)
3465+{
3466+#ifdef USE_SAVEMAP
3467+ char work[BUFFER_SIZE];
3468+#endif
3469+ int i;
3470+ Map = malloc (sizeof (struct map_block) * MapWidth * MapHeight);
3471+ if (Map == NULL)
3472+ {
3473+ perror ("malloc");
3474+ fputs ("EVAC:not enought to map memory\n", stderr);
3475+ exit (1);
3476+ }
3477+#ifdef USE_SAVEMAP
3478+ sprintf (work, "%s/%s", DATA_DIR, SYSMAP_DATA_FILE);
3479+ puts ("Loading saved map data...");
3480+ if (!LoadMapData (work))
3481+ {
3482+ puts ("done.");
3483+ return;
3484+ }
3485+ else
3486+ {
3487+ puts ("no saved map data");
3488+ }
3489+#endif
3490+ for (i = 0; i < MapWidth * MapHeight; i++)
3491+ {
3492+ Map[i].id = MAP_INVALID;
3493+ Map[i].player = 0;
3494+ Map[i].animal = 0;
3495+ Map[i].owner = 0;
3496+ }
3497+ MAP (JailPositionX, JailPositionY)->id = MAP_THERE_WALL;
3498+ for (i = 0; i < ShopLimit; i++)
3499+ {
3500+ int x;
3501+ int y;
3502+ do
3503+ {
3504+ x = getrand (0, MapWidth - 1);
3505+ y = getrand (0, MapHeight - 1);
3506+ }
3507+ while ((MAP (x, y)->id & MAP_HIGH_MASK));
3508+ MAP (x, y)->id |= MAP_THERE_SHOP;
3509+ }
3510+ MakeNewMap ();
3511+ for (i = 0; i < TreasureLimit; i++)
3512+ {
3513+ int x;
3514+ int y;
3515+ do
3516+ {
3517+ x = getrand (0, MapWidth - 1);
3518+ y = getrand (0, MapHeight - 1);
3519+ }
3520+ while ((MAP (x, y)->id & MAP_HIGH_MASK));
3521+ MAP (x, y)->id |= MAP_THERE_ITEM;
3522+ }
3523+ return;
3524+}
3525+
3526+/* allocate bullet */
3527+static struct bullet_t *
3528+NewBullet (int nweapon, struct location pos, int direction)
3529+{
3530+ struct bullet_t *p = malloc (sizeof (struct bullet_t));
3531+ if (p == NULL)
3532+ {
3533+ /* uhm. cannot make bullet. Emergency Evacution.:) */
3534+ perror ("malloc");
3535+ fputs ("EVAC:fail NewBullet\n", stderr);
3536+ NowRunning = 0;
3537+ exit (255);
3538+ }
3539+ p->pprev = pBullet;
3540+ if (pBullet != NULL)
3541+ {
3542+ pBullet->pnext = p;
3543+ }
3544+ p->pnext = NULL;
3545+ p->pweapon = Weapon + nweapon;
3546+ p->fire_pos = p->pos = pos;
3547+ p->direction = direction;
3548+ p->nuser = -1;
3549+ p->ndamage = p->pweapon->firepower;
3550+ p->ndistance = p->pweapon->range;
3551+ p->ntime = 0;
3552+ pBullet = p;
3553+ return p;
3554+}
3555+
3556+/* freeup bullet */
3557+static void
3558+FreeBullet (struct bullet_t *p)
3559+{
3560+ if (p == pBullet)
3561+ {
3562+ pBullet = p->pprev;
3563+ }
3564+ if (p->pprev != NULL)
3565+ {
3566+ p->pprev->pnext = p->pnext;
3567+ }
3568+ if (p->pnext != NULL)
3569+ {
3570+ p->pnext->pprev = p->pprev;
3571+ }
3572+ free (p);
3573+ return;
3574+}
3575+
3576+/* search user shop from position */
3577+static int
3578+searchUserShopFromPos (int nuser, int x, int y)
3579+{
3580+ int i;
3581+ for (i = 0; i < USERSHOP_LIMIT; i++)
3582+ {
3583+ if (User[nuser].myshop[i].build)
3584+ {
3585+ if (User[nuser].myshop[i].pos.x == x &&
3586+ User[nuser].myshop[i].pos.y == y)
3587+ {
3588+ /* found */
3589+ return i;
3590+ }
3591+ }
3592+ }
3593+ return -1; /* ?? no find */
3594+}
3595+
3596+/* send result code :result=0..ok result!=0..ng */
3597+static int
3598+SendResultPacket (SOCKET handle, int result)
3599+{
3600+ int ret = -1;
3601+ if (handle != INVALID_SOCKET)
3602+ {
3603+ unsigned char packet[PACKET_MAX];
3604+ packet[0] = HSERV_RESULT;
3605+ packet[2] = result ? 0x01 : 0x00;
3606+ ret = send_packet_c (handle, packet, 1);
3607+ }
3608+ return ret;
3609+}
3610+
3611+/* map id to map data */
3612+static unsigned char
3613+mapid2mapdata (unsigned char c, int nowner)
3614+{
3615+ if (c & MAP_THERE_ITEM)
3616+ {
3617+ return HCLIT_MAP_ITEM;
3618+ }
3619+ else if (c & MAP_THERE_SHOP)
3620+ {
3621+ return nowner ? HCLIT_MAP_ROAD : HCLIT_MAP_SHOP;
3622+ }
3623+ else if (c & MAP_THERE_WALL)
3624+ {
3625+ return HCLIT_MAP_WALL;
3626+ }
3627+ else
3628+ {
3629+ c &= MAP_MASK;
3630+ switch (c)
3631+ {
3632+ case MAP_ROAD:
3633+ return HCLIT_MAP_ROAD;
3634+ case MAP_TREE:
3635+ return HCLIT_MAP_TREE;
3636+ case MAP_ROCK:
3637+ return HCLIT_MAP_ROCK;
3638+ default:
3639+ return HCLIT_MAP_INVALID;
3640+ }
3641+ }
3642+}
3643+
3644+/* map point to map data */
3645+static unsigned char
3646+mapid2mapdata2 (int x, int y)
3647+{
3648+ return mapid2mapdata (MAP (x, y)->id, MAP (x, y)->owner);
3649+}
3650+
3651+/* make map data for send */
3652+static void
3653+make_send_mapdata (int userno, unsigned char d[VIEW_LIMIT * VIEW_WIDTH])
3654+{
3655+ int x;
3656+ int y;
3657+ int i;
3658+ int n;
3659+ int direction = User[userno].direction;
3660+ x = User[userno].pos.x;
3661+ y = User[userno].pos.y;
3662+ n = 0;
3663+ for (i = 0; i < VIEW_LIMIT; i++)
3664+ {
3665+ int ny;
3666+ int nx;
3667+ nx = x - RGVectorX[direction] * 2;
3668+ ny = y - RGVectorY[direction] * 2;
3669+ adjust_pos (&nx, &ny);
3670+ d[n++] = mapid2mapdata2 (nx, ny);
3671+ nx += RGVectorX[direction];
3672+ ny += RGVectorY[direction];
3673+ adjust_pos (&nx, &ny);
3674+ d[n++] = mapid2mapdata2 (nx, ny);
3675+ d[n++] = mapid2mapdata2 (x, y);
3676+ nx = x + RGVectorX[direction];
3677+ ny = y + RGVectorY[direction];
3678+ adjust_pos (&nx, &ny);
3679+ d[n++] = mapid2mapdata2 (nx, ny);
3680+ nx += RGVectorX[direction];
3681+ ny += RGVectorY[direction];
3682+ adjust_pos (&nx, &ny);
3683+ d[n++] = mapid2mapdata2 (nx, ny);
3684+ x += FWVectorX[direction];
3685+ y += FWVectorY[direction];
3686+ adjust_pos (&x, &y);
3687+ }
3688+ return;
3689+}
3690+
3691+/* convert player data */
3692+static unsigned char
3693+player2mapdata (int x, int y)
3694+{
3695+ unsigned char id = MAP (x, y)->id;
3696+ int n = MAP (x, y)->player;
3697+ if (n)
3698+ {
3699+ if (User[n - 1].cloak_count == 0)
3700+ {
3701+ return TargetDirection[User[n - 1].c_type][User[n - 1].direction];
3702+ }
3703+ else
3704+ {
3705+ return HCLIT_PLAYER_NONE;
3706+ }
3707+ }
3708+ else
3709+ {
3710+ if (id & MAP_THERE_ANIMAL)
3711+ {
3712+ if (Animal[MAP (x, y)->animal].hp)
3713+ {
3714+ return HCLIT_MAP_ANIMAL;
3715+ }
3716+ else
3717+ {
3718+ return HCLIT_MAP_DEADANIMAL;
3719+ }
3720+ }
3721+ else if (id & MAP_THERE_NPC)
3722+ {
3723+ int npc = MAP (x, y)->animal;
3724+ return TargetDirection[Npc[npc].c_type][Npc[npc].direction];
3725+ }
3726+ else if ((id & MAP_THERE_SHOP) && MAP (x, y)->owner)
3727+ {
3728+ return HCLIT_MAP_USERSHOP;
3729+ }
3730+ else
3731+ {
3732+ return HCLIT_PLAYER_NONE;
3733+ }
3734+ }
3735+}
3736+
3737+/* make player on map data for send */
3738+static void
3739+make_send_playeronmapdata (int userno,
3740+ unsigned char d[VIEW_LIMIT * VIEW_WIDTH])
3741+{
3742+ int x;
3743+ int y;
3744+ int i;
3745+ int n;
3746+ int direction = User[userno].direction;
3747+ x = User[userno].pos.x;
3748+ y = User[userno].pos.y;
3749+ n = 0;
3750+ for (i = 0; i < VIEW_LIMIT; i++)
3751+ {
3752+ int ny;
3753+ int nx;
3754+ nx = x - RGVectorX[direction] * 2;
3755+ ny = y - RGVectorY[direction] * 2;
3756+ adjust_pos (&nx, &ny);
3757+ d[n++] = player2mapdata (nx, ny);
3758+ nx += RGVectorX[direction];
3759+ ny += RGVectorY[direction];
3760+ adjust_pos (&nx, &ny);
3761+ d[n++] = player2mapdata (nx, ny);
3762+ d[n++] = player2mapdata (x, y);
3763+ nx = x + RGVectorX[direction];
3764+ ny = y + RGVectorY[direction];
3765+ adjust_pos (&nx, &ny);
3766+ d[n++] = player2mapdata (nx, ny);
3767+ nx += RGVectorX[direction];
3768+ ny += RGVectorY[direction];
3769+ adjust_pos (&nx, &ny);
3770+ d[n++] = player2mapdata (nx, ny);
3771+ x += FWVectorX[direction];
3772+ y += FWVectorY[direction];
3773+ adjust_pos (&x, &y);
3774+ }
3775+ return;
3776+}
3777+
3778+/* copy player or animal or shop name */
3779+static unsigned char
3780+copy_mapdetaildata (int userno, unsigned char *p, int x, int y)
3781+{
3782+ unsigned char ret = 0;
3783+ unsigned char id = MAP (x, y)->id;
3784+ int nplayer = MAP (x, y)->player;
3785+ int nowner = MAP (x, y)->owner;
3786+ int nanimal = MAP (x, y)->animal;
3787+ if (nplayer && User[nplayer - 1].cloak_count == 0)
3788+ {
3789+ memcpy (p, User[nplayer - 1].name, 16);
3790+ if (User[nplayer - 1].maybearrest > 0)
3791+ {
3792+ if (User[nplayer - 1].maybearrest <= ArrestPass)
3793+ {
3794+ ret = 1;
3795+ }
3796+ else if (User[nplayer - 1].maybearrest <= ArrestAnyone)
3797+ {
3798+ ret = 2;
3799+ }
3800+ else
3801+ {
3802+ ret = 3;
3803+ }
3804+ }
3805+ else
3806+ {
3807+ switch (User[nplayer - 1].crime_level)
3808+ {
3809+ case 1:
3810+ ret = 2;
3811+ break;
3812+ case 2:
3813+ ret = 3;
3814+ break;
3815+ }
3816+ }
3817+ ret |= (User[nplayer - 1].ride_pattern << 4);
3818+ }
3819+ else
3820+ {
3821+ if (id & MAP_THERE_ANIMAL)
3822+ {
3823+ memcpy (p, Animal[nanimal].name, 16);
3824+ if (Animal[nanimal].owner_user == userno)
3825+ {
3826+ /* your animal */
3827+ ret = 5;
3828+ }
3829+ else if (Animal[nanimal].moral == 0)
3830+ {
3831+ ret = 1;
3832+ }
3833+ else if (Animal[nanimal].charmcount)
3834+ {
3835+ ret = 3;
3836+ }
3837+ else if (Animal[nanimal].moral < ANIMAL_MORAL_PANIC)
3838+ {
3839+ ret = 2;
3840+ }
3841+ else if (Animal[nanimal].moral > ANIMAL_MORAL_NORMAL)
3842+ {
3843+ ret = 4;
3844+ }
3845+ ret |= (Animal[nanimal].pdata->pattern << 4);
3846+ }
3847+ else if (id & MAP_THERE_NPC)
3848+ {
3849+ memcpy (p, Npc[nanimal].name, 16);
3850+ if (Npc[nanimal].c_type == NpcHunter)
3851+ {
3852+ ret = 3;
3853+ }
3854+ else if (Npc[nanimal].c_type == NpcHige)
3855+ {
3856+ ret = Npc[nanimal].number << 4;
3857+ if (Npc[nanimal].owner_user == userno)
3858+ {
3859+ ret |= 4;
3860+ }
3861+ }
3862+ }
3863+ else if ((id & MAP_THERE_SHOP) && nowner)
3864+ {
3865+ int nshop = searchUserShopFromPos (nowner - 1, x, y);
3866+ if (nshop != -1)
3867+ {
3868+ memcpy (p, User[nowner - 1].myshop[nshop].name, 16);
3869+ }
3870+ else
3871+ {
3872+ /* error??? */
3873+ memset (p, ' ', 16);
3874+ }
3875+ }
3876+ else
3877+ {
3878+ memset (p, ' ', 16);
3879+ }
3880+ }
3881+ return ret;
3882+}
3883+
3884+/* make map detail data for send */
3885+static void
3886+make_send_mapdetaildata (int userno,
3887+ unsigned char d[VIEW_LIMIT * VIEW_WIDTH * 16],
3888+ unsigned char crime[VIEW_LIMIT * VIEW_WIDTH])
3889+{
3890+ int x;
3891+ int y;
3892+ int i;
3893+ int direction = User[userno].direction;
3894+ unsigned char *p = d;
3895+ unsigned char *pcrime = crime;
3896+ x = User[userno].pos.x;
3897+ y = User[userno].pos.y;
3898+ for (i = 0; i < VIEW_LIMIT; i++)
3899+ {
3900+ int ny;
3901+ int nx;
3902+ nx = x - RGVectorX[direction] * 2;
3903+ ny = y - RGVectorY[direction] * 2;
3904+ adjust_pos (&nx, &ny);
3905+ *pcrime++ = copy_mapdetaildata (userno, p, nx, ny);
3906+ p += 16;
3907+ nx += RGVectorX[direction];
3908+ ny += RGVectorY[direction];
3909+ adjust_pos (&nx, &ny);
3910+ *pcrime++ = copy_mapdetaildata (userno, p, nx, ny);
3911+ p += 16;
3912+ *pcrime++ = copy_mapdetaildata (userno, p, x, y);
3913+ p += 16;
3914+ nx = x + RGVectorX[direction];
3915+ ny = y + RGVectorY[direction];
3916+ adjust_pos (&nx, &ny);
3917+ *pcrime++ = copy_mapdetaildata (userno, p, nx, ny);
3918+ p += 16;
3919+ nx += RGVectorX[direction];
3920+ ny += RGVectorY[direction];
3921+ adjust_pos (&nx, &ny);
3922+ *pcrime++ = copy_mapdetaildata (userno, p, nx, ny);
3923+ p += 16;
3924+ x += FWVectorX[direction];
3925+ y += FWVectorY[direction];
3926+ adjust_pos (&x, &y);
3927+ }
3928+ return;
3929+}
3930+
3931+/* make status information */
3932+static int
3933+MakeStatusData (int userno)
3934+{
3935+ int ret = 1;
3936+ int i;
3937+ unsigned char packet[PACKET_MAX];
3938+ unsigned char cwk;
3939+ int n = 2;
3940+ packet[0] = HSERV_STATUS;
3941+ cwk = User[userno].c_type & 0x0f;
3942+ if (User[userno].hungry > HungryBase)
3943+ {
3944+ cwk |= 0x40; /* full */
3945+ }
3946+ else if (User[userno].hungry > 50)
3947+ {
3948+ cwk |= 0x30; /* normal */
3949+ }
3950+ else if (User[userno].hungry > 10)
3951+ {
3952+ cwk |= 0x20; /* hungry */
3953+ }
3954+ else if (User[userno].hungry > 0)
3955+ {
3956+ cwk |= 0x10; /* weak */
3957+ }
3958+ packet[n++] = cwk;
3959+ *(unsigned short *) (packet + n) = htons (User[userno].pos.x);
3960+ n += 2;
3961+ *(unsigned short *) (packet + n) = htons (User[userno].pos.y);
3962+ n += 2;
3963+ *(unsigned long *) (packet + n) = htonl (User[userno].hp);
3964+ n += 4;
3965+ *(unsigned long *) (packet + n) = htonl (User[userno].score);
3966+ n += 4;
3967+ *(unsigned long *) (packet + n) = htonl (User[userno].maybearrest);
3968+ n += 4;
3969+ packet[n++] = User[userno].direction;
3970+ for (i = 0; i < WEAPON_MAX; i++)
3971+ {
3972+ memcpy (packet + n, Weapon[User[userno].weapon[i]].name,
3973+ WEAPONNAME_LEN);
3974+ n += WEAPONNAME_LEN;
3975+ }
3976+ for (i = 0; i < WEAPON_MAX; i++)
3977+ {
3978+ *(unsigned short *) (packet + n) = htons (User[userno].bullette[i]);
3979+ n += 2;
3980+ }
3981+ for (i = 0; i < ITEM_MAX; i++)
3982+ {
3983+ memcpy (packet + n, Item[User[userno].item[i]].name, ITEMNAME_LEN);
3984+ n += ITEMNAME_LEN;
3985+ }
3986+ for (i = 0; i < ITEM_MAX; i++)
3987+ {
3988+ *(unsigned short *) (packet + n) = htons (User[userno].itemcount[i]);
3989+ n += 2;
3990+ }
3991+ if (!memcmp (User[userno].statusinfo + 2, packet + 2, n - 2))
3992+ {
3993+ /* no need send */
3994+ ret = 0;
3995+ }
3996+ else
3997+ {
3998+ memcpy (User[userno].statusinfo, packet, n);
3999+ User[userno].statusinfosize = n;
4000+ }
4001+ return ret;
4002+}
4003+
4004+/* Make map data */
4005+static int
4006+MakeMapData (int userno)
4007+{
4008+ int ret = 1;
4009+ unsigned char packet[PACKET_MAX];
4010+ int n = 2;
4011+ packet[0] = HSERV_MAP;
4012+ make_send_mapdata (userno, packet + n);
4013+ if (User[userno].status == Arrested)
4014+ {
4015+ memset (packet + n, HCLIT_MAP_WALL, VIEW_WIDTH * 2);
4016+ }
4017+ else if (User[userno].status == Shopping)
4018+ {
4019+ memset (packet + n, HCLIT_MAP_SHOP, VIEW_WIDTH * 2);
4020+ }
4021+ n += VIEW_LIMIT * VIEW_WIDTH;
4022+ make_send_playeronmapdata (userno, packet + n);
4023+ n += VIEW_LIMIT * VIEW_WIDTH;
4024+ make_send_mapdetaildata (userno, packet + n,
4025+ packet + n + VIEW_LIMIT * VIEW_WIDTH * 16);
4026+ n += VIEW_LIMIT * VIEW_WIDTH * 16;
4027+ n += VIEW_LIMIT * VIEW_WIDTH;
4028+ if (!memcmp (User[userno].mapdata + 2, packet + 2, n - 2))
4029+ {
4030+ /* no need send */
4031+ ret = 0;
4032+ }
4033+ else
4034+ {
4035+ memcpy (User[userno].mapdata, packet, n);
4036+ User[userno].mapdatasize = n;
4037+ }
4038+ return ret;
4039+}
4040+
4041+/* check and send update information */
4042+static int
4043+SendUpdateInformation (int userno)
4044+{
4045+ int ret = -1;
4046+ if (User[userno].session.handle != INVALID_SOCKET)
4047+ {
4048+ int ntype = 0;
4049+ ret = 0;
4050+ if (MakeStatusData (userno))
4051+ {
4052+ ntype |= 1;
4053+ }
4054+ if (MakeMapData (userno))
4055+ {
4056+ ntype |= 2;
4057+ }
4058+ switch (ntype)
4059+ {
4060+ case 3:
4061+ {
4062+ int n;
4063+ char wkpacket[PACKET_MAX];
4064+ wkpacket[0] = HSERV_MAPANDSTATUS;
4065+ n = 2;
4066+ memcpy (wkpacket + n, User[userno].statusinfo + 2,
4067+ User[userno].statusinfosize - 2);
4068+ n += User[userno].statusinfosize - 2;
4069+ memcpy (wkpacket + n, User[userno].mapdata + 2,
4070+ User[userno].mapdatasize - 2);
4071+ n += User[userno].mapdatasize - 2;
4072+ ret = SENDPACKET (userno, (unsigned char *) wkpacket, n - 2);
4073+ }
4074+ break;
4075+ case 2:
4076+ ret = SENDPACKET (userno, User[userno].mapdata,
4077+ User[userno].mapdatasize - 2);
4078+ break;
4079+ case 1:
4080+ ret = SENDPACKET (userno, User[userno].statusinfo,
4081+ User[userno].statusinfosize - 2);
4082+ break;
4083+ default:
4084+ break;
4085+ }
4086+ }
4087+ return ret;
4088+}
4089+
4090+/* send message */
4091+static int
4092+SendMessagePacket (int userno, int srcuser, const char *p)
4093+{
4094+ int ret = -1;
4095+ if (User[userno].session.handle != INVALID_SOCKET)
4096+ {
4097+ unsigned char packet[PACKET_MAX];
4098+ int nlen = strlen (p);
4099+ packet[0] = HSERV_MESG;
4100+ memcpy (packet + 2, User[srcuser].name, 16);
4101+ if (nlen > PACKET_DATA_MAX - 17)
4102+ {
4103+ nlen = PACKET_DATA_MAX - 17;
4104+ }
4105+ packet[18] = nlen;
4106+ memcpy (packet + 19, p, nlen);
4107+ ret = SENDPACKET (userno, packet, nlen + 17);
4108+ }
4109+ return ret;
4110+}
4111+
4112+/* send system message */
4113+static int
4114+SendSystemMessagePacket (int userno, const char *p)
4115+{
4116+ int ret = -1;
4117+ if (User[userno].session.handle != INVALID_SOCKET)
4118+ {
4119+ unsigned char packet[PACKET_MAX];
4120+ int nlen = strlen (p);
4121+ packet[0] = HSERV_SYSMESG;
4122+ if (nlen > PACKET_DATA_MAX - 1)
4123+ {
4124+ nlen = PACKET_DATA_MAX - 1;
4125+ }
4126+ packet[2] = nlen;
4127+ memcpy (packet + 3, p, nlen);
4128+ ret = SENDPACKET (userno, packet, nlen + 1);
4129+ }
4130+ return ret;
4131+}
4132+
4133+/* send message to all user */
4134+static void
4135+SendMessageAllUser (const char *p)
4136+{
4137+ int i;
4138+ for (i = 0; i < UserLimit; i++)
4139+ {
4140+ if (User[i].session.handle != INVALID_SOCKET)
4141+ {
4142+ if (SendSystemMessagePacket (i, p))
4143+ {
4144+ DisconnectUser (i);
4145+ }
4146+ }
4147+ }
4148+ return;
4149+}
4150+
4151+/* send message to near user */
4152+static void
4153+SendMessageNearUser (int userno, const char *p)
4154+{
4155+ int i;
4156+ for (i = 0; i < UserLimit; i++)
4157+ {
4158+ if (i != userno)
4159+ {
4160+ if (User[i].session.handle != INVALID_SOCKET)
4161+ {
4162+ int n =
4163+ get_rel_distance (User[userno].pos.x, User[userno].pos.y,
4164+ User[i].pos.x, User[i].pos.y);
4165+ if (n <= HEARNEAR_DISTANCE)
4166+ {
4167+ if (SendSystemMessagePacket (i, p))
4168+ {
4169+ DisconnectUser (i);
4170+ }
4171+ }
4172+ }
4173+ }
4174+ }
4175+ return;
4176+}
4177+
4178+/* send message to near user and sender */
4179+static void
4180+SendMessageNearUserSender (int userno, const char *p)
4181+{
4182+ int i;
4183+ for (i = 0; i < UserLimit; i++)
4184+ {
4185+ if (User[i].session.handle != INVALID_SOCKET)
4186+ {
4187+ int n = get_rel_distance (User[userno].pos.x, User[userno].pos.y,
4188+ User[i].pos.x, User[i].pos.y);
4189+ if (n <= HEARNEAR_DISTANCE)
4190+ {
4191+ if (SendSystemMessagePacket (i, p))
4192+ {
4193+ DisconnectUser (i);
4194+ }
4195+ }
4196+ }
4197+ }
4198+ return;
4199+}
4200+
4201+/* send message to near user (origin animal)*/
4202+static void
4203+SendMessageNearUserAnimal (int animalno, const char *p)
4204+{
4205+ int i;
4206+ for (i = 0; i < UserLimit; i++)
4207+ {
4208+ if (User[i].session.handle != INVALID_SOCKET)
4209+ {
4210+ int n =
4211+ get_rel_distance (Animal[animalno].pos.x, Animal[animalno].pos.y,
4212+ User[i].pos.x, User[i].pos.y);
4213+ if (n <= HEARNEAR_DISTANCE)
4214+ {
4215+ if (SendSystemMessagePacket (i, p))
4216+ {
4217+ DisconnectUser (i);
4218+ }
4219+ }
4220+ }
4221+ }
4222+ return;
4223+}
4224+
4225+/* send message to near user (origin position)*/
4226+static void
4227+SendMessageNearUserPosition (struct location pos, const char *p)
4228+{
4229+ int i;
4230+ for (i = 0; i < UserLimit; i++)
4231+ {
4232+ if (User[i].session.handle != INVALID_SOCKET)
4233+ {
4234+ int n = get_rel_distance (pos.x, pos.y,
4235+ User[i].pos.x, User[i].pos.y);
4236+ if (n <= HEARNEAR_DISTANCE)
4237+ {
4238+ if (SendSystemMessagePacket (i, p))
4239+ {
4240+ DisconnectUser (i);
4241+ }
4242+ }
4243+ }
4244+ }
4245+ return;
4246+}
4247+
4248+/* send message to near user (origin position, exclude nuser)*/
4249+static void
4250+SendMessageNearUserPosition2 (struct location pos, const char *p, int nuser)
4251+{
4252+ int i;
4253+ for (i = 0; i < UserLimit; i++)
4254+ {
4255+ if (i != nuser && User[i].session.handle != INVALID_SOCKET)
4256+ {
4257+ int n = get_rel_distance (pos.x, pos.y,
4258+ User[i].pos.x, User[i].pos.y);
4259+ if (n <= HEARNEAR_DISTANCE)
4260+ {
4261+ if (SendSystemMessagePacket (i, p))
4262+ {
4263+ DisconnectUser (i);
4264+ }
4265+ }
4266+ }
4267+ }
4268+ return;
4269+}
4270+
4271+/* send user list */
4272+static int
4273+SendUserListPacket (int userno)
4274+{
4275+ int ret = -1;
4276+ if (User[userno].session.handle != INVALID_SOCKET)
4277+ {
4278+ int i;
4279+ unsigned char packet[PACKET_MAX];
4280+ ret = 0;
4281+ SendSystemMessagePacket (userno, "==== registered people ====");
4282+ for (i = 0; i < UserLimit && !ret; i++)
4283+ {
4284+ if (User[i].name[0] != '\0')
4285+ {
4286+ int n = 2;
4287+ packet[0] = HSERV_WHO;
4288+ memcpy (packet + n, User[i].name, 16);
4289+ n += 16;
4290+ *(unsigned long *) (packet + n) = htonl (User[i].score);
4291+ n += 4;
4292+ packet[n++] =
4293+ (User[i].session.handle != INVALID_SOCKET) ? 1 : 0;
4294+ packet[n++] = User[i].c_type;
4295+ ret = SENDPACKET (userno, packet, n - 2);
4296+ }
4297+ }
4298+ SendSystemMessagePacket (userno, "==== end of list ====");
4299+ }
4300+ return ret;
4301+}
4302+
4303+/* Send Effect 'damage' packet */
4304+static int
4305+SendEffectDamagePacket (int userno)
4306+{
4307+ int ret = -1;
4308+ if (User[userno].session.handle != INVALID_SOCKET)
4309+ {
4310+ unsigned char packet[PACKET_MAX];
4311+ packet[0] = HSERV_EFFECT_DAMAGE;
4312+ ret = SENDPACKET (userno, packet, 0);
4313+ }
4314+ return ret;
4315+}
4316+
4317+/* Send Effect 'death' packet */
4318+static int
4319+SendEffectDeathPacket (int userno)
4320+{
4321+ int ret = -1;
4322+ if (User[userno].session.handle != INVALID_SOCKET)
4323+ {
4324+ unsigned char packet[PACKET_MAX];
4325+ packet[0] = HSERV_EFFECT_DEATH;
4326+ ret = SENDPACKET (userno, packet, 0);
4327+ }
4328+ return ret;
4329+}
4330+
4331+/* Send Effect 'diggin' packet */
4332+static int
4333+SendEffectDiggingPacket (int userno)
4334+{
4335+ int ret = -1;
4336+ if (User[userno].session.handle != INVALID_SOCKET)
4337+ {
4338+ unsigned char packet[PACKET_MAX];
4339+ packet[0] = HSERV_EFFECT_DIGGING;
4340+ ret = SENDPACKET (userno, packet, 0);
4341+ }
4342+ return ret;
4343+}
4344+
4345+/* Send Effect 'fall in hole' packet */
4346+static int
4347+SendEffectFallInHolePacket (int userno)
4348+{
4349+ int ret = -1;
4350+ if (User[userno].session.handle != INVALID_SOCKET)
4351+ {
4352+ unsigned char packet[PACKET_MAX];
4353+ packet[0] = HSERV_EFFECT_FALL;
4354+ ret = SENDPACKET (userno, packet, 0);
4355+ }
4356+ return ret;
4357+}
4358+
4359+#ifdef USE_MAIL
4360+/* send mail header */
4361+static int
4362+SendMailHeader (int userno, MAILDATA * p)
4363+{
4364+ int ret = -1;
4365+ if (User[userno].session.handle != INVALID_SOCKET)
4366+ {
4367+ unsigned char packet[PACKET_MAX];
4368+ int n = 2;
4369+ packet[0] = HSERV_SENDMAIL;
4370+ memcpy (packet + n, User[p->fromuser].name, 16);
4371+ n += 16;
4372+ *(unsigned long *) (packet + n) = htonl (p->timestamp);
4373+ n += 4;
4374+ packet[n++] = p->subject[0];
4375+ if (p->subject[0])
4376+ {
4377+ memcpy (packet + n, p->subject + 1, p->subject[0]);
4378+ n += p->subject[0];
4379+ }
4380+ ret = SENDPACKET (userno, packet, n - 2);
4381+ }
4382+ return ret;
4383+}
4384+
4385+/* send mail body */
4386+static int
4387+SendMailBody (int userno, MAILDATA * p)
4388+{
4389+ int ret = -1;
4390+ if (User[userno].session.handle != INVALID_SOCKET)
4391+ {
4392+ unsigned char packet[PACKET_MAX];
4393+ int i;
4394+ for (i = 0; i < p->line; i++)
4395+ {
4396+ int n = 2;
4397+ packet[0] = HSERV_SENDMAILBODY;
4398+ packet[n++] = p->message[i][0];
4399+ if (p->message[i][0])
4400+ {
4401+ memcpy (packet + n, &p->message[i][1], p->message[i][0]);
4402+ n += p->message[i][0];
4403+ }
4404+ ret = SENDPACKET (userno, packet, n - 2);
4405+ if (ret)
4406+ {
4407+ return ret;
4408+ }
4409+ }
4410+ packet[0] = HSERV_SENDEND;
4411+ ret = SENDPACKET (userno, packet, 0);
4412+ }
4413+ return ret;
4414+}
4415+
4416+#ifdef USE_BBS
4417+/* send BBS header */
4418+static int
4419+SendBBSHeader (int userno, MAILDATA * p)
4420+{
4421+ int ret = -1;
4422+ if (User[userno].session.handle != INVALID_SOCKET)
4423+ {
4424+ unsigned char packet[PACKET_MAX];
4425+ int n = 2;
4426+ packet[0] = HSERV_BBS_HEADER;
4427+ memcpy (packet + n, User[p->fromuser].name, 16);
4428+ n += 16;
4429+ *(unsigned long *) (packet + n) = htonl (p->timestamp);
4430+ n += 4;
4431+ packet[n++] = p->subject[0];
4432+ if (p->subject[0])
4433+ {
4434+ memcpy (packet + n, p->subject + 1, p->subject[0]);
4435+ n += p->subject[0];
4436+ }
4437+ ret = SENDPACKET (userno, packet, n - 2);
4438+ }
4439+ return ret;
4440+}
4441+
4442+/* send bbs body */
4443+static int
4444+SendBBSBody (int userno, MAILDATA * p)
4445+{
4446+ int ret = -1;
4447+ if (User[userno].session.handle != INVALID_SOCKET)
4448+ {
4449+ unsigned char packet[PACKET_MAX];
4450+ int i;
4451+ for (i = 0; i < p->line; i++)
4452+ {
4453+ int n = 2;
4454+ packet[0] = HSERV_BBS_BODY;
4455+ packet[n++] = p->message[i][0];
4456+ if (p->message[i][0])
4457+ {
4458+ memcpy (packet + n, &p->message[i][1], p->message[i][0]);
4459+ n += p->message[i][0];
4460+ }
4461+ ret = SENDPACKET (userno, packet, n - 2);
4462+ if (ret)
4463+ {
4464+ return ret;
4465+ }
4466+ }
4467+ packet[0] = HSERV_BBS_BODYEND;
4468+ ret = SENDPACKET (userno, packet, 0);
4469+ }
4470+ return ret;
4471+}
4472+
4473+#endif /* USE_BBS */
4474+#endif /* USE_MAIL */
4475+
4476+/* send user shop list */
4477+static void
4478+SendUserShopList (int nowner, int nuser, int n)
4479+{
4480+ int i;
4481+ char work[MESG_BUFFER];
4482+ int nshop =
4483+ searchUserShopFromPos (nowner, User[nuser].pos.x, User[nuser].pos.y);
4484+ if (nshop == -1 || User[nowner].myshop[nshop].build == 0)
4485+ {
4486+ /* error ?? */
4487+ SendSystemMessagePacket (nuser, "(FATAL:user shop linkage is broken)");
4488+ return;
4489+ }
4490+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
4491+ {
4492+ if (User[nowner].myshop[nshop].count[n][i])
4493+ {
4494+ sprintf (work,
4495+ n ? "<%2d:%-32.32s:%10luP %4ucount (stock:%4u)>" :
4496+ "<%2d:%-32.32s:%10luP %4uround (stock:%4u)>",
4497+ i,
4498+ (n ? Item[User[nowner].myshop[nshop].list[n][i]].name :
4499+ Weapon[User[nowner].myshop[nshop].list[n][i]].name),
4500+ User[nowner].myshop[nshop].cost[n][i],
4501+ User[nowner].myshop[nshop].leftuse[n][i],
4502+ User[nowner].myshop[nshop].count[n][i]);
4503+ SendSystemMessagePacket (nuser, work);
4504+ }
4505+ }
4506+ return;
4507+}
4508+
4509+/* send weapon list */
4510+static void
4511+SendWeaponList (int nuser)
4512+{
4513+ int nowner = MAP (User[nuser].pos.x, User[nuser].pos.y)->owner;
4514+ SendSystemMessagePacket (nuser, "<WEAPON LIST>");
4515+ if (nowner)
4516+ {
4517+ SendUserShopList (nowner - 1, nuser, 0);
4518+ }
4519+ else
4520+ {
4521+ int i;
4522+ char work[PACKET_DATA_MAX + 1];
4523+ int *plist;
4524+ int nmax;
4525+ if (User[nuser].c_type == Hunter)
4526+ {
4527+ plist = ForHunterWeapon;
4528+ nmax = ForHunterWeaponLimit;
4529+ }
4530+ else
4531+ {
4532+ plist = ForObserverWeapon;
4533+ nmax = ForObserverWeaponLimit;
4534+ }
4535+ for (i = 0; i < nmax; i++)
4536+ {
4537+ WEAPONINFO *pw = Weapon + plist[i];
4538+ sprintf (work, "<%3d:%-32.32s:%10luP %4uround %4u/%4u %4ublock>",
4539+ i, pw->name, pw->cost, pw->bullette,
4540+ pw->firepower, pw->moral, pw->range);
4541+ SendSystemMessagePacket (nuser, work);
4542+ }
4543+ }
4544+ SendSystemMessagePacket (nuser, "<end of list>");
4545+ return;
4546+}
4547+
4548+/* send item list */
4549+static void
4550+SendItemList (int nuser)
4551+{
4552+ int nowner = MAP (User[nuser].pos.x, User[nuser].pos.y)->owner;
4553+ SendSystemMessagePacket (nuser, "<ITEM LIST>");
4554+ if (nowner)
4555+ {
4556+ SendUserShopList (nowner - 1, nuser, 1);
4557+ }
4558+ else
4559+ {
4560+ int i;
4561+ char work[PACKET_DATA_MAX + 1];
4562+ int *plist;
4563+ int nmax;
4564+ if (User[nuser].c_type == Hunter)
4565+ {
4566+ plist = ForHunterItem;
4567+ nmax = ForHunterItemLimit;
4568+ }
4569+ else
4570+ {
4571+ plist = ForObserverItem;
4572+ nmax = ForObserverItemLimit;
4573+ }
4574+ for (i = 0; i < nmax; i++)
4575+ {
4576+ ITEMINFO *pi = Item + plist[i];
4577+ sprintf (work, "<%3d:%-32.32s:%10luP %4ucount>",
4578+ i, pi->name, pi->cost, pi->count);
4579+ SendSystemMessagePacket (nuser, work);
4580+ }
4581+ }
4582+ SendSystemMessagePacket (nuser, "<end of list>");
4583+ return;
4584+}
4585+
4586+/* send who list */
4587+static void
4588+SendWhoList (int nuser)
4589+{
4590+ if (SendUserListPacket (nuser))
4591+ {
4592+ DisconnectUser (nuser);
4593+ }
4594+ return;
4595+}
4596+
4597+/* send startup map data */
4598+static int
4599+SendStartupMapData (int nuser)
4600+{
4601+ int ret = -1;
4602+ if (User[nuser].session.handle != INVALID_SOCKET)
4603+ {
4604+ unsigned char packet[PACKET_MAX];
4605+ int n;
4606+ packet[0] = HSERV_TRANSMAP_START;
4607+ n = 2;
4608+ *(unsigned short *) (packet + n) = htons (MapWidth);
4609+ n += 2;
4610+ *(unsigned short *) (packet + n) = htons (MapHeight);
4611+ n += 2;
4612+ ret = SENDPACKET (nuser, packet, n - 2);
4613+ if (ret == 0)
4614+ {
4615+ /* map data transfer */
4616+ int i;
4617+ n = 2;
4618+ packet[0] = HSERV_TRANSMAP_CHUNK;
4619+ for (i = 0; i < MapWidth * MapHeight; i++)
4620+ {
4621+ if (Map[i].id & MAP_THERE_SHOP)
4622+ {
4623+ if (Map[i].owner)
4624+ {
4625+ /* perhaps,it is user shop. */
4626+ packet[n++] = HCLIT_MAP_USERSHOP;
4627+ }
4628+ else
4629+ {
4630+ packet[n++] = HCLIT_MAP_SHOP;
4631+ }
4632+ }
4633+ else if (Map[i].id & MAP_THERE_WALL)
4634+ {
4635+ packet[n++] = HCLIT_MAP_WALL;
4636+ }
4637+ else
4638+ {
4639+ if ((Map[i].id & MAP_MASK) == MAP_ROCK)
4640+ {
4641+ packet[n++] = HCLIT_MAP_ROCK;
4642+ }
4643+ else
4644+ {
4645+ packet[n++] = HCLIT_MAP_ROAD;
4646+ }
4647+ }
4648+ if (n == 2 + SENDMAP_CHUNK)
4649+ {
4650+ /* ok. send packet. */
4651+ ret = SENDPACKET (nuser, packet, n - 2);
4652+ n = 2;
4653+ if (ret)
4654+ {
4655+ break;
4656+ }
4657+ }
4658+ }
4659+ if (n != 2)
4660+ {
4661+ for (; n < 2 + SENDMAP_CHUNK; n++)
4662+ {
4663+ packet[n] = HCLIT_MAP_ROAD;
4664+ }
4665+ ret = SENDPACKET (nuser, packet, n - 2);
4666+ }
4667+ }
4668+ }
4669+ return ret;
4670+}
4671+
4672+/********************************************************/
4673+/* npc say */
4674+static void
4675+NPCsay (int npc, const char *mesg[], int nmax)
4676+{
4677+ char work[MESG_BUFFER];
4678+ sprintf (work, mesg[getrand (0, nmax - 1)], CUTTAIL (Npc[npc].name));
4679+ SendMessageNearUserPosition (Npc[npc].pos, work);
4680+ return;
4681+}
4682+
4683+/* cause damage */
4684+static void
4685+cause_damage (int nuser, unsigned ndamage, int fromuser, enum target_type t)
4686+{
4687+ if (ndamage && User[nuser].hp)
4688+ {
4689+ SendEffectDamagePacket (nuser);
4690+ if (t == TargetNpc && Npc[fromuser].name[0] == '\0')
4691+ {
4692+ fromuser = -1;
4693+ }
4694+ if (fromuser >= 0)
4695+ {
4696+ char work[PACKET_DATA_MAX - 1];
4697+ switch (t)
4698+ {
4699+ case TargetUser:
4700+ sprintf (work, "%-.16s damages you. lost %uHP.",
4701+ CUTTAIL (User[fromuser].name), ndamage);
4702+ break;
4703+ case TargetNpc:
4704+ sprintf (work, "%-.16s damages you. lost %uHP.",
4705+ CUTTAIL (Npc[fromuser].name), ndamage);
4706+ break;
4707+ case TargetAnimal:
4708+ sprintf (work, "Animal '%-.16s' damages you. lost %uHP",
4709+ CUTTAIL (Animal[fromuser].name), ndamage);
4710+ break;
4711+ default:
4712+ work[0] = '\0';
4713+ break;
4714+ }
4715+ if (work[0])
4716+ {
4717+ SendSystemMessagePacket (nuser, work);
4718+ }
4719+ if (t == TargetUser)
4720+ {
4721+ sprintf (work, "You attack %-.16s", CUTTAIL (User[nuser].name));
4722+ SendSystemMessagePacket (fromuser, work);
4723+ }
4724+ }
4725+ if (User[nuser].hp)
4726+ {
4727+ User[nuser].lastuser = fromuser;
4728+ User[nuser].lastuser_type = t;
4729+ }
4730+ if (User[nuser].hp > ndamage)
4731+ {
4732+ User[nuser].hp -= ndamage;
4733+ }
4734+ else
4735+ {
4736+ User[nuser].hp = 0;
4737+ }
4738+ }
4739+ return;
4740+}
4741+
4742+/* cause damage to animal */
4743+static void
4744+cause_damage_animal (int nanimal, unsigned ndamage, unsigned nmoral)
4745+{
4746+ if (Animal[nanimal].hp)
4747+ {
4748+ if (Animal[nanimal].moral > nmoral)
4749+ {
4750+ Animal[nanimal].moral -= nmoral;
4751+ }
4752+ else
4753+ {
4754+ Animal[nanimal].moral = 0;
4755+ }
4756+ if (Animal[nanimal].hp > ndamage)
4757+ {
4758+ Animal[nanimal].hp -= ndamage;
4759+ }
4760+ else
4761+ {
4762+ Animal[nanimal].hp = 0;
4763+ }
4764+ }
4765+ return;
4766+}
4767+
4768+/* cause damage to npc */
4769+static void
4770+cause_damage_npc (int npc, unsigned ndamage)
4771+{
4772+ if (Npc[npc].hp)
4773+ {
4774+ if (Npc[npc].hp > ndamage)
4775+ {
4776+ Npc[npc].hp -= ndamage;
4777+ }
4778+ else
4779+ {
4780+ Npc[npc].hp = 0;
4781+ }
4782+ }
4783+ return;
4784+}
4785+
4786+/* heal */
4787+static void
4788+cause_heal (int nuser, unsigned nheal)
4789+{
4790+ if (User[nuser].hp + nheal <= HpLimit)
4791+ {
4792+ User[nuser].hp += nheal;
4793+ }
4794+ else
4795+ {
4796+ User[nuser].hp = HpLimit;
4797+ }
4798+ return;
4799+}
4800+
4801+/* eat */
4802+static void
4803+cause_eat (int nuser, unsigned neat)
4804+{
4805+ if (User[nuser].hungry + neat <= HungryLimit)
4806+ {
4807+ User[nuser].hungry += neat;
4808+ }
4809+ else
4810+ {
4811+ User[nuser].hungry = HungryLimit;
4812+ }
4813+ return;
4814+}
4815+
4816+/* add score */
4817+static void
4818+add_score (int nuser, unsigned nscore)
4819+{
4820+ if (nscore)
4821+ {
4822+ User[nuser].score += nscore;
4823+ if (User[nuser].score > SCORE_LIMIT)
4824+ {
4825+ User[nuser].score = SCORE_LIMIT;
4826+ }
4827+ }
4828+ return;
4829+}
4830+
4831+/* decrement score */
4832+static void
4833+dec_score (int nuser, unsigned nscore)
4834+{
4835+ if (nscore)
4836+ {
4837+ if (User[nuser].score > nscore)
4838+ {
4839+ User[nuser].score -= nscore;
4840+ }
4841+ else
4842+ {
4843+ User[nuser].score = 0;
4844+ }
4845+ }
4846+ return;
4847+}
4848+
4849+/* add crime point */
4850+static void
4851+add_crime (int nuser, unsigned ncrime)
4852+{
4853+ if (ncrime)
4854+ {
4855+ User[nuser].maybearrest += ncrime;
4856+ if (User[nuser].maybearrest > SCORE_LIMIT)
4857+ {
4858+ User[nuser].maybearrest = SCORE_LIMIT;
4859+ }
4860+ switch (User[nuser].crime_level)
4861+ {
4862+ case 0:
4863+ if (User[nuser].maybearrest > ArrestPass)
4864+ {
4865+ User[nuser].crime_level = 1;
4866+ }
4867+ case 1:
4868+ if (User[nuser].maybearrest > ArrestAnyone)
4869+ {
4870+ User[nuser].crime_level = 2;
4871+ }
4872+ }
4873+ }
4874+ return;
4875+}
4876+
4877+/* add arrest */
4878+static void
4879+add_arrest (int nuser)
4880+{
4881+ if (User[nuser].arrest_count + 1 < ARREST_LIMIT)
4882+ {
4883+ User[nuser].arrest_count++;
4884+ }
4885+ else
4886+ {
4887+ SendSystemMessagePacket (nuser, "[You were arrested too many times!]");
4888+ SendSystemMessagePacket (nuser, "[You were executed!]");
4889+ User[nuser].hp = 0;
4890+ User[nuser].lastuser = -1;
4891+ }
4892+ return;
4893+}
4894+
4895+/********************************************************/
4896+/* make new connection */
4897+static int
4898+NewConnection (SESSION * psession)
4899+{
4900+ int ret = -1;
4901+ unsigned char packet[PACKET_MAX];
4902+ union ipaddr_u
4903+ {
4904+ unsigned long addr_l;
4905+ unsigned char addr[4];
4906+ }
4907+ wkadr;
4908+
4909+ wkadr.addr_l = psession->addr;
4910+ printf ("try new connection...from %u.%u.%u.%u:%u\n",
4911+ wkadr.addr[0], wkadr.addr[1], wkadr.addr[2], wkadr.addr[3],
4912+ ntohs (psession->port));
4913+ if (receive_packet_c (psession->handle, packet, PACKET_DATA_MAX) == 0)
4914+ {
4915+ printf ("packet ID:%02x length:%d\n", packet[0] & 0x3f,
4916+ packet[1] + ((int) (packet[0] & 0xc0) << 2));
4917+ packet[0] &= 0x3f;
4918+ if (packet[0] == HCLIT_LOGIN)
4919+ {
4920+ /* login */
4921+ int nuser = SearchUser ((char *) (packet + 2));
4922+ puts ("attempt to login.");
4923+ if (packet[1] != 16 + 16 + 2 ||
4924+ packet[2 + 16 + 16 + 1] != HPROTOCOL_VERSION)
4925+ {
4926+ /* illegal protocol */
4927+ puts ("protocol mismatch.");
4928+ SendResultPacket (psession->handle, -1);
4929+ }
4930+ else if (nuser != -1)
4931+ {
4932+ int i;
4933+ const unsigned char *p = packet + 2 + 16;
4934+ char uname[USERNAME_LEN];
4935+ char work[PASSWORD_LEN];
4936+ memcpy (uname, User[nuser].name, USERNAME_LEN);
4937+#ifdef MAKEWIN32
4938+ convertH2C (uname, USERNAME_LEN);
4939+#endif
4940+ printf ("User name:%-16.16s\n", uname);
4941+ for (i = 0; i < PASSWORD_LEN; i++)
4942+ {
4943+ if (*(p + i) == '\0')
4944+ {
4945+ break;
4946+ }
4947+ work[i] = *(p + i);
4948+ }
4949+ for (; i < PASSWORD_LEN; i++)
4950+ {
4951+ work[i] = ' ';
4952+ }
4953+ if (memcmp (User[nuser].password, work, PASSWORD_LEN) == 0)
4954+ {
4955+ /* password check is ok */
4956+ if (User[nuser].session.handle != INVALID_SOCKET)
4957+ {
4958+ /* already login */
4959+ /* cut connection */
4960+ puts ("cut old connection.");
4961+ cutsocket (User[nuser].session.handle);
4962+ User[nuser].session.handle = INVALID_SOCKET;
4963+ }
4964+ if (SendResultPacket (psession->handle, 0) == -1)
4965+ {
4966+ /* ?? error */
4967+ puts ("can't send result. fail to login.");
4968+ DisconnectUser (nuser);
4969+ }
4970+ else
4971+ {
4972+ User[nuser].session = *psession;
4973+#ifdef USE_FORK
4974+ create_send_process (nuser, psession->handle);
4975+#endif
4976+#ifdef USE_W32THREAD
4977+ create_send_message_queue_thread (nuser);
4978+#endif
4979+ ActivateUser (nuser);
4980+ puts ("send startup map data...");
4981+ if (SendStartupMapData (nuser) == -1)
4982+ {
4983+ /* ?? error */
4984+ puts ("can't send startup map data. fail to login");
4985+ DisconnectUser (nuser);
4986+ }
4987+ else
4988+ {
4989+ puts ("Ok");
4990+ SendSystemMessagePacket (nuser, ServerInfo);
4991+ if (User[nuser].status == Arrested)
4992+ {
4993+ SendSystemMessagePacket (nuser,
4994+ "[Welcome to Jail!]");
4995+ }
4996+#ifdef USE_MAIL
4997+ if (CheckNewMail (nuser))
4998+ {
4999+ /* new mail! */
5000+ SendSystemMessagePacket (nuser,
5001+ "[You have new mail]");
5002+ }
5003+#endif
5004+ ret = 0;
5005+ }
5006+ }
5007+ }
5008+ else
5009+ {
5010+ puts ("mismatch password.");
5011+ SendResultPacket (psession->handle, -1);
5012+ }
5013+ }
5014+ else
5015+ {
5016+ puts ("no user.");
5017+ SendResultPacket (psession->handle, -1);
5018+ }
5019+ }
5020+ else if (packet[0] == HCLIT_NEWUSER)
5021+ {
5022+ /* new user */
5023+ puts ("attempt to create new user");
5024+ if (packet[1] == USERNAME_LEN + PASSWORD_LEN + 16 + PASSWORD_LEN)
5025+ {
5026+ /* ok */
5027+ if (packet[2 + 16 + 16 + 1] != HPROTOCOL_VERSION)
5028+ {
5029+ /* illegal protocol */
5030+ puts ("protocol mismatch");
5031+ SendResultPacket (psession->handle, -1);
5032+ }
5033+ else if (memcmp (packet + 2 + 16 + 16 + 16, makeUserKey,
5034+ PASSWORD_LEN))
5035+ {
5036+ /* illegal system password */
5037+ puts ("system password mismatch");
5038+ printf ("Client key[%-16.16s]\n",
5039+ packet + 2 + 16 + 16 + 16);
5040+ SendResultPacket (psession->handle, -1);
5041+ }
5042+ else
5043+ {
5044+ int nuser = NewUser ((char *) (packet + 2));
5045+ printf ("NewUser check:%d\n", nuser);
5046+ if (nuser == -2)
5047+ {
5048+ /* double user */
5049+ puts ("double user");
5050+ SendResultPacket (psession->handle, -1);
5051+ }
5052+ else if (nuser == -1)
5053+ {
5054+ /* error */
5055+ puts ("error?");
5056+ SendResultPacket (psession->handle, -1);
5057+ }
5058+ else
5059+ {
5060+ int i;
5061+ char *ps;
5062+ char *pd;
5063+ puts ("ok. new user!");
5064+ ps = (char *) (packet + 2 + 16);
5065+ pd = User[nuser].password;
5066+ for (i = 0; i < PASSWORD_LEN; i++)
5067+ {
5068+ if (*(ps + i) == '\0')
5069+ {
5070+ break;
5071+ }
5072+ *pd++ = *(ps + i);
5073+ }
5074+ for (; i < PASSWORD_LEN; i++)
5075+ {
5076+ *pd++ = ' ';
5077+ }
5078+ User[nuser].c_type =
5079+ packet[2 + 16 + 16] ? Observer : Hunter;
5080+ if (SendResultPacket (psession->handle, 0) == -1)
5081+ {
5082+ /* ?? error */
5083+ puts ("occur error in make new user");
5084+ DisconnectUser (nuser);
5085+ }
5086+ else
5087+ {
5088+ User[nuser].session = *psession;
5089+#ifdef USE_FORK
5090+ create_send_process (nuser, psession->handle);
5091+#endif
5092+#ifdef USE_W32THREAD
5093+ create_send_message_queue_thread (nuser);
5094+#endif
5095+ ActivateUser (nuser);
5096+ puts ("send startup map data...");
5097+ if (SendStartupMapData (nuser) == -1)
5098+ {
5099+ /* ?? error */
5100+ puts
5101+ ("can't send startup map data. fail to login");
5102+ DisconnectUser (nuser);
5103+ }
5104+ else
5105+ {
5106+ SendSystemMessagePacket (nuser, ServerInfo);
5107+ puts ("success.");
5108+ ret = 0;
5109+ }
5110+ }
5111+ }
5112+ }
5113+ }
5114+ }
5115+ else if (packet[0] == HCLIT_DELUSER)
5116+ {
5117+ int nuser = SearchUser ((char *) (packet + 2));
5118+ puts ("attempt to delete.");
5119+ if (nuser != -1)
5120+ {
5121+ int i;
5122+ const unsigned char *p = packet + 2 + 16;
5123+ char uname[USERNAME_LEN];
5124+ char work[PASSWORD_LEN];
5125+ memcpy (uname, User[nuser].name, USERNAME_LEN);
5126+#ifdef MAKEWIN32
5127+ convertH2C (uname, USERNAME_LEN);
5128+#endif
5129+ printf ("User name:%-16.16s\n", uname);
5130+ for (i = 0; i < PASSWORD_LEN; i++)
5131+ {
5132+ if (*(p + i) == '\0')
5133+ {
5134+ break;
5135+ }
5136+ work[i] = *(p + i);
5137+ }
5138+ for (; i < PASSWORD_LEN; i++)
5139+ {
5140+ work[i] = ' ';
5141+ }
5142+ if (memcmp (User[nuser].password, work, PASSWORD_LEN) == 0)
5143+ {
5144+ /* ok. delete this user. */
5145+ puts ("OK. delete this user.");
5146+ DeleteUser (nuser);
5147+ SendResultPacket (psession->handle, 0);
5148+ }
5149+ else
5150+ {
5151+ puts ("password mismatch.");
5152+ SendResultPacket (psession->handle, -1);
5153+ }
5154+ }
5155+ else
5156+ {
5157+ puts ("no user.");
5158+ SendResultPacket (psession->handle, -1);
5159+ }
5160+ }
5161+ }
5162+ return ret;
5163+}
5164+
5165+/* check new connection */
5166+static void
5167+CheckNewConnection (void)
5168+{
5169+ SESSION session;
5170+ if (waitconnect (mainSocket, &session) == 0)
5171+ {
5172+ /* success connect */
5173+ puts ("connected.");
5174+ if (NewConnection (&session) == -1)
5175+ {
5176+ /* occur error */
5177+ puts ("occur error");
5178+ if (session.handle != INVALID_SOCKET)
5179+ {
5180+ cutsocket (session.handle);
5181+ }
5182+ }
5183+ else
5184+ {
5185+ puts ("ok. comming new user.");
5186+ FD_SET (session.handle, &mainFDS);
5187+ }
5188+ }
5189+ return;
5190+}
5191+
5192+/********************************************************/
5193+/* move command */
5194+static void
5195+doMove (int nuser, int n)
5196+{
5197+ if (n >= 0 && n <= 3)
5198+ {
5199+ User[nuser].move = n + 1;
5200+ }
5201+ return;
5202+}
5203+
5204+/* change direction command */
5205+static void
5206+doChangeDirection (int nuser, int n)
5207+{
5208+ if (n >= 0 && n <= 3)
5209+ {
5210+ User[nuser].wk_direction = n;
5211+ }
5212+ return;
5213+}
5214+
5215+/* fire weaon command */
5216+static void
5217+doFire (int nuser, int n)
5218+{
5219+ if (n == 1)
5220+ {
5221+ User[nuser].action = Fire1;
5222+ }
5223+ else if (n == 2)
5224+ {
5225+ User[nuser].action = Fire2;
5226+ }
5227+ return;
5228+}
5229+
5230+/* use item command */
5231+static void
5232+doUseItem (int nuser, int n)
5233+{
5234+ switch (n)
5235+ {
5236+ case 1:
5237+ User[nuser].action = UseItem1;
5238+ break;
5239+ case 2:
5240+ User[nuser].action = UseItem2;
5241+ break;
5242+ case 3:
5243+ User[nuser].action = UseItem3;
5244+ break;
5245+ case 4:
5246+ User[nuser].action = UseItem4;
5247+ break;
5248+ }
5249+ return;
5250+}
5251+
5252+/* pickup command */
5253+static void
5254+doPickUp (int nuser)
5255+{
5256+ User[nuser].action = PickUp;
5257+ return;
5258+}
5259+
5260+/* pay command */
5261+static void
5262+doPay (int nuser)
5263+{
5264+ User[nuser].action = Pay;
5265+ return;
5266+}
5267+
5268+/* buy command */
5269+static void
5270+doBuy (int nuser, int n, int m)
5271+{
5272+ User[nuser].action = n ? BuyItem : BuyWeapon;
5273+ User[nuser].wk_for_action = m;
5274+ return;
5275+}
5276+
5277+/* who command */
5278+static void
5279+doWho (int nuser)
5280+{
5281+ User[nuser].action = Who;
5282+ return;
5283+}
5284+
5285+/* request weapon list command */
5286+static void
5287+doListWeapon (int nuser)
5288+{
5289+ User[nuser].action = RequestWeapon;
5290+ return;
5291+}
5292+
5293+/* request item list command */
5294+static void
5295+doListItem (int nuser)
5296+{
5297+ User[nuser].action = RequestItem;
5298+ return;
5299+}
5300+
5301+/* store lastpickup-animal */
5302+static void
5303+doStoreAnimal (int nuser, unsigned long lwk)
5304+{
5305+ User[nuser].action = StoreAnimal;
5306+ User[nuser].lwk_for_action = lwk;
5307+ return;
5308+}
5309+
5310+/* store item or weapn */
5311+static void
5312+doStoreObj (int nuser, int n, int m, unsigned long lwk)
5313+{
5314+ User[nuser].action = n ? StoreItem : StoreWeapon;
5315+ User[nuser].wk_for_action = m - 1;
5316+ User[nuser].lwk_for_action = lwk;
5317+ return;
5318+}
5319+
5320+/* discard item or weapon in shop */
5321+static void
5322+doDiscardMyshopObj (int nuser, int n, int m)
5323+{
5324+ User[nuser].action = n ? DiscardItem : DiscardWeapon;
5325+ User[nuser].wk_for_action = m;
5326+ return;
5327+}
5328+
5329+/* list up my shop */
5330+static void
5331+doListMyshop (int nuser)
5332+{
5333+ User[nuser].action = ListMyShop;
5334+ return;
5335+}
5336+
5337+/* list up my animal */
5338+static void
5339+doListMyAnimal (int nuser)
5340+{
5341+ User[nuser].action = ListMyAnimal;
5342+ return;
5343+}
5344+
5345+/* list up live animal */
5346+static void
5347+doListLiveAnimal (int nuser)
5348+{
5349+ User[nuser].action = ListLiveAnimal;
5350+ return;
5351+}
5352+
5353+/* drop weapon or item */
5354+static void
5355+doDropObj (int nuser, int n, int m, const unsigned char *p)
5356+{
5357+ int nlen = *p;
5358+ User[nuser].action = n ? DropItem : DropWeapon;
5359+ User[nuser].wk_for_action = m - 1;
5360+ if (nlen > sizeof (User[nuser].mesg_for_action) - 1)
5361+ {
5362+ nlen = sizeof (User[nuser].mesg_for_action) - 1;
5363+ }
5364+ if (nlen)
5365+ {
5366+ strncpy (User[nuser].mesg_for_action, (char *) (p + 1), nlen);
5367+ }
5368+ User[nuser].mesg_for_action[nlen] = '\0';
5369+ return;
5370+}
5371+
5372+/* do say command */
5373+static void
5374+doSay (int nuser, unsigned char *p)
5375+{
5376+ User[nuser].action = DoSay;
5377+ memcpy (User[nuser].mesg_for_action, p,
5378+ sizeof (User[nuser].mesg_for_action));
5379+ return;
5380+}
5381+
5382+/* do tell command */
5383+static void
5384+doTell (int nuser, unsigned char *p)
5385+{
5386+ User[nuser].action = DoTell;
5387+ memcpy (User[nuser].mesg_for_action, p,
5388+ sizeof (User[nuser].mesg_for_action));
5389+ return;
5390+}
5391+
5392+/* do broadcast command */
5393+static void
5394+doBroadcast (int nuser, unsigned char *p)
5395+{
5396+ User[nuser].action = DoBroadcast;
5397+ memcpy (User[nuser].mesg_for_action, p,
5398+ sizeof (User[nuser].mesg_for_action));
5399+ return;
5400+}
5401+
5402+/* do write npc shop command */
5403+static void
5404+doWriteNpcShop (int nuser, int nlen, const char *p)
5405+{
5406+ User[nuser].action = DoWriteMesg;
5407+ User[nuser].wk_for_action = nlen;
5408+ memcpy (User[nuser].mesg_for_action, p, nlen);
5409+ return;
5410+}
5411+
5412+/* do change user shop name */
5413+static void
5414+doChangeShopName (int nuser, const char *p)
5415+{
5416+ User[nuser].action = DoChangeShopName;
5417+ strncpy (User[nuser].mesg_for_action, p, 16);
5418+ User[nuser].mesg_for_action[16] = '\0';
5419+ return;
5420+}
5421+
5422+/* do destroy user shop */
5423+static void
5424+doDestroyShop (int nuser)
5425+{
5426+ User[nuser].action = DoDestroyShop;
5427+ return;
5428+}
5429+
5430+#ifdef USE_MAIL
5431+/* send mail header */
5432+static void
5433+doSendMyMail (int nuser, unsigned char *p)
5434+{
5435+ int ntarget = SearchUser ((char *) p);
5436+ if (User[nuser].t_mail != NULL)
5437+ {
5438+ /* ?? need to discard old transaction */
5439+ FreeMail (User[nuser].t_mail);
5440+ User[nuser].t_mail = NULL;
5441+ }
5442+ if (ntarget != -1)
5443+ {
5444+ printf ("user:%d try to send mail to user:%d...\n", nuser, ntarget);
5445+ User[nuser].t_mail = NewMail ();
5446+ User[nuser].t_target = ntarget;
5447+ if (User[nuser].t_mail != NULL)
5448+ {
5449+ int n = *(p + 16);
5450+ User[nuser].t_mail->fromuser = nuser;
5451+ memcpy (User[nuser].t_mail->subject, p + 16, n + 1);
5452+ }
5453+ }
5454+ else
5455+ {
5456+ SendSystemMessagePacket (nuser, "(Mail error:no such user!)");
5457+ }
5458+ return;
5459+}
5460+
5461+/* send mail body */
5462+static void
5463+doSendMyMailBody (int nuser, unsigned char *p)
5464+{
5465+ if (User[nuser].t_mail != NULL)
5466+ {
5467+ AddMessageMail (User[nuser].t_mail, (char *) p);
5468+ }
5469+ return;
5470+}
5471+
5472+/* end of send mail */
5473+static void
5474+doSendMyMailEnd (int nuser)
5475+{
5476+ if (User[nuser].t_mail != NULL)
5477+ {
5478+ if (User[nuser].t_target != -1)
5479+ {
5480+ /* try to send */
5481+ if (AddMailUser (User[nuser].t_target, User[nuser].t_mail))
5482+ {
5483+ /* ?? occur error. perhaps mailbox is full. */
5484+ puts ("Mail delivery fail");
5485+ SendSystemMessagePacket (nuser,
5486+ "(Mail error:target user's mailbox is"
5487+ " full)");
5488+ }
5489+ else
5490+ {
5491+ puts ("Mail delivery success.");
5492+ SendSystemMessagePacket (nuser, "[Ok. deliver mail.]");
5493+ SendSystemMessagePacket (User[nuser].t_target,
5494+ "[You have new mail!]");
5495+ User[nuser].t_mail = NULL;
5496+ User[nuser].t_target = -1;
5497+ }
5498+ }
5499+#ifdef USE_BBS
5500+ else
5501+ {
5502+ /* for BBS */
5503+ int n;
5504+ for (n = 0; n < BBS_BOX_LIMIT; n++)
5505+ {
5506+ if (BBSdata[n] == NULL)
5507+ {
5508+ break;
5509+ }
5510+ }
5511+ if (n == BBS_BOX_LIMIT)
5512+ {
5513+ /* BBS box is full. delete old article. */
5514+ puts ("BBS article box is full. delete old article.");
5515+ FreeMail (BBSdata[0]);
5516+ BBSdata[0] = NULL;
5517+ ReorderBBSbox ();
5518+ n = BBS_BOX_LIMIT - 1;
5519+ }
5520+ puts ("post article success.");
5521+ SendSystemMessagePacket (nuser, "[Ok. post article.]");
5522+ BBSdata[n] = User[nuser].t_mail;
5523+ User[nuser].t_mail = NULL;
5524+ }
5525+#endif /* USE_BBS */
5526+ }
5527+ else
5528+ {
5529+ SendSystemMessagePacket (nuser, "(Mail error:can't send)");
5530+ }
5531+ return;
5532+}
5533+
5534+/* list my mail box command */
5535+static void
5536+doListMyMail (int nuser)
5537+{
5538+ User[nuser].action = ListMyMail;
5539+ return;
5540+}
5541+
5542+/* read my mail command */
5543+static void
5544+doReadMyMail (int nuser, int n)
5545+{
5546+ if (n > 0 && n <= MAIL_BOX_LIMIT)
5547+ {
5548+ User[nuser].action = ReadMyMail;
5549+ User[nuser].wk_for_action = n - 1;
5550+ }
5551+ return;
5552+}
5553+
5554+/* delete my mail command */
5555+static void
5556+doDeleteMyMail (int nuser, int n)
5557+{
5558+ if (n > 0 && n <= MAIL_BOX_LIMIT)
5559+ {
5560+ User[nuser].action = DeleteMyMail;
5561+ User[nuser].wk_for_action = n - 1;
5562+ }
5563+ return;
5564+}
5565+
5566+#ifdef USE_BBS
5567+/* post BBS article header */
5568+static void
5569+doPostBBS (int nuser, unsigned char *p)
5570+{
5571+ if (User[nuser].t_mail != NULL)
5572+ {
5573+ /* ?? need to discard old transaction */
5574+ FreeMail (User[nuser].t_mail);
5575+ User[nuser].t_mail = NULL;
5576+ }
5577+ printf ("user:%d try to post BBS...\n", nuser);
5578+ User[nuser].t_mail = NewMail ();
5579+ User[nuser].t_target = -1;
5580+ if (User[nuser].t_mail != NULL)
5581+ {
5582+ int n = *p;
5583+ User[nuser].t_mail->fromuser = nuser;
5584+ memcpy (User[nuser].t_mail->subject, p, n + 1);
5585+ }
5586+ return;
5587+}
5588+
5589+/* list bbs command */
5590+static void
5591+doListBBS (int nuser)
5592+{
5593+ User[nuser].action = ListBBS;
5594+ return;
5595+}
5596+
5597+/* read bbs command */
5598+static void
5599+doReadBBS (int nuser, int n)
5600+{
5601+ if (n > 0 && n <= BBS_BOX_LIMIT)
5602+ {
5603+ User[nuser].action = ReadBBS;
5604+ User[nuser].wk_for_action = n - 1;
5605+ }
5606+ return;
5607+}
5608+
5609+#endif /* USE_BBS */
5610+#endif /* USE_MAIL */
5611+
5612+/* trasnfer score to other user */
5613+static void
5614+doTransferScore (int nuser, unsigned char *p)
5615+{
5616+ int ndist = SearchUser ((char *) p);
5617+ if (ndist != -1)
5618+ {
5619+ char work[MESG_BUFFER];
5620+ unsigned n = ntohl (*(unsigned long *) (p + 16));
5621+ unsigned ntax = n / 100;
5622+ if (User[nuser].score < n + ntax)
5623+ {
5624+ /* no score */
5625+ SendSystemMessagePacket (nuser, "[no have enough score]");
5626+ return;
5627+ }
5628+ dec_score (nuser, n + ntax);
5629+ add_score (ndist, n);
5630+ sprintf (work, "[You transfer %uscore to %-.16s. Tax:%upoint]",
5631+ n, CUTTAIL (User[ndist].name), ntax);
5632+ SendSystemMessagePacket (nuser, work);
5633+ sprintf (work, "[You receive %uscore from %-.16s]",
5634+ n, CUTTAIL (User[nuser].name));
5635+ SendSystemMessagePacket (ndist, work);
5636+ }
5637+ else
5638+ {
5639+ SendSystemMessagePacket (nuser, "[no such user]");
5640+ }
5641+ return;
5642+}
5643+
5644+/* do change animal name */
5645+static void
5646+doChangeUserAnimalName (int nuser, unsigned char *p)
5647+{
5648+ User[nuser].action = DoChangeAnimalName;
5649+ strncpy (User[nuser].mesg_for_action, (char *) p, 16);
5650+ User[nuser].mesg_for_action[16] = '\0';
5651+ return;
5652+}
5653+
5654+/* logoff command */
5655+static void
5656+doLogoff (int nuser)
5657+{
5658+ DisconnectUser (nuser);
5659+ return;
5660+}
5661+
5662+/* parse user command */
5663+static void
5664+parseCommand (int nuser, unsigned char *packet)
5665+{
5666+ switch (packet[0] & 0x3f)
5667+ {
5668+ case HCLIT_MOVE:
5669+ if (User[nuser].status != Arrested)
5670+ {
5671+ doMove (nuser, packet[2]);
5672+ }
5673+ break;
5674+ case HCLIT_CHDIR:
5675+ doChangeDirection (nuser, packet[2]);
5676+ break;
5677+ case HCLIT_FIRE:
5678+ if (User[nuser].status == Healthy)
5679+ {
5680+ doFire (nuser, packet[2]);
5681+ }
5682+ break;
5683+ case HCLIT_ITEM:
5684+ if (User[nuser].status == Healthy)
5685+ {
5686+ doUseItem (nuser, packet[2]);
5687+ }
5688+ break;
5689+ case HCLIT_PICK:
5690+ if (User[nuser].status == Healthy)
5691+ {
5692+ doPickUp (nuser);
5693+ }
5694+ break;
5695+ case HCLIT_PAY:
5696+ if (User[nuser].c_type == Hunter && User[nuser].status == Arrested)
5697+ {
5698+ doPay (nuser);
5699+ }
5700+ break;
5701+ case HCLIT_BUY:
5702+ if (User[nuser].status != Arrested)
5703+ {
5704+ doBuy (nuser, packet[2], packet[3]);
5705+ }
5706+ break;
5707+ case HCLIT_MESG:
5708+ doSay (nuser, packet + 2);
5709+ break;
5710+ case HCLIT_MESG2U:
5711+ doTell (nuser, packet + 2);
5712+ break;
5713+ case HCLIT_MESG2ALL:
5714+ doBroadcast (nuser, packet + 2);
5715+ break;
5716+ case HCLIT_WHO:
5717+ doWho (nuser);
5718+ break;
5719+ case HCLIT_REQWEAPON:
5720+ doListWeapon (nuser);
5721+ break;
5722+ case HCLIT_REQITEM:
5723+ doListItem (nuser);
5724+ break;
5725+ case HCLIT_WRITEMESG:
5726+ if (User[nuser].status != Arrested)
5727+ {
5728+ doWriteNpcShop (nuser, packet[2], (char *) (packet + 3));
5729+ }
5730+ break;
5731+ case HCLIT_DROPOBJ:
5732+ if (User[nuser].status == Healthy)
5733+ {
5734+ doDropObj (nuser, packet[2], packet[3], packet + 4);
5735+ }
5736+ break;
5737+ case HCLIT_CHANGEANIMAL:
5738+ doChangeUserAnimalName (nuser, packet + 2);
5739+ break;
5740+ case HCLIT_STOREANIMAL:
5741+ if (User[nuser].status != Arrested)
5742+ {
5743+ doStoreAnimal (nuser, ntohl (*(unsigned long *) (packet + 2)));
5744+ }
5745+ break;
5746+ case HCLIT_STOREOBJ:
5747+ if (User[nuser].status != Arrested)
5748+ {
5749+ doStoreObj (nuser, packet[2], packet[3],
5750+ ntohl (*(unsigned long *) (packet + 4)));
5751+ }
5752+ break;
5753+ case HCLIT_CHANGEMYSHOP:
5754+ if (User[nuser].status != Arrested)
5755+ {
5756+ doChangeShopName (nuser, (char *) (packet + 2));
5757+ }
5758+ break;
5759+ case HCLIT_DISCARDMYSHOPOBJ:
5760+ if (User[nuser].status != Arrested)
5761+ {
5762+ doDiscardMyshopObj (nuser, packet[2], packet[3]);
5763+ }
5764+ break;
5765+ case HCLIT_DESTROYMYSHOP:
5766+ if (User[nuser].status != Arrested)
5767+ {
5768+ doDestroyShop (nuser);
5769+ }
5770+ break;
5771+ case HCLIT_LISTMYSHOP:
5772+ if (User[nuser].status != Arrested)
5773+ {
5774+ doListMyshop (nuser);
5775+ }
5776+ break;
5777+ case HCLIT_REQANIMAL:
5778+ if (User[nuser].status != Arrested && User[nuser].c_type == Hunter)
5779+ {
5780+ doListMyAnimal (nuser);
5781+ }
5782+ break;
5783+ case HCLIT_LISTLIVEANIMAL:
5784+ if (User[nuser].status != Arrested)
5785+ {
5786+ doListLiveAnimal (nuser);
5787+ }
5788+ break;
5789+#ifdef USE_MAIL
5790+ case HCLIT_SENDMAIL:
5791+ doSendMyMail (nuser, packet + 2);
5792+ break;
5793+ case HCLIT_SENDMAILBODY:
5794+ doSendMyMailBody (nuser, packet + 2);
5795+ break;
5796+ case HCLIT_SENDEND:
5797+ doSendMyMailEnd (nuser);
5798+ break;
5799+ case HCLIT_LISTMAIL:
5800+ doListMyMail (nuser);
5801+ break;
5802+ case HCLIT_READMAIL:
5803+ doReadMyMail (nuser, packet[2]);
5804+ break;
5805+ case HCLIT_DELETEMAIL:
5806+ doDeleteMyMail (nuser, packet[2]);
5807+ break;
5808+#ifdef USE_BBS
5809+ case HCLIT_BBS_POST:
5810+ doPostBBS (nuser, packet + 2);
5811+ break;
5812+ case HCLIT_BBS_LIST:
5813+ doListBBS (nuser);
5814+ break;
5815+ case HCLIT_BBS_READ:
5816+ doReadBBS (nuser, packet[2]);
5817+ break;
5818+#endif /* USE_BBS */
5819+#endif /* USE_MAIL */
5820+ case HCLIT_TRANSFERSCORE:
5821+ doTransferScore (nuser, packet + 2);
5822+ break;
5823+ case HCLIT_LOGOFF:
5824+ doLogoff (nuser);
5825+ break;
5826+ }
5827+ return;
5828+}
5829+
5830+/* receive user command */
5831+static int
5832+receiveUserCommand (int nuser)
5833+{
5834+ unsigned char packet[PACKET_MAX];
5835+ int ret = -1;
5836+ SOCKET handle = User[nuser].session.handle;
5837+ if (receive_packet_c (handle, packet, PACKET_DATA_MAX) == 0)
5838+ {
5839+ parseCommand (nuser, packet);
5840+ ret = 0;
5841+ }
5842+ User[nuser].idletimer = 0;
5843+ return ret;
5844+}
5845+
5846+/* handling user packet */
5847+static void
5848+HandleUser (fd_set * rfds)
5849+{
5850+ int nuser;
5851+ for (nuser = 0; nuser < UserLimit; nuser++)
5852+ {
5853+ if (User[nuser].session.handle != INVALID_SOCKET)
5854+ {
5855+ SOCKET handle = User[nuser].session.handle;
5856+ if (FD_ISSET (handle, rfds) && receiveUserCommand (nuser) != 0)
5857+ {
5858+ DisconnectUser (nuser);
5859+ }
5860+ }
5861+ }
5862+ return;
5863+}
5864+
5865+/********************************************************/
5866+/* check and send hige-shop message */
5867+static void
5868+checkHigeMessage (int nuser)
5869+{
5870+ int f = 0;
5871+ int i;
5872+ for (i = 0; i < UserLimit; i++)
5873+ {
5874+ if (i == nuser)
5875+ {
5876+ continue;
5877+ }
5878+ if (User[i].name[0] != '\0' && User[i].higemesg[0] != '\0')
5879+ {
5880+ /* find message */
5881+ char work[PACKET_DATA_MAX];
5882+ int n = 0;
5883+ memcpy (work, User[i].name, USERNAME_LEN);
5884+ n += USERNAME_LEN;
5885+ work[n++] = ':';
5886+ strncpy (work + n, User[i].higemesg, PACKET_DATA_MAX - n);
5887+ SendSystemMessagePacket (nuser, work);
5888+ f = 1;
5889+ }
5890+ if (User[i].c_type == Hunter)
5891+ {
5892+ char work[PACKET_DATA_MAX];
5893+ switch (User[i].crime_level)
5894+ {
5895+ case 1:
5896+ sprintf (work, "<WANTED '%-.16s'>", CUTTAIL (User[i].name));
5897+ SendSystemMessagePacket (nuser, work);
5898+ break;
5899+ case 2:
5900+ sprintf (work, "<Dead or Alive '%-.16s'",
5901+ CUTTAIL (User[i].name));
5902+ SendSystemMessagePacket (nuser, work);
5903+ break;
5904+ }
5905+ }
5906+ }
5907+ if (!f)
5908+ {
5909+ /* no message */
5910+ SendSystemMessagePacket (nuser,
5911+ "Shop HIGE:Do you wanna use my design?");
5912+ }
5913+ return;
5914+}
5915+
5916+
5917+/* movement users */
5918+static void
5919+MovementUserPhase (void)
5920+{
5921+ int i;
5922+ for (i = 0; i < UserLimit; i++)
5923+ {
5924+ if (User[i].session.handle != INVALID_SOCKET)
5925+ {
5926+ if (User[i].speed_count == 0)
5927+ {
5928+ if (User[i].hold_count && User[i].move != NoMove)
5929+ {
5930+ SendSystemMessagePacket (i, "[You can't move now!]");
5931+ User[i].move = NoMove;
5932+ }
5933+ User[i].move_bkup = User[i].move;
5934+ if (User[i].move_bkup != NoMove)
5935+ {
5936+ unsigned char c;
5937+ int x = User[i].pos.x;
5938+ int y = User[i].pos.y;
5939+ switch (User[i].move_bkup)
5940+ {
5941+ case MoveForward:
5942+ x += FWVectorX[User[i].wk_direction];
5943+ y += FWVectorY[User[i].wk_direction];
5944+ break;
5945+ case MoveBackward:
5946+ x -= FWVectorX[User[i].wk_direction];
5947+ y -= FWVectorY[User[i].wk_direction];
5948+ break;
5949+ case MoveLeft:
5950+ x -= RGVectorX[User[i].wk_direction];
5951+ y -= RGVectorY[User[i].wk_direction];
5952+ break;
5953+ case MoveRight:
5954+ x += RGVectorX[User[i].wk_direction];
5955+ y += RGVectorY[User[i].wk_direction];
5956+ break;
5957+ default:
5958+ break;
5959+ }
5960+ adjust_pos (&x, &y);
5961+ c = MAP (x, y)->id & MAP_MASK;
5962+ if (MAP (x, y)->player || (MAP (x, y)->id & MAP_NOT_MOVE) ||
5963+ c == MAP_ROCK || c == MAP_INVALID)
5964+ {
5965+ /* impossible to move */
5966+ User[i].move_bkup = NoMove;
5967+ User[i].move = NoMove;
5968+ SendSystemMessagePacket (i,
5969+ "[Can't move its direction!]");
5970+ }
5971+ else
5972+ {
5973+ User[i].wk_pos.x = x;
5974+ User[i].wk_pos.y = y;
5975+ MAP (x, y)->player = i + 1;
5976+ User[i].status = Healthy;
5977+ }
5978+ }
5979+ }
5980+ }
5981+ }
5982+ for (i = 0; i < UserLimit; i++)
5983+ {
5984+ if (User[i].session.handle != INVALID_SOCKET)
5985+ {
5986+ if (User[i].speed_count == 0)
5987+ {
5988+ if (User[i].move_bkup != NoMove)
5989+ {
5990+ int x;
5991+ int y;
5992+ x = User[i].pos.x;
5993+ y = User[i].pos.y;
5994+ MAP (x, y)->player = 0;
5995+ User[i].pos = User[i].wk_pos;
5996+ User[i].direction = User[i].wk_direction;
5997+ User[i].move = NoMove;
5998+ x = User[i].pos.x;
5999+ y = User[i].pos.y;
6000+ if (MAP (x, y)->id & MAP_THERE_SHOP)
6001+ {
6002+ User[i].status = Shopping;
6003+ if (MAP (x, y)->owner == 0)
6004+ {
6005+ /* in hige shop. check message. */
6006+ checkHigeMessage (i);
6007+ }
6008+ }
6009+ }
6010+ else if (User[i].direction != User[i].wk_direction)
6011+ {
6012+ User[i].direction = User[i].wk_direction;
6013+ }
6014+ User[i].speed_count = User[i].speed;
6015+ }
6016+ else
6017+ {
6018+ User[i].speed_count--;
6019+ }
6020+ }
6021+ }
6022+ return;
6023+}
6024+
6025+/********************************************************/
6026+/* build up user shop */
6027+static int
6028+buildupMyShop (int nuser)
6029+{
6030+ int nshop;
6031+ for (nshop = 0; nshop < USERSHOP_LIMIT; nshop++)
6032+ {
6033+ if (User[nuser].myshop[nshop].build == 0)
6034+ {
6035+ /* ok. find free slot */
6036+ break;
6037+ }
6038+ }
6039+ if (nshop == USERSHOP_LIMIT)
6040+ {
6041+ SendSystemMessagePacket (nuser, "[You can't build anymore]");
6042+ return -1;
6043+ }
6044+ else
6045+ {
6046+ int x = User[nuser].pos.x;
6047+ int y = User[nuser].pos.y;
6048+ if (!(MAP (x, y)->id & MAP_HIGH_MASK) &&
6049+ (MAP (x, y)->id & MAP_MASK) == MAP_ROAD)
6050+ {
6051+ /* ok. */
6052+ int i;
6053+ User[nuser].myshop[nshop].build = 1;
6054+ User[nuser].myshop[nshop].pos = User[nuser].pos;
6055+ MAP (x, y)->owner = nuser + 1;
6056+ MAP (x, y)->id |= MAP_THERE_SHOP;
6057+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
6058+ {
6059+ User[nuser].myshop[nshop].list[0][i] = 0;
6060+ User[nuser].myshop[nshop].list[1][i] = 0;
6061+ User[nuser].myshop[nshop].leftuse[0][i] = 0;
6062+ User[nuser].myshop[nshop].leftuse[1][i] = 0;
6063+ User[nuser].myshop[nshop].count[0][i] = 0;
6064+ User[nuser].myshop[nshop].count[1][i] = 0;
6065+ User[nuser].myshop[nshop].cost[0][i] = 0;
6066+ User[nuser].myshop[nshop].cost[1][i] = 0;
6067+ }
6068+ return 0;
6069+ }
6070+ else
6071+ {
6072+ return -1;
6073+ }
6074+ }
6075+}
6076+
6077+/* store last pickup-animal */
6078+static void
6079+storeLastPickup (int nuser, unsigned long ncost)
6080+{
6081+ int x = User[nuser].pos.x;
6082+ int y = User[nuser].pos.y;
6083+ if (MAP (x, y)->owner == nuser + 1)
6084+ {
6085+ int nshop = searchUserShopFromPos (nuser, x, y);
6086+ ANIMALDATA *p = get_animal_slot (nuser);
6087+ if (nshop == -1 || User[nuser].myshop[nshop].build == 0)
6088+ {
6089+ SendSystemMessagePacket (nuser,
6090+ "(FATAL:user shop linkage is broken)");
6091+ return;
6092+ }
6093+ if (p != NULL)
6094+ {
6095+ int nitem = p->forsell_item;
6096+ int i;
6097+ /* store to shop */
6098+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
6099+ {
6100+ if (User[nuser].myshop[nshop].list[1][i] == nitem &&
6101+ User[nuser].myshop[nshop].cost[1][i] == ncost)
6102+ {
6103+ break;
6104+ }
6105+ }
6106+ if (i == SELLINSHOP_LIMIT)
6107+ {
6108+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
6109+ {
6110+ if (User[nuser].myshop[nshop].list[1][i] == 0 ||
6111+ User[nuser].myshop[nshop].count[1][i] == 0)
6112+ {
6113+ User[nuser].myshop[nshop].list[1][i] = nitem;
6114+ User[nuser].myshop[nshop].count[1][i] = 0;
6115+ User[nuser].myshop[nshop].cost[1][i] = ncost;
6116+ User[nuser].myshop[nshop].leftuse[1][i] =
6117+ Item[nitem].count;
6118+ break;
6119+ }
6120+ }
6121+ }
6122+ if (i < SELLINSHOP_LIMIT)
6123+ {
6124+ User[nuser].myshop[nshop].count[1][i]++;
6125+ SendSystemMessagePacket (nuser, "[1 animal stocked]");
6126+ }
6127+ else
6128+ {
6129+ SendSystemMessagePacket (nuser, "[NO STOCK SPACE]");
6130+ put_animal_slot (nuser, p);
6131+ }
6132+ }
6133+ else
6134+ {
6135+ SendSystemMessagePacket (nuser, "[You have no animal]");
6136+ }
6137+ }
6138+ else
6139+ {
6140+ SendSystemMessagePacket (nuser, "[You must go to your shop]");
6141+ }
6142+ return;
6143+}
6144+
6145+/* store item or weapon */
6146+static void
6147+storeItemOrWeapon (int nuser, int isitem, int nslot, unsigned long cost)
6148+{
6149+ int x = User[nuser].pos.x;
6150+ int y = User[nuser].pos.y;
6151+ if (MAP (x, y)->owner == nuser + 1)
6152+ {
6153+ int nshop = searchUserShopFromPos (nuser, x, y);
6154+ char work[MESG_BUFFER];
6155+ int i;
6156+ int n;
6157+ unsigned short nleft;
6158+ if (nshop == -1 || User[nuser].myshop[nshop].build == 0)
6159+ {
6160+ SendSystemMessagePacket (nuser,
6161+ "(FATAL:user shop linkage is broken)");
6162+ return;
6163+ }
6164+ if (isitem)
6165+ {
6166+ if (nslot < 0 || nslot > ITEM_MAX)
6167+ {
6168+ /* illegal slot */
6169+ SendSystemMessagePacket (nuser, "[Illegal slot number]");
6170+ return;
6171+ }
6172+ n = User[nuser].item[nslot];
6173+ nleft = User[nuser].itemcount[nslot];
6174+ }
6175+ else
6176+ {
6177+ if (nslot < 0 || nslot > WEAPON_MAX)
6178+ {
6179+ /* illegal slot */
6180+ SendSystemMessagePacket (nuser, "[Illegal slot number]");
6181+ return;
6182+ }
6183+ n = User[nuser].weapon[nslot];
6184+ nleft = User[nuser].bullette[nslot];
6185+ }
6186+ if (n == 0 || nleft == 0)
6187+ {
6188+ /* NG */
6189+ sprintf (work, "[%s slot%d is empty]",
6190+ isitem ? "Item" : "Weapon", nslot + 1);
6191+ SendSystemMessagePacket (nuser, work);
6192+ return;
6193+ }
6194+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
6195+ {
6196+ if (User[nuser].myshop[nshop].list[isitem][i] == n &&
6197+ User[nuser].myshop[nshop].leftuse[isitem][i] == nleft &&
6198+ User[nuser].myshop[nshop].cost[isitem][i] == cost)
6199+ {
6200+ break;
6201+ }
6202+ }
6203+ if (i == SELLINSHOP_LIMIT)
6204+ {
6205+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
6206+ {
6207+ if (User[nuser].myshop[nshop].list[isitem][i] == 0 ||
6208+ User[nuser].myshop[nshop].count[isitem][i] == 0)
6209+ {
6210+ User[nuser].myshop[nshop].list[isitem][i] = n;
6211+ User[nuser].myshop[nshop].count[isitem][i] = 0;
6212+ User[nuser].myshop[nshop].leftuse[isitem][i] = nleft;
6213+ User[nuser].myshop[nshop].cost[isitem][i] = cost;
6214+ break;
6215+ }
6216+ }
6217+ }
6218+ if (i < SELLINSHOP_LIMIT)
6219+ {
6220+ if (isitem)
6221+ {
6222+ User[nuser].item[nslot] = 0;
6223+ User[nuser].itemcount[nslot] = 0;
6224+ }
6225+ else
6226+ {
6227+ User[nuser].weapon[nslot] = 0;
6228+ User[nuser].bullette[nslot] = 0;
6229+ }
6230+ User[nuser].myshop[nshop].count[isitem][i]++;
6231+ sprintf (work, "[%-.32s stocked]",
6232+ isitem ? Item[n].name : Weapon[n].name);
6233+ SendSystemMessagePacket (nuser, work);
6234+ }
6235+ else
6236+ {
6237+ SendSystemMessagePacket (nuser, "[NO STOCK SPACE]");
6238+ }
6239+ }
6240+ else
6241+ {
6242+ SendSystemMessagePacket (nuser, "[You must go to your shop]");
6243+ }
6244+ return;
6245+}
6246+
6247+/* discard item or weapon in my shop */
6248+static void
6249+discardItemOrWeapon (int nuser, int isitem, int n)
6250+{
6251+ int x = User[nuser].pos.x;
6252+ int y = User[nuser].pos.y;
6253+ if (MAP (x, y)->owner == nuser + 1)
6254+ {
6255+ int nshop = searchUserShopFromPos (nuser, x, y);
6256+ if (nshop == -1 || User[nuser].myshop[nshop].build == 0)
6257+ {
6258+ SendSystemMessagePacket (nuser,
6259+ "(FATAL:user shop linkage is broken)");
6260+ return;
6261+ }
6262+ if (n >= 0 && n < SELLINSHOP_LIMIT)
6263+ {
6264+ if (User[nuser].myshop[nshop].list[isitem][n] != 0)
6265+ {
6266+ /* ok */
6267+ User[nuser].myshop[nshop].list[isitem][n] = 0;
6268+ User[nuser].myshop[nshop].count[isitem][n] = 0;
6269+ SendSystemMessagePacket (nuser, isitem ?
6270+ "[Discard Item]" : "[Discard Weapon]");
6271+ }
6272+ else
6273+ {
6274+ SendSystemMessagePacket (nuser, "[It is EMPTY]");
6275+ }
6276+ }
6277+ }
6278+ else
6279+ {
6280+ SendSystemMessagePacket (nuser, "[You must go to your shop]");
6281+ }
6282+ return;
6283+}
6284+
6285+/* destroy my shop */
6286+static void
6287+processDestroyMyshop (int nuser)
6288+{
6289+ int x = User[nuser].pos.x;
6290+ int y = User[nuser].pos.y;
6291+ int nshop = searchUserShopFromPos (nuser, x, y);
6292+ if (nshop != -1 && User[nuser].myshop[nshop].build)
6293+ {
6294+ int i;
6295+ MAP (x, y)->id &= ~MAP_THERE_SHOP;
6296+ MAP (x, y)->owner = 0;
6297+ User[nuser].myshop[nshop].build = 0;
6298+ for (i = 0; i < SELLINSHOP_LIMIT; i++)
6299+ {
6300+ if (User[nuser].myshop[nshop].list[0][i] &&
6301+ User[nuser].myshop[nshop].count[0][i])
6302+ {
6303+ int j;
6304+ unsigned long ncost =
6305+ Weapon[User[nuser].myshop[nshop].list[0][i]].cost / 2;
6306+ for (j = 0; j < User[nuser].myshop[nshop].count[0][i]; j++)
6307+ {
6308+ add_score (nuser, ncost);
6309+ }
6310+ }
6311+ if (User[nuser].myshop[nshop].list[0][i] &&
6312+ User[nuser].myshop[nshop].count[0][i])
6313+ {
6314+ int j;
6315+ unsigned long ncost =
6316+ Item[User[nuser].myshop[nshop].list[0][i]].cost / 2;
6317+ for (j = 0; j < User[nuser].myshop[nshop].count[0][i]; j++)
6318+ {
6319+ add_score (nuser, ncost);
6320+ }
6321+ }
6322+ }
6323+ SendSystemMessagePacket (nuser, "[You destroy your shop]");
6324+ }
6325+ else
6326+ {
6327+ SendSystemMessagePacket (nuser, "[You must go to your shop]");
6328+ }
6329+ return;
6330+}
6331+
6332+/* change myshop name */
6333+static void
6334+processChangeMyshop (int nuser, const char *p)
6335+{
6336+ int x = User[nuser].pos.x;
6337+ int y = User[nuser].pos.y;
6338+ int nshop = searchUserShopFromPos (nuser, x, y);
6339+ if (nshop != -1 && User[nuser].myshop[nshop].build)
6340+ {
6341+ int i;
6342+ for (i = 0; p[i] != '\0' && i < USERNAME_LEN; i++)
6343+ {
6344+ User[nuser].myshop[nshop].name[i] = p[i];
6345+ }
6346+ for (; i < USERNAME_LEN; i++)
6347+ {
6348+ User[nuser].myshop[nshop].name[i] = ' ';
6349+ }
6350+ SendSystemMessagePacket (nuser, "[Your shop name is changed]");
6351+ }
6352+ else
6353+ {
6354+ SendSystemMessagePacket (nuser, "[You must go to your shop]");
6355+ }
6356+ return;
6357+}
6358+
6359+/* write message on hige shop */
6360+static void
6361+processWriteMesg (int nuser, int nlen, const char *p)
6362+{
6363+ int x = User[nuser].pos.x;
6364+ int y = User[nuser].pos.y;
6365+ if ((MAP (x, y)->id & MAP_THERE_SHOP) && MAP (x, y)->owner == 0)
6366+ {
6367+ if (nlen > sizeof (User[nuser].higemesg) - 1)
6368+ {
6369+ nlen = sizeof (User[nuser].higemesg) - 1;
6370+ }
6371+ if (nlen)
6372+ {
6373+ strncpy (User[nuser].higemesg, p, nlen);
6374+ }
6375+ User[nuser].higemesg[nlen] = '\0';
6376+ if (nlen == 0)
6377+ {
6378+ SendSystemMessagePacket (nuser, "[Your message is cleard]");
6379+ }
6380+ else
6381+ {
6382+ SendSystemMessagePacket (nuser,
6383+ "[Your write message on Shop HIGE]");
6384+ }
6385+ }
6386+ else
6387+ {
6388+ SendSystemMessagePacket (nuser, "[You must go to Shop HIGE!]");
6389+ }
6390+ return;
6391+}
6392+
6393+/* process change user animal name */
6394+static void
6395+processChangeUserAnimalName (int nuser, const char *p)
6396+{
6397+ int x = User[nuser].pos.x;
6398+ int y = User[nuser].pos.y;
6399+ x += FWVectorX[User[nuser].direction];
6400+ y += FWVectorY[User[nuser].direction];
6401+ adjust_pos (&x, &y);
6402+ if (MAP (x, y)->id & MAP_THERE_ANIMAL)
6403+ {
6404+ int nanimal = MAP (x, y)->animal;
6405+ if (Animal[nanimal].owner_user == nuser)
6406+ {
6407+ /* your animal */
6408+ int i;
6409+ for (i = 0; i < USERNAME_LEN && *p != '\0'; i++, p++)
6410+ {
6411+ Animal[nanimal].name[i] = *p;
6412+ }
6413+ for (; i < USERNAME_LEN; i++)
6414+ {
6415+ Animal[nanimal].name[i] = ' ';
6416+ }
6417+ SendSystemMessagePacket (nuser, "[animal name is changed]");
6418+ }
6419+ else
6420+ {
6421+ SendSystemMessagePacket (nuser, "[This animal is not yours!]");
6422+ }
6423+ }
6424+ else
6425+ {
6426+ SendSystemMessagePacket (nuser, "[no animal on front!]");
6427+ }
6428+ return;
6429+}
6430+
6431+/* send message */
6432+static void
6433+processSendMessage (int nuser, unsigned char *p)
6434+{
6435+ char work[PACKET_DATA_MAX + 1];
6436+ int nlen = *p;
6437+ if (nlen > PACKET_DATA_MAX - USERNAME_LEN - 5)
6438+ {
6439+ nlen = PACKET_DATA_MAX - USERNAME_LEN - 5;
6440+ }
6441+ memcpy (work, User[nuser].name, USERNAME_LEN);
6442+ memcpy (work + USERNAME_LEN, " say,", 5);
6443+ if (nlen)
6444+ {
6445+ memcpy (work + USERNAME_LEN + 5, p + 1, nlen);
6446+ }
6447+ work[USERNAME_LEN + 5 + nlen] = '\0';
6448+ SendMessageNearUserSender (nuser, work);
6449+ return;
6450+}
6451+
6452+/* broadcast message */
6453+static void
6454+processBroadcastMessage (int nuser, unsigned char *p)
6455+{
6456+ char work[PACKET_DATA_MAX + 1];
6457+ int nlen = *p;
6458+ if (nlen > PACKET_DATA_MAX - USERNAME_LEN - 11)
6459+ {
6460+ nlen = PACKET_DATA_MAX - USERNAME_LEN - 11;
6461+ }
6462+ memcpy (work, User[nuser].name, USERNAME_LEN);
6463+ memcpy (work + USERNAME_LEN, " broadcast,", 11);
6464+ if (nlen)
6465+ {
6466+ memcpy (work + USERNAME_LEN + 11, p + 1, nlen);
6467+ }
6468+ work[USERNAME_LEN + 11 + nlen] = '\0';
6469+ SendMessageAllUser (work);
6470+ return;
6471+}
6472+
6473+/* send message to specific user */
6474+static void
6475+processSendMessage2User (int nuser, unsigned char *p)
6476+{
6477+ int destuser = SearchUser ((char *) p);
6478+ if (destuser != -1)
6479+ {
6480+ char work[PACKET_DATA_MAX];
6481+ int nlen = *(p + 16);
6482+ memcpy (work, p + 17, nlen);
6483+ work[nlen] = '\0';
6484+ SendMessagePacket (destuser, nuser, work);
6485+ if (nlen > PACKET_DATA_MAX - USERNAME_LEN - 10)
6486+ {
6487+ nlen = PACKET_DATA_MAX - USERNAME_LEN - 10;
6488+ }
6489+ sprintf (work, "You tell %-.16s,", CUTTAIL (User[destuser].name));
6490+ if (nlen)
6491+ {
6492+ memcpy (work + USERNAME_LEN + 10, p + 17, nlen);
6493+ }
6494+ work[USERNAME_LEN + 10 + nlen] = '\0';
6495+ SendSystemMessagePacket (nuser, work);
6496+ }
6497+ return;
6498+}
6499+
6500+/* process fire weapon */
6501+static void
6502+processFireWeapon (int nuser, int nweapon)
6503+{
6504+ if (User[nuser].reload[nweapon] == 0)
6505+ {
6506+ struct bullet_t *pbullet;
6507+ if (User[nuser].bullette[nweapon])
6508+ {
6509+ User[nuser].bullette[nweapon]--;
6510+ }
6511+ else
6512+ {
6513+ User[nuser].weapon[nweapon] = 0; /* bear hand */
6514+ }
6515+ pbullet = NewBullet (User[nuser].weapon[nweapon],
6516+ User[nuser].pos, User[nuser].direction);
6517+ pbullet->nuser = nuser; /* owner */
6518+ pbullet->t_type = TargetUser;
6519+ User[nuser].reload[nweapon] = Weapon[User[nuser].weapon[nweapon]].rate;
6520+ User[nuser].cloak_count = 0;
6521+ }
6522+ else
6523+ {
6524+ char work[PACKET_DATA_MAX];
6525+ sprintf (work, "[Weapon:%-32.32s NOT READY]",
6526+ Weapon[User[nuser].weapon[nweapon]].name);
6527+ SendSystemMessagePacket (nuser, work);
6528+ }
6529+ return;
6530+}
6531+
6532+/* char near animal */
6533+static void
6534+processCharmAnimal (int nuser, int neffect)
6535+{
6536+ int i;
6537+ for (i = 0; i < AnimalLimit; i++)
6538+ {
6539+ if (Animal[i].pdata != NULL && Animal[i].hp)
6540+ {
6541+ int n = get_rel_distance (User[nuser].pos.x, User[nuser].pos.y,
6542+ Animal[i].pos.x, Animal[i].pos.y);
6543+ if (n < neffect)
6544+ {
6545+ /* charm this */
6546+ Animal[i].charm = CharmPosition;
6547+ Animal[i].charmcount = CharmCount;
6548+ Animal[i].charm_pos = User[nuser].pos;
6549+ }
6550+ }
6551+ }
6552+ return;
6553+}
6554+
6555+/* list up near Animal */
6556+static void
6557+ListUpNearAnimal (int nuser, int neffect)
6558+{
6559+ int i;
6560+ char work[MESG_BUFFER];
6561+ for (i = 0; i < AnimalLimit; i++)
6562+ {
6563+ if (Animal[i].pdata != NULL && Animal[i].hp)
6564+ {
6565+ int dx1;
6566+ int dx2;
6567+ int dy1;
6568+ int dy2;
6569+ int n;
6570+ calculate_delta_x (User[nuser].pos.x, Animal[i].pos.x, &dx1, &dx2);
6571+ calculate_delta_y (User[nuser].pos.y, Animal[i].pos.y, &dy1, &dy2);
6572+ n = get_rel_distance_in (dx1, dx2, dy1, dy2);
6573+ if (n < neffect)
6574+ {
6575+ /* list up this */
6576+ int relpos = get_rel_position_in (dx1, dx2, dy1, dy2);
6577+ sprintf (work, "<%-16.16s %10s %5dBlock>",
6578+ Animal[i].name, RelDirection[relpos], n);
6579+ SendSystemMessagePacket (nuser, work);
6580+ }
6581+ }
6582+ }
6583+ return;
6584+}
6585+
6586+/* list up near human */
6587+static void
6588+ListUpNearHuman (int nuser, int neffect)
6589+{
6590+ int i;
6591+ enum npctype_t npct;
6592+ char work[MESG_BUFFER];
6593+ for (i = 0; i < UserLimit; i++)
6594+ {
6595+ if (nuser == i)
6596+ {
6597+ continue;
6598+ }
6599+ if (User[i].session.handle != INVALID_SOCKET && User[i].hp &&
6600+ User[i].cloak_count == 0 && User[i].c_type != User[nuser].c_type)
6601+ {
6602+ int dx1;
6603+ int dx2;
6604+ int dy1;
6605+ int dy2;
6606+ int n;
6607+ calculate_delta_x (User[nuser].pos.x, User[i].pos.x, &dx1, &dx2);
6608+ calculate_delta_y (User[nuser].pos.y, User[i].pos.y, &dy1, &dy2);
6609+ n = get_rel_distance_in (dx1, dx2, dy1, dy2);
6610+ if (n < neffect)
6611+ {
6612+ /* list up this */
6613+ int relpos = get_rel_position_in (dx1, dx2, dy1, dy2);
6614+ if (User[i].c_type == Hunter)
6615+ {
6616+ sprintf (work, "<Hunter:%-16.16s %10s %5dBlock crime:%lu>",
6617+ User[i].name, RelDirection[relpos], n,
6618+ User[i].maybearrest);
6619+ }
6620+ else
6621+ {
6622+ sprintf (work, "<Guard :%-16.16s %10s %5dBlock>",
6623+ User[i].name, RelDirection[relpos], n);
6624+ }
6625+ SendSystemMessagePacket (nuser, work);
6626+ }
6627+ }
6628+ }
6629+ if (User[nuser].c_type == Hunter)
6630+ {
6631+ npct = NpcObserver;
6632+ }
6633+ else
6634+ {
6635+ npct = NpcHunter;
6636+ }
6637+ for (i = 0; i < NpcLimit; i++)
6638+ {
6639+ if (Npc[i].name[0] != '\0' && Npc[i].hp && Npc[i].c_type == npct)
6640+ {
6641+ int dx1;
6642+ int dx2;
6643+ int dy1;
6644+ int dy2;
6645+ int n;
6646+ calculate_delta_x (User[nuser].pos.x, Npc[i].pos.x, &dx1, &dx2);
6647+ calculate_delta_y (User[nuser].pos.y, Npc[i].pos.y, &dy1, &dy2);
6648+ n = get_rel_distance_in (dx1, dx2, dy1, dy2);
6649+ if (n < neffect)
6650+ {
6651+ /* list up this */
6652+ int relpos = get_rel_position_in (dx1, dx2, dy1, dy2);
6653+ if (Npc[i].c_type == NpcHunter)
6654+ {
6655+ sprintf (work, "<Hunter:%-16.16s %10s %5dBlock crime:NA>",
6656+ Npc[i].name, RelDirection[relpos], n);
6657+ }
6658+ else
6659+ {
6660+ sprintf (work, "<Guard :%-16.16s %10s %5dBlock>",
6661+ Npc[i].name, RelDirection[relpos], n);
6662+ }
6663+ SendSystemMessagePacket (nuser, work);
6664+ }
6665+ }
6666+ }
6667+ return;
6668+}
6669+
6670+/* glow tree */
6671+static void
6672+glowTree (int nuser)
6673+{
6674+ int x = User[nuser].pos.x;
6675+ int y = User[nuser].pos.y;
6676+ INVALID_MAP (x, y);
6677+ MAP (x, y)->id |= MAP_TREE;
6678+ return;
6679+}
6680+
6681+/* dig hole */
6682+static int
6683+digHoleHere (int nuser)
6684+{
6685+ int x = User[nuser].pos.x;
6686+ int y = User[nuser].pos.y;
6687+ x += FWVectorX[User[nuser].direction];
6688+ y += FWVectorY[User[nuser].direction];
6689+ adjust_pos (&x, &y);
6690+ if ((MAP (x, y)->id & MAP_HIGH_MASK) ||
6691+ (MAP (x, y)->id & MAP_MASK) != MAP_ROAD)
6692+ {
6693+ return -1;
6694+ }
6695+ else
6696+ {
6697+ MAP (x, y)->id |= MAP_THERE_HOLE;
6698+ User[nuser].hold_count = DigCount; /* need time for digging */
6699+ SendEffectDiggingPacket (nuser);
6700+ return 0;
6701+ }
6702+}
6703+
6704+/* ride */
6705+static void
6706+rideVehicle (int nuser, int nslot, int nspeed, int npattern)
6707+{
6708+ if (User[nuser].c_type == Hunter)
6709+ {
6710+ if (User[nuser].animal_slot > nslot)
6711+ {
6712+ /* need shrink slot */
6713+ int i;
6714+ for (i = nslot; i < User[nuser].animal_slot; i++)
6715+ {
6716+ User[nuser].lastPickupAnimal[i] = NULL;
6717+ }
6718+ }
6719+ User[nuser].animal_slot = nslot;
6720+ }
6721+ User[nuser].speed = nspeed;
6722+ User[nuser].speed_count = 0;
6723+ User[nuser].ride_pattern = npattern;
6724+ return;
6725+}
6726+
6727+/* hire npc for user */
6728+static int
6729+HireNpcForUser (int nuser, int neffect)
6730+{
6731+ int i;
6732+ for (i = NpcLimitForSystem; i < NpcLimit; i++)
6733+ {
6734+ if (Npc[i].name[0] == '\0')
6735+ {
6736+ static const char *mesg[4] = {
6737+ "%-.16s say,OK Boss. I will guard you.",
6738+ "%-.16s say,Ready for deployment",
6739+ "%-.16s say,It's show time!",
6740+ "%-.16s say,Do you wanna use my design?"
6741+ };
6742+ static const int ck_x[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
6743+ static const int ck_y[8] = { -1, -1, 0, 1, 1, 1, 0, -1 };
6744+ int x;
6745+ int y;
6746+ int j;
6747+ x = User[nuser].pos.x;
6748+ y = User[nuser].pos.y;
6749+ for (j = 0; j < 8; j++)
6750+ {
6751+ int wkx = x + ck_x[j];
6752+ int wky = y + ck_y[j];
6753+ adjust_pos (&wkx, &wky);
6754+ if ((MAP (wkx, wky)->id & MAP_MASK) == MAP_ROCK ||
6755+ (MAP (wkx, wky)->id & MAP_NOT_MOVE) ||
6756+ MAP (wkx, wky)->player)
6757+ {
6758+ continue;
6759+ }
6760+ break;
6761+ }
6762+ if (j == 8)
6763+ {
6764+ return -1;
6765+ }
6766+ x += ck_x[j];
6767+ y += ck_y[j];
6768+ adjust_pos (&x, &y);
6769+ Npc[i].c_type = NpcHige;
6770+ Npc[i].number = getrand (1, HireableNpcType);
6771+ memcpy (Npc[i].name,
6772+ NpcHiges[getrand (0, NpcHigesN - 1)], USERNAME_LEN);
6773+ MAP (x, y)->id |= MAP_THERE_NPC;
6774+ MAP (x, y)->animal = i;
6775+ Npc[i].pos.x = x;
6776+ Npc[i].pos.y = y;
6777+ Npc[i].direction = getrand (0, 3);
6778+ Npc[i].speed = getrand (NpcSpeedMin, NpcSpeedMax) * NpcSpeedBase;
6779+ Npc[i].speed_count = 0;
6780+ Npc[i].search = getrand (NpcSearchMin, NpcSearchMax);
6781+ Npc[i].attack = getrand (NpcAttackMin, NpcAttackMax);
6782+ Npc[i].owner_user = nuser;
6783+ Npc[i].ntarget_user = -1;
6784+ Npc[i].hp = neffect;
6785+ if (User[nuser].c_type == Hunter)
6786+ {
6787+ Npc[i].weapon = get_npc_weapon (NpcHunter);
6788+ Npc[i].moral_limit = ANIMAL_MORAL_PANIC;
6789+ }
6790+ else
6791+ {
6792+ Npc[i].weapon = get_npc_weapon (NpcObserver);
6793+ Npc[i].moral_limit = ANIMAL_MORAL_NORMAL + 1;
6794+ }
6795+ Npc[i].bullette = Weapon[Npc[i].weapon].bullette;
6796+ Npc[i].nochangelock_count = 0;
6797+ Npc[i].hold_count = 0;
6798+ Npc[i].reload = 0;
6799+ NPCsay (i, mesg, 4);
6800+ return 0;
6801+ }
6802+ }
6803+ return -1;
6804+}
6805+
6806+/* process use item */
6807+static void
6808+processUseItem (int nuser, int nitem)
6809+{
6810+ if (User[nuser].itemcount[nitem])
6811+ {
6812+ char work[MESG_BUFFER];
6813+ ITEMINFO *pitem = Item + User[nuser].item[nitem];
6814+ User[nuser].itemcount[nitem]--;
6815+ switch (pitem->id)
6816+ {
6817+ case Noeffect:
6818+ /* no effect */
6819+ strcpy (work, "No effect");
6820+ break;
6821+ case Heal:
6822+ /* heal */
6823+ cause_heal (nuser, pitem->effect);
6824+ sprintf (work, "You get %uHP", pitem->effect);
6825+ break;
6826+ case Tree:
6827+ /* glow Tree */
6828+ glowTree (nuser);
6829+ strcpy (work, "[Tree is important resource.]");
6830+ break;
6831+ case Charm:
6832+ /* charm near animal */
6833+ strcpy (work, "You attempt to charm animal...");
6834+ processCharmAnimal (nuser, pitem->effect);
6835+ break;
6836+ case Score:
6837+ /* get score */
6838+ add_score (nuser, pitem->effect);
6839+ sprintf (work, "You get %uscore", pitem->effect);
6840+ break;
6841+ case Damage:
6842+ /* bad ... */
6843+ cause_damage (nuser, pitem->effect, -1, TargetNone);
6844+ sprintf (work, "You lost %uHP", pitem->effect);
6845+ break;
6846+ case AnimalRadar:
6847+ /* animal radar */
6848+ SendSystemMessagePacket (nuser, "<scan animal...>");
6849+ ListUpNearAnimal (nuser, pitem->effect);
6850+ strcpy (work, "<end of scan>");
6851+ break;
6852+ case HumanRadar:
6853+ /* human radar */
6854+ SendSystemMessagePacket (nuser, "<scan...>");
6855+ ListUpNearHuman (nuser, pitem->effect);
6856+ strcpy (work, "<end of scan>");
6857+ break;
6858+ case Invisible:
6859+ if (User[nuser].cloak_count)
6860+ {
6861+ User[nuser].itemcount[nitem]++;
6862+ strcpy (work, "[You are already invisible!]");
6863+ }
6864+ else
6865+ {
6866+ User[nuser].cloak_count = pitem->effect;
6867+ strcpy (work, "[You are now invisible]");
6868+ }
6869+ break;
6870+ case BuildShop:
6871+ if (buildupMyShop (nuser))
6872+ {
6873+ /* occur error */
6874+ User[nuser].itemcount[nitem]++;
6875+ strcpy (work, "[You can't build shop here!]");
6876+ }
6877+ else
6878+ {
6879+ strcpy (work, "[Build your shop!]");
6880+ }
6881+ break;
6882+ case DigHole:
6883+ if (digHoleHere (nuser))
6884+ {
6885+ strcpy (work, "[You try to dig...but you can't dig hole]");
6886+ }
6887+ else
6888+ {
6889+ strcpy (work, "[You dig hole... hehehe]");
6890+ }
6891+ break;
6892+ case Vehicle:
6893+ sprintf (work, "You ride on %-.32s", pitem->name);
6894+ rideVehicle (nuser, pitem->effect % 100, pitem->effect / 100,
6895+ pitem->pattern);
6896+ break;
6897+ case Food:
6898+ cause_eat (nuser, pitem->effect);
6899+ sprintf (work, "You eat %-.32s. ", pitem->name);
6900+ if (pitem->effect > 100)
6901+ {
6902+ strcat (work, "Delicious!");
6903+ }
6904+ else if (pitem->effect >= 50)
6905+ {
6906+ strcat (work, "uhmm. no feel so bad.");
6907+ }
6908+ else if (pitem->effect >= 10)
6909+ {
6910+ strcat (work, "better than nothing.");
6911+ }
6912+ else
6913+ {
6914+ strcat (work, "I think this is dogfood.");
6915+ }
6916+ break;
6917+ case HireNpc:
6918+ if (HireNpcForUser (nuser, pitem->effect))
6919+ {
6920+ User[nuser].itemcount[nitem]++;
6921+ strcpy (work, "[Can't hire NPC now]");
6922+ }
6923+ else
6924+ {
6925+ strcpy (work, "[You hire NPC]");
6926+ }
6927+ break;
6928+ default:
6929+ strcpy (work, "?? error item");
6930+ break;
6931+ }
6932+ SendSystemMessagePacket (nuser, work);
6933+ }
6934+ if (User[nuser].itemcount[nitem] == 0)
6935+ {
6936+ User[nuser].item[nitem] = 0;
6937+ }
6938+ return;
6939+}
6940+
6941+/* add item to slot */
6942+static int
6943+addItemSlot (int nuser, int nitem)
6944+{
6945+ int i;
6946+ char work[MESG_BUFFER];
6947+ for (i = 0; i < ITEM_MAX; i++)
6948+ {
6949+ if (User[nuser].item[i] == 0 || User[nuser].itemcount[i] == 0)
6950+ {
6951+ break;
6952+ }
6953+ }
6954+ if (i == ITEM_MAX)
6955+ {
6956+ /* full hand */
6957+ /* no space */
6958+ return -1;
6959+ }
6960+ User[nuser].item[i] = nitem;
6961+ User[nuser].itemcount[i] = Item[User[nuser].item[i]].count;
6962+ sprintf (work, "[Get item%1d:%-.32s]",
6963+ i + 1, Item[User[nuser].item[i]].name);
6964+ SendSystemMessagePacket (nuser, work);
6965+ return i;
6966+}
6967+
6968+/* add weapon to slot */
6969+static int
6970+addWeaponSlot (int nuser, int nweapon)
6971+{
6972+ int i;
6973+ char work[MESG_BUFFER];
6974+ for (i = 0; i < WEAPON_MAX; i++)
6975+ {
6976+ if (User[nuser].weapon[i] == 0 || User[nuser].bullette[i] == 0)
6977+ {
6978+ break;
6979+ }
6980+ }
6981+ if (i == WEAPON_MAX)
6982+ {
6983+ /* full hand */
6984+ /* no space */
6985+ return -1;
6986+ }
6987+ User[nuser].weapon[i] = nweapon;
6988+ User[nuser].bullette[i] = Weapon[User[nuser].weapon[i]].bullette;
6989+ User[nuser].reload[i] = 0;
6990+ sprintf (work, "[Get weapon%1d:%-.32s]",
6991+ i + 1, Weapon[User[nuser].weapon[i]].name);
6992+ SendSystemMessagePacket (nuser, work);
6993+ return i;
6994+}
6995+
6996+/* process pickup */
6997+static void
6998+processPickUp (int nuser)
6999+{
7000+ int x = User[nuser].pos.x;
7001+ int y = User[nuser].pos.y;
7002+ x += FWVectorX[User[nuser].direction];
7003+ y += FWVectorY[User[nuser].direction];
7004+ adjust_pos (&x, &y);
7005+ if (MAP (x, y)->id & MAP_THERE_ITEM)
7006+ {
7007+ /* pickup */
7008+ struct itembox_t *pitembox;
7009+ int nitem;
7010+ int isitem;
7011+ unsigned nleft;
7012+ int okpickup = 0;
7013+ SendSystemMessagePacket (nuser, "[You open treasure box...]");
7014+ pitembox = getUserItemBox (x, y);
7015+ if (pitembox == NULL)
7016+ {
7017+ /* it is made by system */
7018+ if (getrand (1, 100) == 1)
7019+ {
7020+ /* trap */
7021+ unsigned ndamage = getrand (100, 500);
7022+ SendSystemMessagePacket (nuser, "[Explode! You are damaged!]");
7023+ cause_damage (nuser, ndamage, -1, TargetNone);
7024+ okpickup = 1;
7025+ }
7026+ else if (getrand (1, 100) <= RateBoxInItem)
7027+ {
7028+ /* it's item */
7029+ isitem = 1;
7030+ nitem = getrand (1, ItemLimit - 1);
7031+ nleft = Item[nitem].count;
7032+ if (addItemSlot (nuser, nitem) != -1)
7033+ {
7034+ okpickup = 1;
7035+ }
7036+ }
7037+ else
7038+ {
7039+ /* it's weapon */
7040+ isitem = 0;
7041+ nitem = getrand (1, WeaponLimit - 1);
7042+ nleft = Weapon[nitem].bullette;
7043+ if (addWeaponSlot (nuser, nitem) != -1)
7044+ {
7045+ okpickup = 1;
7046+ }
7047+ }
7048+ }
7049+ else
7050+ {
7051+ /* user made */
7052+ isitem = pitembox->isitem;
7053+ nitem = pitembox->n;
7054+ nleft = pitembox->left;
7055+ if (pitembox->isitem)
7056+ {
7057+ /* it's item */
7058+ int nslot = addItemSlot (nuser, pitembox->n);
7059+ if (nslot != -1)
7060+ {
7061+ User[nuser].itemcount[nslot] = pitembox->left;
7062+ okpickup = 1;
7063+ }
7064+ }
7065+ else
7066+ {
7067+ /* its's weapon */
7068+ int nslot = addWeaponSlot (nuser, pitembox->n);
7069+ if (nslot != -1)
7070+ {
7071+ User[nuser].bullette[nslot] = pitembox->left;
7072+ okpickup = 1;
7073+ }
7074+ }
7075+ if (pitembox->message[0] != '\0')
7076+ {
7077+ SendSystemMessagePacket (nuser, pitembox->message);
7078+ }
7079+ free (pitembox);
7080+ }
7081+ if (!okpickup)
7082+ {
7083+ /* can't get this. drop original position */
7084+ char work[MESG_BUFFER];
7085+ sprintf (work, "[You have no space to get %-.32s!]",
7086+ isitem ? Item[nitem].name : Weapon[nitem].name);
7087+ SendSystemMessagePacket (nuser, work);
7088+ addUserItemBox (x, y, isitem, nitem, nleft, NULL);
7089+ }
7090+ else
7091+ {
7092+ MAP (x, y)->id &= ~MAP_THERE_ITEM;
7093+ }
7094+ }
7095+ else if (MAP (x, y)->id & MAP_THERE_ANIMAL)
7096+ {
7097+ int nanimal = MAP (x, y)->animal;
7098+ if (User[nuser].c_type == Hunter)
7099+ {
7100+ /* animal */
7101+ if (Animal[nanimal].moral < ANIMAL_MORAL_PANIC)
7102+ {
7103+ /* ok. you can catch */
7104+ char work[MESG_BUFFER];
7105+ unsigned n;
7106+ MAP (x, y)->id &= ~MAP_THERE_ANIMAL;
7107+ n = Animal[nanimal].pdata->value;
7108+ if (Animal[nanimal].hp == 0)
7109+ {
7110+ n /= 100;
7111+ }
7112+ else
7113+ {
7114+ put_animal_slot (nuser, Animal[nanimal].pdata);
7115+ }
7116+ add_score (nuser, n);
7117+ add_crime (nuser, n);
7118+ sprintf (work, "[You catch %-.16s:%upoint]",
7119+ CUTTAIL (Animal[nanimal].name), n);
7120+ SendSystemMessagePacket (nuser, work);
7121+ DeleteAnimal (nanimal);
7122+ }
7123+ else
7124+ {
7125+ /* aggressive animal */
7126+ SendSystemMessagePacket (nuser,
7127+ "[You can't catch aggressive animal!]");
7128+ }
7129+ }
7130+ else
7131+ {
7132+ /* observer */
7133+ if (Animal[nanimal].hp == 0)
7134+ {
7135+ /* it is animal corpse */
7136+ char work[MESG_BUFFER];
7137+ sprintf (work, "[You collect %-.16s's corpse:10point]",
7138+ CUTTAIL (Animal[nanimal].name));
7139+ SendSystemMessagePacket (nuser, work);
7140+ MAP (x, y)->id &= ~MAP_THERE_ANIMAL;
7141+ add_score (nuser, 10);
7142+ DeleteAnimal (nanimal);
7143+ }
7144+ else
7145+ {
7146+ SendSystemMessagePacket (nuser,
7147+ "[You do not allow to catch animal!]");
7148+ }
7149+ }
7150+ }
7151+ else if (MAP (x, y)->id & MAP_THERE_NPC)
7152+ {
7153+ int npc = MAP (x, y)->animal;
7154+ if (User[nuser].c_type == Observer && Npc[npc].c_type == NpcHunter)
7155+ {
7156+ /* arrest! */
7157+ char work[MESG_BUFFER];
7158+ sprintf (work, "[You arrest %-.16s. Get 500point.]",
7159+ CUTTAIL (Npc[npc].name));
7160+ SendSystemMessagePacket (nuser, work);
7161+ add_score (nuser, 500);
7162+ MAP (x, y)->id &= ~MAP_THERE_NPC;
7163+ Npc[npc].name[0] = '\0';
7164+ }
7165+ }
7166+ else if (MAP (x, y)->player)
7167+ {
7168+ int ntarget = MAP (x, y)->player - 1;
7169+ if (User[nuser].c_type == Observer && User[ntarget].c_type == Hunter)
7170+ {
7171+ char work[MESG_BUFFER];
7172+ if (User[ntarget].maybearrest || User[ntarget].crime_level > 1)
7173+ {
7174+ unsigned long npts = User[ntarget].maybearrest + 100;
7175+ switch (User[ntarget].crime_level)
7176+ {
7177+ case 1:
7178+ npts += ArrestPass / 2;
7179+ add_crime (ntarget, ArrestPass);
7180+ break;
7181+ case 2:
7182+ npts += ArrestAnyone / 2;
7183+ add_crime (ntarget, ArrestAnyone);
7184+ break;
7185+ }
7186+ User[ntarget].crime_level = 0;
7187+ sprintf (work, "[You arrest %-.16s. Get %lupoint.]",
7188+ CUTTAIL (User[ntarget].name), npts);
7189+ SendSystemMessagePacket (nuser, work);
7190+ sprintf (work, "[You were arrested by %-.16s]",
7191+ CUTTAIL (User[nuser].name));
7192+ SendSystemMessagePacket (ntarget, work);
7193+ SendSystemMessagePacket (ntarget, "[Go to Jail!]");
7194+ ClearUser (ntarget);
7195+ User[ntarget].status = Arrested;
7196+ add_arrest (ntarget);
7197+ User[ntarget].action = NoAction;
7198+ User[ntarget].move = NoMove;
7199+ User[ntarget].pos.x = JailPositionX;
7200+ User[ntarget].pos.y = JailPositionY;
7201+ clear_animal_slot (ntarget);
7202+ add_score (nuser, npts);
7203+ }
7204+ else
7205+ {
7206+ sprintf (work, "[You attempt to arrest %-.16s]",
7207+ CUTTAIL (User[ntarget].name));
7208+ SendSystemMessagePacket (nuser, work);
7209+ SendSystemMessagePacket (nuser, "[But he do not crime]");
7210+ sprintf (work, "[%-.16s attempt to arrest you]",
7211+ CUTTAIL (User[nuser].name));
7212+ SendSystemMessagePacket (ntarget, work);
7213+ SendSystemMessagePacket (ntarget, "[But you are innocence]");
7214+ }
7215+ }
7216+ else
7217+ {
7218+ SendSystemMessagePacket (nuser, "[What do you want?]");
7219+ }
7220+ }
7221+ else
7222+ {
7223+ SendSystemMessagePacket (nuser, "[You catch the air]");
7224+ }
7225+ return;
7226+}
7227+
7228+/* process pay*/
7229+static void
7230+processPay (int nuser)
7231+{
7232+ if (User[nuser].status == Arrested)
7233+ {
7234+ unsigned ncost = User[nuser].maybearrest;
7235+ char work[MESG_BUFFER];
7236+ if (ncost)
7237+ {
7238+ if (User[nuser].score >= ncost)
7239+ {
7240+ dec_score (nuser, ncost);
7241+ sprintf (work, "[You paid %upoint for free]", ncost);
7242+ User[nuser].status = Healthy;
7243+ User[nuser].maybearrest = 0;
7244+ ActivateUser (nuser);
7245+ }
7246+ else
7247+ {
7248+ strcpy (work, "[You have not enought point for free]");
7249+ }
7250+ }
7251+ else
7252+ {
7253+ /* ok. you are free now. */
7254+ strcpy (work, "[You are free now]");
7255+ User[nuser].status = Healthy;
7256+ User[nuser].maybearrest = 0;
7257+ ActivateUser (nuser);
7258+ }
7259+ SendSystemMessagePacket (nuser, work);
7260+ }
7261+ else
7262+ {
7263+ SendSystemMessagePacket (nuser, "[No need pay. You are free.]");
7264+ }
7265+ return;
7266+}
7267+
7268+/* buy in HIGE Shop */
7269+static void
7270+buyInHigeShop (int nuser, int buyitem)
7271+{
7272+ char work[MESG_BUFFER];
7273+ int buy = 0;
7274+ int nospace = 0;
7275+ unsigned ncost = 0;
7276+ int n = User[nuser].wk_for_action;
7277+ if (User[nuser].c_type == Hunter)
7278+ {
7279+ if (buyitem)
7280+ {
7281+ if (n >= 0 && n < ForHunterItemLimit)
7282+ {
7283+ ncost = Item[ForHunterItem[n]].cost;
7284+ if (User[nuser].score >= ncost)
7285+ {
7286+ if (addItemSlot (nuser, ForHunterItem[n]) != -1)
7287+ {
7288+ dec_score (nuser, ncost);
7289+ buy = 1;
7290+ }
7291+ else
7292+ {
7293+ nospace = 1;
7294+ }
7295+ }
7296+ }
7297+ }
7298+ else
7299+ {
7300+ if (n >= 0 && n < ForHunterWeaponLimit)
7301+ {
7302+ ncost = Weapon[ForHunterWeapon[n]].cost;
7303+ if (User[nuser].score >= ncost)
7304+ {
7305+ if (addWeaponSlot (nuser, ForHunterWeapon[n]) != -1)
7306+ {
7307+ dec_score (nuser, ncost);
7308+ buy = 1;
7309+ }
7310+ else
7311+ {
7312+ nospace = 1;
7313+ }
7314+ }
7315+ }
7316+ }
7317+ }
7318+ else
7319+ {
7320+ if (buyitem)
7321+ {
7322+ if (n >= 0 && n < ForObserverItemLimit)
7323+ {
7324+ ncost = Item[ForObserverItem[n]].cost;
7325+ if (User[nuser].score >= ncost)
7326+ {
7327+ if (addItemSlot (nuser, ForObserverItem[n]) != -1)
7328+ {
7329+ dec_score (nuser, ncost);
7330+ buy = 1;
7331+ }
7332+ else
7333+ {
7334+ nospace = 1;
7335+ }
7336+ }
7337+ }
7338+ }
7339+ else
7340+ {
7341+ if (n >= 0 && n < ForObserverWeaponLimit)
7342+ {
7343+ ncost = Weapon[ForObserverWeapon[n]].cost;
7344+ if (User[nuser].score >= ncost)
7345+ {
7346+ if (addWeaponSlot (nuser, ForObserverWeapon[n]) != -1)
7347+ {
7348+ dec_score (nuser, ncost);
7349+ buy = 1;
7350+ }
7351+ else
7352+ {
7353+ nospace = 1;
7354+ }
7355+ }
7356+ }
7357+ }
7358+ }
7359+ if (buy)
7360+ {
7361+ if (ncost)
7362+ {
7363+ sprintf (work, "[You paid %upoint]", ncost);
7364+ }
7365+ else
7366+ {
7367+ strcpy (work, "[You no need pay for this!]");
7368+ }
7369+ }
7370+ else
7371+ {
7372+ if (nospace)
7373+ {
7374+ strcpy (work,
7375+ buyitem ? "[no free Item slot]" : "[no free Weapon slot]");
7376+ }
7377+ else if (ncost)
7378+ {
7379+ sprintf (work, "[Need %upoint for buy!]", ncost);
7380+ }
7381+ else
7382+ {
7383+ strcpy (work, "[out of item number range]");
7384+ }
7385+ }
7386+ SendSystemMessagePacket (nuser, work);
7387+ return;
7388+}
7389+
7390+/* buy in User Shop */
7391+static void
7392+buyInUserShop (int nowner, int nuser, int buyitem)
7393+{
7394+ int x = User[nuser].pos.x;
7395+ int y = User[nuser].pos.y;
7396+ int nshop = searchUserShopFromPos (nowner, x, y);
7397+ if (nshop == -1 || User[nowner].myshop[nshop].build == 0)
7398+ {
7399+ SendSystemMessagePacket (nuser, "(FATAL:user shop linkage is broken)");
7400+ }
7401+ else
7402+ {
7403+ char work[MESG_BUFFER];
7404+ unsigned short ncost = 0;
7405+ int n = User[nuser].wk_for_action;
7406+ if (n >= 0 && n < SELLINSHOP_LIMIT)
7407+ {
7408+ if (User[nowner].myshop[nshop].count[buyitem][n])
7409+ {
7410+ int buy = 0;
7411+ int nospace = 0;
7412+ ncost = User[nowner].myshop[nshop].cost[buyitem][n];
7413+ if (User[nuser].score >= ncost)
7414+ {
7415+ int nbuy = User[nowner].myshop[nshop].list[buyitem][n];
7416+ if (buyitem)
7417+ {
7418+ int nitem;
7419+ nitem = addItemSlot (nuser, nbuy);
7420+ if (nitem != -1)
7421+ {
7422+ User[nuser].itemcount[nitem] =
7423+ User[nowner].myshop[nshop].leftuse[buyitem][n];
7424+ buy = 1;
7425+ }
7426+ else
7427+ {
7428+ nospace = 1;
7429+ }
7430+ }
7431+ else
7432+ {
7433+ int nweapon;
7434+ nweapon = addWeaponSlot (nuser, nbuy);
7435+ if (nweapon != -1)
7436+ {
7437+ User[nuser].bullette[nweapon] =
7438+ User[nowner].myshop[nshop].leftuse[buyitem][n];
7439+ buy = 1;
7440+ }
7441+ else
7442+ {
7443+ nospace = 1;
7444+ }
7445+ }
7446+ if (buy)
7447+ {
7448+ dec_score (nuser, ncost);
7449+ add_score (nowner, ncost);
7450+ }
7451+ }
7452+ if (buy)
7453+ {
7454+ User[nowner].myshop[nshop].count[buyitem][n]--;
7455+ if (ncost)
7456+ {
7457+ sprintf (work, "[You paid %upoint]", ncost);
7458+ }
7459+ else
7460+ {
7461+ strcpy (work, "[You no need pay for this!]");
7462+ }
7463+ }
7464+ else
7465+ {
7466+ if (nospace)
7467+ {
7468+ strcpy (work, buyitem ?
7469+ "[no free Item slot]" :
7470+ "[no free Weapon slot]");
7471+ }
7472+ else
7473+ {
7474+ sprintf (work, "[Need %upoint for buy!]", ncost);
7475+ }
7476+ }
7477+ }
7478+ else
7479+ {
7480+ strcpy (work, "[no stock]");
7481+ }
7482+ SendSystemMessagePacket (nuser, work);
7483+ }
7484+ else
7485+ {
7486+ SendSystemMessagePacket (nuser, "[out of item number range]");
7487+ }
7488+ }
7489+ return;
7490+}
7491+
7492+/* process buy */
7493+static void
7494+processBuy (int nuser, int buyitem)
7495+{
7496+ if (MAP (User[nuser].pos.x, User[nuser].pos.y)->id & MAP_THERE_SHOP)
7497+ {
7498+ /* ok. in shop. */
7499+ int nowner = MAP (User[nuser].pos.x, User[nuser].pos.y)->owner;
7500+ if (!nowner)
7501+ {
7502+ buyInHigeShop (nuser, buyitem);
7503+ }
7504+ else
7505+ {
7506+ buyInUserShop (nowner - 1, nuser, buyitem);
7507+ }
7508+ }
7509+ else
7510+ {
7511+ SendSystemMessagePacket (nuser, "[No shop here!]");
7512+ }
7513+ return;
7514+}
7515+
7516+/* process list myshop */
7517+static void
7518+processListMyShop (int nuser)
7519+{
7520+ int i;
7521+ SendSystemMessagePacket (nuser, "<Your shop list>");
7522+ for (i = 0; i < USERSHOP_LIMIT; i++)
7523+ {
7524+ if (User[nuser].myshop[i].build)
7525+ {
7526+ char work[MESG_BUFFER];
7527+ sprintf (work,
7528+ "<%d:%-16.16s (%3d,%3d)>", i + 1,
7529+ User[nuser].myshop[i].name,
7530+ User[nuser].myshop[i].pos.x, User[nuser].myshop[i].pos.y);
7531+ SendSystemMessagePacket (nuser, work);
7532+ }
7533+ }
7534+ SendSystemMessagePacket (nuser, "<end of list>");
7535+ return;
7536+}
7537+
7538+/* process list my animal */
7539+static void
7540+processListMyAnimal (int nuser)
7541+{
7542+ int i;
7543+ char work[MESG_BUFFER];
7544+ SendSystemMessagePacket (nuser, "<CAPTURED ANIMAL>");
7545+ for (i = 0; i < User[nuser].animal_slot; i++)
7546+ {
7547+ ANIMALDATA *p = User[nuser].lastPickupAnimal[i];
7548+ if (p != NULL)
7549+ {
7550+ sprintf (work, "<%d:%-16.16s(%-.32s)>", i + 1, p->name,
7551+ Item[p->forsell_item].name);
7552+ SendSystemMessagePacket (nuser, work);
7553+ }
7554+ else
7555+ {
7556+ sprintf (work, "<%d:EMPTY>", i + 1);
7557+ SendSystemMessagePacket (nuser, work);
7558+ }
7559+ }
7560+ SendSystemMessagePacket (nuser, "<end of list>");
7561+ return;
7562+}
7563+
7564+/* drop item or weapon */
7565+static void
7566+dropItemOrWeapon (int nuser, int isitem, int nslot, const char *pmesg)
7567+{
7568+ int x = User[nuser].pos.x;
7569+ int y = User[nuser].pos.y;
7570+ if (!(MAP (x, y)->id & MAP_HIGH_MASK))
7571+ {
7572+ int n;
7573+ unsigned ncount;
7574+ if (isitem)
7575+ {
7576+ if (nslot < 0 || nslot > ITEM_MAX)
7577+ {
7578+ /* illegal slot */
7579+ SendSystemMessagePacket (nuser, "[Illegal slot number]");
7580+ return;
7581+ }
7582+ n = User[nuser].item[nslot];
7583+ ncount = User[nuser].itemcount[nslot];
7584+ }
7585+ else
7586+ {
7587+ if (nslot < 0 || nslot > WEAPON_MAX)
7588+ {
7589+ /* illegal slot */
7590+ SendSystemMessagePacket (nuser, "[Illegal slot number]");
7591+ return;
7592+ }
7593+ n = User[nuser].weapon[nslot];
7594+ ncount = User[nuser].bullette[nslot];
7595+ }
7596+ if (n && ncount)
7597+ {
7598+ MAP (x, y)->id |= MAP_THERE_ITEM;
7599+ addUserItemBox (x, y, isitem, n, ncount, pmesg);
7600+ if (isitem)
7601+ {
7602+ User[nuser].item[nslot] = 0;
7603+ User[nuser].itemcount[nslot] = 0;
7604+ }
7605+ else
7606+ {
7607+ User[nuser].weapon[nslot] = 0;
7608+ User[nuser].bullette[nslot] = 0;
7609+ }
7610+ SendSystemMessagePacket (nuser, isitem ?
7611+ "[Drop item]" : "[Drop Weapon]");
7612+ }
7613+ else
7614+ {
7615+ SendSystemMessagePacket (nuser, isitem ?
7616+ "[Item is empty]" : "[Weapon is empty]");
7617+ }
7618+ }
7619+ else
7620+ {
7621+ SendSystemMessagePacket (nuser, "[You can't drop here!]");
7622+ }
7623+ return;
7624+}
7625+
7626+/* process list live animal */
7627+static void
7628+processListLiveAnimal (int nuser)
7629+{
7630+ int i;
7631+ int *animal = malloc (AnimalDataLimit * sizeof (int));
7632+ char work[MESG_BUFFER];
7633+ if (animal == NULL)
7634+ {
7635+ SendSystemMessagePacket (nuser,
7636+ "<FATAL:can't allocate animal list memory!>");
7637+ return;
7638+ }
7639+ memset (animal, 0, AnimalDataLimit * sizeof (int));
7640+ SendSystemMessagePacket (nuser, "<ANIMAL LIST>");
7641+ for (i = 0; i < AnimalLimit; i++)
7642+ {
7643+ if (Animal[i].pdata != NULL && Animal[i].hp)
7644+ {
7645+ animal[Animal[i].pdata->n]++;
7646+ }
7647+ }
7648+ for (i = 0; i < AnimalDataLimit; i++)
7649+ {
7650+ if (animal[i])
7651+ {
7652+ sprintf (work, "<'%-16.16s' lives:%3d rate:%3u value:%5u>",
7653+ AnimalData[i].name, animal[i],
7654+ AnimalData[i].rate, AnimalData[i].value);
7655+ SendSystemMessagePacket (nuser, work);
7656+ }
7657+ }
7658+ SendSystemMessagePacket (nuser, "<end of list>");
7659+ free (animal);
7660+ return;
7661+}
7662+
7663+#ifdef USE_MAIL
7664+/* list my mailbox */
7665+static void
7666+processListMyMail (int nuser)
7667+{
7668+ int i;
7669+ int f = 0;
7670+ SendSystemMessagePacket (nuser, "<MAILBOX>");
7671+ ReorderMailbox (nuser);
7672+ for (i = 0; i < MAIL_BOX_LIMIT; i++)
7673+ {
7674+ if (User[nuser].mail[i] != NULL)
7675+ {
7676+ MAILDATA *pmail = User[nuser].mail[i];
7677+ char subjectbuffer[32];
7678+ char work[MESG_BUFFER];
7679+ if (pmail->subject[0])
7680+ {
7681+ int n = pmail->subject[0];
7682+ if (n > 32)
7683+ {
7684+ n = 32;
7685+ }
7686+ strncpy (subjectbuffer, pmail->subject + 1, n);
7687+ for (; n < 32; n++)
7688+ {
7689+ subjectbuffer[n] = '\0';
7690+ }
7691+ }
7692+ else
7693+ {
7694+ strcpy (subjectbuffer, "NO SUBJECT");
7695+ }
7696+ sprintf (work, "<%c%2d:%-16.16s %-.32s>",
7697+ pmail->readflag ? ' ' : '*', i + 1,
7698+ User[pmail->fromuser].name, subjectbuffer);
7699+ SendSystemMessagePacket (nuser, work);
7700+ f = 1;
7701+ }
7702+ }
7703+ SendSystemMessagePacket (nuser, (!f) ? "<no mail!>" : "<end of list>");
7704+ return;
7705+}
7706+
7707+/* read my mail */
7708+static void
7709+processReadMyMail (int nuser)
7710+{
7711+ int n = User[nuser].wk_for_action;
7712+ if (n >= 0 && n < MAIL_BOX_LIMIT && User[nuser].mail[n] != NULL)
7713+ {
7714+ /* ok. read this mail. */
7715+ printf ("user:%d read mail...\n", nuser);
7716+ if (SendMailHeader (nuser, User[nuser].mail[n]) ||
7717+ SendMailBody (nuser, User[nuser].mail[n]))
7718+ {
7719+ /* error */
7720+ DisconnectUser (nuser);
7721+ }
7722+ else
7723+ {
7724+ User[nuser].mail[n]->readflag = 1;
7725+ SendSystemMessagePacket (nuser, "[end of mail-data transfer]");
7726+ puts ("done");
7727+ }
7728+ }
7729+ else
7730+ {
7731+ SendSystemMessagePacket (nuser, "[no such mail!]");
7732+ }
7733+ return;
7734+}
7735+
7736+/* delete my mail */
7737+static void
7738+processDeleteMyMail (int nuser)
7739+{
7740+ int n = User[nuser].wk_for_action;
7741+ if (n >= 0 && n < MAIL_BOX_LIMIT && User[nuser].mail[n] != NULL)
7742+ {
7743+ /* ok. delete this mail. */
7744+ FreeMail (User[nuser].mail[n]);
7745+ User[nuser].mail[n] = NULL;
7746+ ReorderMailbox (nuser);
7747+ SendSystemMessagePacket (nuser, "[deleted 1 message]");
7748+ }
7749+ else
7750+ {
7751+ SendSystemMessagePacket (nuser, "[no such mail!]");
7752+ }
7753+ return;
7754+}
7755+
7756+#ifdef USE_BBS
7757+/* list bbs */
7758+static void
7759+processListBBS (int nuser)
7760+{
7761+ int i;
7762+ int f = 0;
7763+ SendSystemMessagePacket (nuser, "<BBS article(s)>");
7764+ for (i = 0; i < BBS_BOX_LIMIT; i++)
7765+ {
7766+ if (BBSdata[i] != NULL)
7767+ {
7768+ MAILDATA *pmail = BBSdata[i];
7769+ char subjectbuffer[32];
7770+ char work[MESG_BUFFER];
7771+ if (pmail->subject[0])
7772+ {
7773+ int n = pmail->subject[0];
7774+ if (n > 32)
7775+ {
7776+ n = 32;
7777+ }
7778+ strncpy (subjectbuffer, pmail->subject + 1, n);
7779+ for (; n < 32; n++)
7780+ {
7781+ subjectbuffer[n] = '\0';
7782+ }
7783+ }
7784+ else
7785+ {
7786+ strcpy (subjectbuffer, "NO SUBJECT");
7787+ }
7788+ sprintf (work, "<%2d:%-16.16s %-.32s>",
7789+ i + 1, User[pmail->fromuser].name, subjectbuffer);
7790+ SendSystemMessagePacket (nuser, work);
7791+ f = 1;
7792+ }
7793+ }
7794+ SendSystemMessagePacket (nuser, (!f) ? "<no article!>" : "<end of list>");
7795+ return;
7796+}
7797+
7798+/* read bbs article */
7799+static void
7800+processReadBBS (int nuser)
7801+{
7802+ int n = User[nuser].wk_for_action;
7803+ if (n >= 0 && n < BBS_BOX_LIMIT && BBSdata[n] != NULL)
7804+ {
7805+ /* ok. read this article. */
7806+ printf ("user:%d read article %d...\n", nuser, n + 1);
7807+ if (SendBBSHeader (nuser, BBSdata[n]) ||
7808+ SendBBSBody (nuser, BBSdata[n]))
7809+ {
7810+ /* error */
7811+ DisconnectUser (nuser);
7812+ }
7813+ else
7814+ {
7815+ SendSystemMessagePacket (nuser, "[end of article-data transfer]");
7816+ puts ("done");
7817+ }
7818+ }
7819+ else
7820+ {
7821+ SendSystemMessagePacket (nuser, "[no such article!]");
7822+ }
7823+ return;
7824+}
7825+
7826+#endif /* USE_BBS */
7827+#endif /* USE_MAIL */
7828+
7829+/* resolve Users */
7830+static void
7831+ResolveUserPhase (void)
7832+{
7833+ int i;
7834+ for (i = 0; i < UserLimit; i++)
7835+ {
7836+ if (User[i].session.handle != INVALID_SOCKET)
7837+ {
7838+ switch (User[i].action)
7839+ {
7840+ case NoAction:
7841+ break;
7842+ case Fire1:
7843+ processFireWeapon (i, 0);
7844+ break;
7845+ case Fire2:
7846+ processFireWeapon (i, 1);
7847+ break;
7848+ case UseItem1:
7849+ processUseItem (i, 0);
7850+ break;
7851+ case UseItem2:
7852+ processUseItem (i, 1);
7853+ break;
7854+ case UseItem3:
7855+ processUseItem (i, 2);
7856+ break;
7857+ case UseItem4:
7858+ processUseItem (i, 3);
7859+ break;
7860+ case PickUp:
7861+ processPickUp (i);
7862+ break;
7863+ case Pay:
7864+ processPay (i);
7865+ break;
7866+ case BuyWeapon:
7867+ processBuy (i, 0);
7868+ break;
7869+ case BuyItem:
7870+ processBuy (i, 1);
7871+ break;
7872+ case Who:
7873+ SendWhoList (i);
7874+ break;
7875+ case RequestWeapon:
7876+ SendWeaponList (i);
7877+ break;
7878+ case RequestItem:
7879+ SendItemList (i);
7880+ break;
7881+ case StoreAnimal:
7882+ storeLastPickup (i, User[i].lwk_for_action);
7883+ break;
7884+ case StoreWeapon:
7885+ storeItemOrWeapon (i, 0,
7886+ User[i].wk_for_action,
7887+ User[i].lwk_for_action);
7888+ break;
7889+ case StoreItem:
7890+ storeItemOrWeapon (i, 1,
7891+ User[i].wk_for_action,
7892+ User[i].lwk_for_action);
7893+ break;
7894+ case DiscardWeapon:
7895+ discardItemOrWeapon (i, 0, User[i].wk_for_action);
7896+ break;
7897+ case DiscardItem:
7898+ discardItemOrWeapon (i, 1, User[i].wk_for_action);
7899+ break;
7900+ case ListMyShop:
7901+ processListMyShop (i);
7902+ break;
7903+ case DropWeapon:
7904+ dropItemOrWeapon (i, 0, User[i].wk_for_action,
7905+ User[i].mesg_for_action);
7906+ break;
7907+ case DropItem:
7908+ dropItemOrWeapon (i, 1, User[i].wk_for_action,
7909+ User[i].mesg_for_action);
7910+ break;
7911+ case ListMyAnimal:
7912+ processListMyAnimal (i);
7913+ break;
7914+ case DoSay:
7915+ processSendMessage (i, (unsigned char *)
7916+ User[i].mesg_for_action);
7917+ break;
7918+ case DoTell:
7919+ processSendMessage2User (i, (unsigned char *)
7920+ User[i].mesg_for_action);
7921+ break;
7922+ case DoBroadcast:
7923+ processBroadcastMessage (i, (unsigned char *)
7924+ User[i].mesg_for_action);
7925+ break;
7926+ case DoWriteMesg:
7927+ processWriteMesg (i, User[i].wk_for_action,
7928+ User[i].mesg_for_action);
7929+ break;
7930+ case DoChangeShopName:
7931+ processChangeMyshop (i, User[i].mesg_for_action);
7932+ break;
7933+ case DoDestroyShop:
7934+ processDestroyMyshop (i);
7935+ break;
7936+ case ListLiveAnimal:
7937+ processListLiveAnimal (i);
7938+ break;
7939+ case DoChangeAnimalName:
7940+ processChangeUserAnimalName (i, User[i].mesg_for_action);
7941+ break;
7942+#ifdef USE_MAIL
7943+ case ListMyMail:
7944+ processListMyMail (i);
7945+ break;
7946+ case ReadMyMail:
7947+ processReadMyMail (i);
7948+ break;
7949+ case DeleteMyMail:
7950+ processDeleteMyMail (i);
7951+ break;
7952+#ifdef USE_BBS
7953+ case ListBBS:
7954+ processListBBS (i);
7955+ break;
7956+ case ReadBBS:
7957+ processReadBBS (i);
7958+ break;
7959+#endif /* USE_BBS */
7960+#endif /* USE_MAIL */
7961+ default:
7962+ break;
7963+ }
7964+ User[i].action = NoAction;
7965+ }
7966+ }
7967+ return;
7968+}
7969+
7970+/* movement bullets */
7971+static void
7972+MovementBulletPhase (void)
7973+{
7974+ struct bullet_t *pb = pBullet;
7975+ while (pb != NULL)
7976+ {
7977+ if (pb->ndistance > 0)
7978+ {
7979+ if (pb->ntime == 0)
7980+ {
7981+ /* move */
7982+ pb->pos.x += FWVectorX[pb->direction];
7983+ pb->pos.y += FWVectorY[pb->direction];
7984+ adjust_pos (&pb->pos.x, &pb->pos.y);
7985+ pb->ntime = pb->pweapon->speed;
7986+ pb->ndistance--;
7987+ if (pb->ndamage > pb->pweapon->reduce)
7988+ {
7989+ pb->ndamage -= pb->pweapon->reduce;
7990+ }
7991+ else
7992+ {
7993+ pb->ndamage = 0;
7994+ }
7995+ }
7996+ else
7997+ {
7998+ pb->ntime--;
7999+ }
8000+ }
8001+ pb = pb->pprev;
8002+ }
8003+ return;
8004+}
8005+
8006+/* check animal count */
8007+static int
8008+CountLiveAnimal (ANIMALDATA * p)
8009+{
8010+ int ret = 0;
8011+ int i;
8012+ for (i = 0; i < AnimalLimit; i++)
8013+ {
8014+ if (Animal[i].pdata == p && Animal[i].hp)
8015+ {
8016+ ret++;
8017+ }
8018+ }
8019+ return ret;
8020+}
8021+
8022+/* resolve */
8023+static void
8024+ResolveBulletPhase (void)
8025+{
8026+ struct bullet_t *pb = pBullet;
8027+ while (pb != NULL)
8028+ {
8029+ struct bullet_t *pwork = pb->pprev;
8030+ if (pb->ndamage > 0)
8031+ {
8032+ int x = pb->pos.x;
8033+ int y = pb->pos.y;
8034+ unsigned char c = MAP (x, y)->id & MAP_MASK;
8035+ if (MAP (x, y)->player)
8036+ {
8037+ /* hit to player */
8038+ int nuser = MAP (x, y)->player - 1;
8039+ if (User[nuser].status == Healthy || User[nuser].maybearrest)
8040+ {
8041+ int ndamage = getrand (pb->ndamage >> 1, pb->ndamage);
8042+ cause_damage (nuser, ndamage, pb->nuser, pb->t_type);
8043+ if (pb->pweapon->b_type != BulletAP)
8044+ {
8045+ /* bullet vanish */
8046+ FreeBullet (pb);
8047+ pb = NULL;
8048+ }
8049+ }
8050+ }
8051+ else if (MAP (x, y)->id & MAP_THERE_ANIMAL)
8052+ {
8053+ /* hit to animal */
8054+ int nanimal = MAP (x, y)->animal;
8055+ if (Animal[nanimal].hp)
8056+ {
8057+ int aggressive =
8058+ (Animal[nanimal].moral > ANIMAL_MORAL_NORMAL) ? 1 : 0;
8059+ int ndamage = getrand (pb->ndamage >> 1, pb->ndamage);
8060+ int nmoral =
8061+ getrand (pb->pweapon->moral >> 1, pb->pweapon->moral);
8062+ char work[MESG_BUFFER];
8063+ if (pb->nuser != -1)
8064+ {
8065+ if (pb->t_type == TargetUser)
8066+ {
8067+ sprintf (work, "You attack animal '%-.16s'",
8068+ CUTTAIL (Animal[nanimal].name));
8069+ SendSystemMessagePacket (pb->nuser, work);
8070+ }
8071+ sprintf (work, "[%-.16s shoot animal!]",
8072+ CUTTAIL ((pb->t_type == TargetUser) ?
8073+ User[pb->nuser].name :
8074+ Npc[pb->nuser].name));
8075+ if (pb->t_type == TargetUser)
8076+ {
8077+ SendMessageNearUserPosition2 (pb->pos, work,
8078+ pb->nuser);
8079+ }
8080+ else
8081+ {
8082+ SendMessageNearUserPosition (pb->pos, work);
8083+ }
8084+ }
8085+ cause_damage_animal (nanimal, ndamage, nmoral);
8086+ if (Animal[nanimal].hp == 0)
8087+ {
8088+ if (pb->nuser != -1 && pb->t_type == TargetUser)
8089+ {
8090+ sprintf (work, "animal '%-.16s' died.",
8091+ CUTTAIL (Animal[nanimal].name));
8092+ SendSystemMessagePacket (pb->nuser, work);
8093+ if (CountLiveAnimal (Animal[nanimal].pdata) == 0)
8094+ {
8095+ /* this is last animal! */
8096+ sprintf (work,
8097+ "[animal '%-.16s' is extermination!]",
8098+ CUTTAIL (Animal[nanimal].name));
8099+ SendSystemMessagePacket (pb->nuser, work);
8100+ if (User[pb->nuser].c_type == Observer)
8101+ {
8102+ unsigned pts = Animal[nanimal].pdata->value;
8103+ dec_score (pb->nuser, pts);
8104+ sprintf (work, "[You lost %upoint!]", pts);
8105+ SendSystemMessagePacket (pb->nuser, work);
8106+ }
8107+ }
8108+ else
8109+ {
8110+ if (User[pb->nuser].c_type == Observer &&
8111+ aggressive)
8112+ {
8113+ unsigned pts = Animal[nanimal].pdata->moral;
8114+ if (pts)
8115+ {
8116+ add_score (pb->nuser, pts);
8117+ sprintf (work,
8118+ "[You kill dangerous animal."
8119+ " get %upoint]", pts);
8120+ SendSystemMessagePacket (pb->nuser,
8121+ work);
8122+ }
8123+ }
8124+ }
8125+ }
8126+ Animal[nanimal].moral = 0;
8127+ }
8128+ else if (Animal[nanimal].moral == 0)
8129+ {
8130+ if (pb->nuser != -1 && pb->t_type == TargetUser)
8131+ {
8132+ sprintf (work, "animal '%-.16s' stun.",
8133+ CUTTAIL (Animal[nanimal].name));
8134+ SendSystemMessagePacket (pb->nuser, work);
8135+ }
8136+ }
8137+ if (Animal[nanimal].hp)
8138+ {
8139+ if (pb->pweapon->b_type == BulletCharm)
8140+ {
8141+ /* charm animal! */
8142+ if (getrand (1, 100) <=
8143+ Animal[nanimal].pdata->charm_rate)
8144+ {
8145+ /* success! */
8146+ if (Animal[nanimal].owner_user == -1)
8147+ {
8148+ sprintf (work, "You charm animal '%-.16s'!",
8149+ CUTTAIL (Animal[nanimal].name));
8150+ SendSystemMessagePacket (pb->nuser, work);
8151+ Animal[nanimal].owner_user = pb->nuser;
8152+ }
8153+ else
8154+ {
8155+ sprintf (work,
8156+ "Animal '%-.16s' is free now!",
8157+ CUTTAIL (Animal[nanimal].name));
8158+ SendMessageNearUserPosition (pb->pos, work);
8159+ Animal[nanimal].owner_user = -1;
8160+ }
8161+ }
8162+ else
8163+ {
8164+ /* fail */
8165+ sprintf (work,
8166+ "You fail to charm animal '%-.16s'.",
8167+ CUTTAIL (Animal[nanimal].name));
8168+ SendSystemMessagePacket (pb->nuser, work);
8169+ }
8170+ }
8171+ else
8172+ {
8173+ if (Animal[nanimal].moral >= ANIMAL_MORAL_PANIC &&
8174+ getrand (1, 100) <= ANIMAL_RATE_ANGRY)
8175+ {
8176+ /* angry! */
8177+ Animal[nanimal].charmcount = AngryCount;
8178+ if (pb->nuser == -1)
8179+ {
8180+ Animal[nanimal].charm_pos = pb->fire_pos;
8181+ Animal[nanimal].charm = CharmPosition;
8182+ }
8183+ else
8184+ {
8185+ Animal[nanimal].ntarget = pb->nuser;
8186+ Animal[nanimal].charm =
8187+ (pb->t_type == TargetUser) ?
8188+ CharmUser : CharmNpc;
8189+ }
8190+ }
8191+ else if (Animal[nanimal].moral < ANIMAL_MORAL_PANIC)
8192+ {
8193+ /* run away */
8194+ Animal[nanimal].charmcount = 0;
8195+ }
8196+ }
8197+ }
8198+ if (pb->pweapon->b_type != BulletAP)
8199+ {
8200+ /* bullet vanish */
8201+ FreeBullet (pb);
8202+ pb = NULL;
8203+ }
8204+ }
8205+ }
8206+ else if (MAP (x, y)->id & MAP_THERE_NPC)
8207+ {
8208+ /* hit to NPC */
8209+ int npc = MAP (x, y)->animal;
8210+ if (Npc[npc].hp)
8211+ {
8212+ int ndamage = getrand (pb->ndamage >> 1, pb->ndamage);
8213+ char work[MESG_BUFFER];
8214+ if (pb->nuser != -1 && pb->t_type == TargetUser)
8215+ {
8216+ sprintf (work, "You attack '%-.16s'",
8217+ CUTTAIL (Npc[npc].name));
8218+ SendSystemMessagePacket (pb->nuser, work);
8219+ }
8220+ cause_damage_npc (npc, ndamage);
8221+ if (Npc[npc].hp == 0)
8222+ {
8223+ if (pb->nuser != -1 && pb->t_type == TargetUser)
8224+ {
8225+ sprintf (work, "'%-.16s' died.",
8226+ CUTTAIL (Npc[npc].name));
8227+ SendSystemMessagePacket (pb->nuser, work);
8228+ if (User[pb->nuser].c_type == Hunter &&
8229+ Npc[npc].c_type == NpcObserver)
8230+ {
8231+ /* it is crime! */
8232+ add_crime (pb->nuser, CrimeNpcMurder);
8233+ SendSystemMessagePacket (pb->nuser,
8234+ "[You are murder!]");
8235+ }
8236+ }
8237+ else
8238+ {
8239+ if (pb->nuser != -1 && pb->t_type == TargetNpc)
8240+ {
8241+ sprintf (work, "'%-.16s' killed by ",
8242+ CUTTAIL (Npc[npc].name));
8243+ strcat (work, CUTTAIL (Npc[pb->nuser].name));
8244+ }
8245+ else
8246+ {
8247+ sprintf (work, "'%-.16s' killed by any!",
8248+ CUTTAIL (Npc[npc].name));
8249+ }
8250+ SendMessageNearUserPosition (Npc[npc].pos, work);
8251+ }
8252+ Npc[npc].name[0] = '\0';
8253+ MAP (Npc[npc].pos.x, Npc[npc].pos.y)->id &=
8254+ ~MAP_THERE_NPC;
8255+ }
8256+ else
8257+ {
8258+ /* still alive */
8259+ if (Npc[npc].c_type == NpcObserver)
8260+ {
8261+ /* maybe counter-attack */
8262+ if (!(pb->t_type == TargetNpc && pb->nuser == npc))
8263+ {
8264+ static const char *mesg[5] = {
8265+ "%-.16s say,Hey! Why do you attack me?",
8266+ "%-.16s say,No! Don't shoot me!",
8267+ "%-.16s say,What's think?!",
8268+ "%-.16s say,Ohch! We are under fire!",
8269+ "%-.16s say,Ok. I will kill you."
8270+ };
8271+ NPCsay (npc, mesg, 5);
8272+ Npc[npc].ntarget_user = pb->nuser;
8273+ Npc[npc].t_type = pb->t_type;
8274+ Npc[npc].nochangelock_count =
8275+ NPC_COUNTERATTACK_COUNT;
8276+ }
8277+ }
8278+ else if (Npc[npc].c_type == NpcHige)
8279+ {
8280+ int willcounter = 0;
8281+ if (pb->t_type == TargetUser &&
8282+ Npc[npc].owner_user != pb->nuser)
8283+ {
8284+ willcounter = 1;
8285+ }
8286+ else if (pb->t_type == TargetNpc &&
8287+ Npc[npc].owner_user != -1 &&
8288+ Npc[npc].owner_user !=
8289+ Npc[pb->nuser].owner_user)
8290+ {
8291+ willcounter = 1;
8292+ }
8293+ if (willcounter)
8294+ {
8295+ static const char *mesg[5] = {
8296+ "%-.16s say,Detect one boggy!",
8297+ "%-.16s say,We are under attack!",
8298+ "%-.16s say,Engage!",
8299+ "%-.16s say,Caution! Enemy fire!",
8300+ "%-.16s say,Emergency! Enemy attack us!"
8301+ };
8302+ NPCsay (npc, mesg, 5);
8303+ Npc[npc].ntarget_user = pb->nuser;
8304+ Npc[npc].t_type = pb->t_type;
8305+ }
8306+ else
8307+ {
8308+ static const char *mesg[5] = {
8309+ "%-.16s say,Hey! No shoot me!",
8310+ "%-.16s say,I'm friendly!",
8311+ "%-.16s say,This is friendly! Don't shoot!",
8312+ "%-.16s say,Don't shoot! Are you enemy's spy?",
8313+ "%-.16s say,Take more care!"
8314+ };
8315+ NPCsay (npc, mesg, 5);
8316+ }
8317+ }
8318+ }
8319+ if (pb->pweapon->b_type != BulletAP)
8320+ {
8321+ /* bullet vanish */
8322+ FreeBullet (pb);
8323+ pb = NULL;
8324+ }
8325+ }
8326+ }
8327+ else if (c == MAP_ROCK)
8328+ {
8329+ /* collision rock */
8330+ if (pb->pweapon->b_type != BulletAP)
8331+ {
8332+ /* bullet vanish */
8333+ FreeBullet (pb);
8334+ pb = NULL;
8335+ }
8336+ }
8337+ else if (c == MAP_TREE)
8338+ {
8339+ /* collision tree */
8340+ if (pb->pweapon->b_type != BulletAP)
8341+ {
8342+ if (pb->ndamage >= TreeHP)
8343+ {
8344+ /* can break tree */
8345+ pb->ndamage -= TreeHP;
8346+ INVALID_MAP (x, y);
8347+ MAP (x, y)->id |= MAP_ROAD;
8348+ }
8349+ else
8350+ {
8351+ /* bullet vanish */
8352+ FreeBullet (pb);
8353+ pb = NULL;
8354+ }
8355+ }
8356+ else
8357+ {
8358+ /* break tree! */
8359+ INVALID_MAP (x, y);
8360+ MAP (x, y)->id |= MAP_ROAD;
8361+ }
8362+ }
8363+ }
8364+ if (pb != NULL && pb->ndistance == 0)
8365+ {
8366+ /* no more left effective range... */
8367+ /* bullet vanish */
8368+ FreeBullet (pb);
8369+ }
8370+ pb = pwork;
8371+ }
8372+ return;
8373+}
8374+
8375+/* check attacker */
8376+static void
8377+check_live_attacker (int nuser)
8378+{
8379+ if (User[nuser].lastuser != -1)
8380+ {
8381+ switch (User[nuser].lastuser_type)
8382+ {
8383+ case TargetUser:
8384+ if (User[User[nuser].lastuser].session.handle != INVALID_SOCKET &&
8385+ User[User[nuser].lastuser].hp == 0)
8386+ {
8387+ User[nuser].lastuser = -1;
8388+ User[nuser].lastuser_type = TargetNone;
8389+ }
8390+ break;
8391+ case TargetNpc:
8392+ if (Npc[User[nuser].lastuser].name[0] == '\0')
8393+ {
8394+ User[nuser].lastuser = -1;
8395+ User[nuser].lastuser_type = TargetNone;
8396+ }
8397+ break;
8398+ case TargetAnimal:
8399+ if (Animal[User[nuser].lastuser].pdata == NULL ||
8400+ Animal[User[nuser].lastuser].hp == 0 ||
8401+ Animal[User[nuser].lastuser].moral == 0)
8402+ {
8403+ User[nuser].lastuser = -1;
8404+ User[nuser].lastuser_type = TargetNone;
8405+ }
8406+ break;
8407+ default:
8408+ break;
8409+ }
8410+ }
8411+ return;
8412+}
8413+
8414+/* prep for next turn */
8415+static void
8416+TurnEndPhase (int tickcount)
8417+{
8418+ static int dec_arrest_count = 0;
8419+ static int hungry_count = 0;
8420+ static unsigned long dec_jail_count = 0;
8421+ int i;
8422+ for (i = 0; i < UserLimit; i++)
8423+ {
8424+ if (User[i].session.handle != INVALID_SOCKET)
8425+ {
8426+ /* check attacker */
8427+ check_live_attacker (i);
8428+ /* check alive */
8429+ if (User[i].hp == 0)
8430+ {
8431+ /* die */
8432+ SendEffectDeathPacket (i);
8433+ dec_score (i, 100);
8434+ if (User[i].c_type == Hunter)
8435+ {
8436+ dec_score (i, User[i].maybearrest);
8437+ switch (User[i].crime_level)
8438+ {
8439+ case 1:
8440+ dec_score (i, ArrestPass / 2);
8441+ break;
8442+ case 2:
8443+ dec_score (i, ArrestAnyone / 2);
8444+ break;
8445+ }
8446+ }
8447+ if (User[i].lastuser != -1)
8448+ {
8449+ /* anyone kill you */
8450+ char work[MESG_BUFFER];
8451+ const char *pname;
8452+ int nuser = User[i].lastuser;
8453+ if (User[i].lastuser_type == TargetUser)
8454+ {
8455+ sprintf (work, "[You kill %-.16s]",
8456+ CUTTAIL (User[i].name));
8457+ SendSystemMessagePacket (nuser, work);
8458+ }
8459+ switch (User[i].lastuser_type)
8460+ {
8461+ case TargetUser:
8462+ pname = User[nuser].name;
8463+ break;
8464+ case TargetNpc:
8465+ pname = Npc[nuser].name;
8466+ break;
8467+ case TargetAnimal:
8468+ pname = Animal[nuser].name;
8469+ break;
8470+ default:
8471+ pname = NULL;
8472+ break;
8473+ }
8474+ if (pname != NULL)
8475+ {
8476+ sprintf (work,
8477+ "[You were killed by %-.16s]",
8478+ CUTTAIL (pname));
8479+ SendSystemMessagePacket (i, work);
8480+ }
8481+ if (User[i].lastuser_type == TargetUser)
8482+ {
8483+ if (User[nuser].c_type == Observer &&
8484+ User[i].c_type == Hunter)
8485+ {
8486+ unsigned npoint = 0;
8487+ npoint += User[i].score / 100;
8488+ if (npoint)
8489+ {
8490+ add_score (nuser, npoint);
8491+ sprintf (work, "[You get %upoint]", npoint);
8492+ SendSystemMessagePacket (nuser, work);
8493+ }
8494+ }
8495+ else if (User[nuser].c_type == Hunter &&
8496+ User[i].c_type == Observer)
8497+ {
8498+ add_crime (nuser, CrimeMurder);
8499+ SendSystemMessagePacket (nuser,
8500+ "[You are murder!]");
8501+ }
8502+ else if (User[i].crime_level == 2)
8503+ {
8504+ /* it is murder */
8505+ unsigned npoint = User[i].score / 100;
8506+ if (npoint)
8507+ {
8508+ add_score (nuser, npoint);
8509+ sprintf (work, "[You get bonus %upoint]",
8510+ npoint);
8511+ SendSystemMessagePacket (nuser, work);
8512+ }
8513+ }
8514+ }
8515+ }
8516+ else
8517+ {
8518+ /* you die by your own */
8519+ SendSystemMessagePacket (i, "[You died]");
8520+ }
8521+ if (!(MAP (User[i].pos.x, User[i].pos.y)->id &
8522+ (MAP_THERE_WALL | MAP_THERE_ITEM)))
8523+ {
8524+ MAP (User[i].pos.x, User[i].pos.y)->id |= MAP_THERE_ITEM;
8525+ }
8526+ ClearUser (i); /* clear from map */
8527+ ActivateUser (i); /* reborn */
8528+ }
8529+ if (dec_arrest_count == 0 &&
8530+ User[i].c_type == Hunter && User[i].maybearrest)
8531+ {
8532+ if (User[i].maybearrest > DecArrest)
8533+ {
8534+ User[i].maybearrest -= DecArrest;
8535+ }
8536+ else
8537+ {
8538+ User[i].maybearrest = 0;
8539+ }
8540+ if (User[i].status == Arrested && User[i].arrest_count > 1)
8541+ {
8542+ unsigned long crime_floor = User[i].arrest_count * 100;
8543+ if (User[i].maybearrest < crime_floor)
8544+ {
8545+ User[i].maybearrest = crime_floor;
8546+ }
8547+ }
8548+ }
8549+ if (dec_jail_count == 0 && User[i].arrest_count)
8550+ {
8551+ User[i].arrest_count--;
8552+ }
8553+ if (tickcount == 0)
8554+ {
8555+ /* send information data to User */
8556+ if (SendUpdateInformation (i) != 0)
8557+ {
8558+ DisconnectUser (i);
8559+ }
8560+ }
8561+ if (User[i].cloak_count)
8562+ {
8563+ User[i].cloak_count--;
8564+ }
8565+ if (User[i].hold_count)
8566+ {
8567+ User[i].hold_count--;
8568+ }
8569+ if (User[i].reload[0])
8570+ {
8571+ User[i].reload[0]--;
8572+ }
8573+ if (User[i].reload[1])
8574+ {
8575+ User[i].reload[1]--;
8576+ }
8577+ if (hungry_count == 0 && User[i].status == Healthy)
8578+ {
8579+ /* hungry? */
8580+ switch (User[i].hungry)
8581+ {
8582+ case 50:
8583+ SendSystemMessagePacket (i, "[You feel hungry]");
8584+ break;
8585+ case 10:
8586+ SendSystemMessagePacket (i, "[You feel weak by hungry]");
8587+ break;
8588+ case 4:
8589+ case 3:
8590+ case 2:
8591+ case 1:
8592+ case 0:
8593+ SendSystemMessagePacket (i, "[You can't move by hungry!]");
8594+ User[i].hold_count += 10 * (5 - User[i].hungry);
8595+ break;
8596+ default:
8597+ break;
8598+ }
8599+ if (User[i].hungry > 0)
8600+ {
8601+ User[i].hungry--;
8602+ }
8603+ else
8604+ {
8605+ char work[MESG_BUFFER];
8606+ cause_damage (i, DamageWhenHungry, -1, TargetNone);
8607+ sprintf (work, "[You lost %uHP by hugry]",
8608+ DamageWhenHungry);
8609+ SendSystemMessagePacket (i, work);
8610+ }
8611+ }
8612+ if (MAP (User[i].pos.x, User[i].pos.y)->id & MAP_THERE_HOLE)
8613+ {
8614+ /* it's hole! */
8615+ char work[MESG_BUFFER];
8616+ MAP (User[i].pos.x, User[i].pos.y)->id &= ~MAP_THERE_HOLE;
8617+ User[i].hold_count = HoldCount;
8618+ SendSystemMessagePacket (i, "[You fall in hole!]");
8619+ SendEffectFallInHolePacket (i);
8620+ sprintf (work, "[You hear sound %-.16s fall in hole]",
8621+ CUTTAIL (User[i].name));
8622+ SendMessageNearUser (i, work);
8623+ }
8624+ User[i].idletimer++;
8625+ if (User[i].idletimer == MaxTimeoutValue)
8626+ {
8627+ /* perhaps,disconnect session. */
8628+ char work[USERNAME_LEN];
8629+ memcpy (work, User[i].name, USERNAME_LEN);
8630+#ifdef MAKEWIN32
8631+ convertH2C (work, USERNAME_LEN);
8632+#endif
8633+ printf ("user(%d)[%-16.16s] no response\n", i, work);
8634+ DisconnectUser (i);
8635+ }
8636+ }
8637+ }
8638+ if (dec_arrest_count == 0)
8639+ {
8640+ dec_arrest_count = TurnPerDecArrest;
8641+ }
8642+ else
8643+ {
8644+ dec_arrest_count--;
8645+ }
8646+ if (dec_jail_count == 0)
8647+ {
8648+ dec_jail_count = TurnPerJailCount;
8649+ }
8650+ else
8651+ {
8652+ dec_jail_count--;
8653+ }
8654+ if (hungry_count == 0)
8655+ {
8656+ hungry_count = TurnPerHungry;
8657+ }
8658+ else
8659+ {
8660+ hungry_count--;
8661+ }
8662+ return;
8663+}
8664+
8665+/* count players in area */
8666+static int
8667+count_player_in (int x, int y)
8668+{
8669+ int ret = 0;
8670+ int by = y - 1;
8671+ int i;
8672+ x--;
8673+ for (i = 0; i < 3; i++)
8674+ {
8675+ int bx = x;
8676+ int j;
8677+ for (j = 0; j < 3; j++)
8678+ {
8679+ int n;
8680+ adjust_pos (&bx, &by);
8681+ n = MAP (bx, by)->player;
8682+ if (n && User[n - 1].cloak_count == 0)
8683+ {
8684+ ret++;
8685+ }
8686+ else if (MAP (bx, by)->id & MAP_THERE_NPC)
8687+ {
8688+ ret++;
8689+ }
8690+ bx++;
8691+ }
8692+ by++;
8693+ }
8694+ return ret;
8695+}
8696+
8697+/* count specific players in area */
8698+static int
8699+count_specific_player_in (int x, int y, enum usertype_t c_type)
8700+{
8701+ int ret = 0;
8702+ int by = y - 1;
8703+ int i;
8704+ x--;
8705+
8706+ for (i = 0; i < 3; i++)
8707+ {
8708+ int bx = x;
8709+ int j;
8710+ for (j = 0; j < 3; j++)
8711+ {
8712+ int n;
8713+ adjust_pos (&bx, &by);
8714+ n = MAP (bx, by)->player;
8715+ if (n && User[n - 1].cloak_count == 0 &&
8716+ User[n - 1].c_type == c_type)
8717+ {
8718+ ret++;
8719+ }
8720+ else if (MAP (bx, by)->id & MAP_THERE_NPC)
8721+ {
8722+ int npc = MAP (bx, by)->animal;
8723+ if (c_type == Hunter && Npc[npc].c_type == NpcHunter)
8724+ {
8725+ ret++;
8726+ }
8727+ else if (c_type == Observer && Npc[npc].c_type == NpcObserver)
8728+ {
8729+ ret++;
8730+ }
8731+ else if (Npc[npc].c_type == NpcHige &&
8732+ User[Npc[npc].owner_user].c_type == c_type)
8733+ {
8734+ ret++;
8735+ }
8736+ }
8737+
8738+ bx++;
8739+ }
8740+ by++;
8741+ }
8742+ return ret;
8743+}
8744+
8745+/* random move */
8746+static void
8747+random_move (int *px, int *py)
8748+{
8749+ static const int ck_x[4] = { 0, 1, 0, -1 };
8750+ static const int ck_y[4] = { -1, 0, 1, 0 };
8751+ int i;
8752+ int dx[4];
8753+ int dy[4];
8754+ int n = 0;
8755+ for (i = 0; i < 4; i++)
8756+ {
8757+ int wkx = *px + ck_x[i];
8758+ int wky = *py + ck_y[i];
8759+ adjust_pos (&wkx, &wky);
8760+ if (MAP (wkx, wky)->player)
8761+ {
8762+ /* uhmm. player in destnation point. */
8763+ continue;
8764+ }
8765+ if (MAP (wkx, wky)->id & MAP_NOT_MOVE)
8766+ {
8767+ /* uhmm. other animal. */
8768+ continue;
8769+ }
8770+ dx[n] = ck_x[i];
8771+ dy[n] = ck_y[i];
8772+ n++;
8773+ }
8774+ if (n)
8775+ {
8776+ int m = 0;
8777+ if (n > 1)
8778+ {
8779+ m = getrand (0, n - 1);
8780+ }
8781+ *px += dx[m];
8782+ *py += dy[m];
8783+ }
8784+ return;
8785+}
8786+
8787+/* check attack type */
8788+static int
8789+check_attacker (int nowner, int ntarget, enum target_type t_type)
8790+{
8791+ switch (t_type)
8792+ {
8793+ case TargetUser: