1 | /* |
1 | /* |
2 | * static char *rcsid_init_c = |
2 | * static char *rcsid_init_c = |
3 | * "$Id: request.C,v 1.1 2006/08/13 17:16:06 elmex Exp $"; |
3 | * "$Id: request.C,v 1.11 2006/08/29 07:34:01 root Exp $"; |
4 | */ |
4 | */ |
5 | |
5 | |
6 | /* |
6 | /* |
7 | CrossFire, A Multiplayer game for X-windows |
7 | CrossFire, A Multiplayer game for X-windows |
8 | |
8 | |
… | |
… | |
104 | -1, /* Internal */ |
104 | -1, /* Internal */ |
105 | -1, /* life stealing */ |
105 | -1, /* life stealing */ |
106 | -1 /* Disease - not fully done yet */ |
106 | -1 /* Disease - not fully done yet */ |
107 | }; |
107 | }; |
108 | |
108 | |
|
|
109 | static void |
|
|
110 | socket_map_scroll (NewSocket *ns, int dx, int dy) |
|
|
111 | { |
|
|
112 | struct Map newmap; |
|
|
113 | int x,y, mx, my; |
|
|
114 | |
|
|
115 | { |
|
|
116 | char buf[MAXSOCKBUF]; |
|
|
117 | |
|
|
118 | sprintf(buf,"map_scroll %d %d", dx, dy); |
|
|
119 | Write_String_To_Socket(ns, buf, strlen (buf)); |
|
|
120 | } |
|
|
121 | |
|
|
122 | /* If we are using the Map1aCmd, we may in fact send |
|
|
123 | * head information that is outside the viewable map. |
|
|
124 | * So set the mx,my to the max value we want to |
|
|
125 | * look for. Removed code to do so - it caused extra |
|
|
126 | * complexities for the client, and probably doesn't make |
|
|
127 | * that much difference in bandwidth. |
|
|
128 | */ |
|
|
129 | mx = ns->mapx; |
|
|
130 | my = ns->mapy; |
|
|
131 | |
|
|
132 | if (ns->mapmode == Map1aCmd) { |
|
|
133 | mx += MAX_HEAD_OFFSET; |
|
|
134 | my += MAX_HEAD_OFFSET; |
|
|
135 | } |
|
|
136 | |
|
|
137 | /* the x and y here are coordinates for the new map, i.e. if we moved |
|
|
138 | * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason, |
|
|
139 | * if the destination x or y coordinate is outside the viewable |
|
|
140 | * area, we clear the values - otherwise, the old values |
|
|
141 | * are preserved, and the check_head thinks it needs to clear them. |
|
|
142 | */ |
|
|
143 | for(x=0; x<mx; x++) { |
|
|
144 | for(y=0; y<my; y++) { |
|
|
145 | if(x >= ns->mapx || y >= ns->mapy) { |
|
|
146 | /* clear cells outside the viewable area */ |
|
|
147 | memset(&newmap.cells[x][y], 0, sizeof(struct MapCell)); |
|
|
148 | } |
|
|
149 | else if ((x+dx) < 0 || (x+dx) >= ns->mapx || (y+dy) < 0 || (y + dy) >= ns->mapy) { |
|
|
150 | /* clear newly visible tiles within the viewable area */ |
|
|
151 | memset(&(newmap.cells[x][y]), 0, sizeof(struct MapCell)); |
|
|
152 | } |
|
|
153 | else { |
|
|
154 | memcpy(&(newmap.cells[x][y]), |
|
|
155 | &(ns->lastmap.cells[x+dx][y+dy]),sizeof(struct MapCell)); |
|
|
156 | } |
|
|
157 | } |
|
|
158 | } |
|
|
159 | |
|
|
160 | memcpy(&(ns->lastmap), &newmap,sizeof(struct Map)); |
|
|
161 | |
|
|
162 | /* Make sure that the next "map1" command will be sent (even if it is |
|
|
163 | * empty). |
|
|
164 | */ |
|
|
165 | ns->sent_scroll = 1; |
|
|
166 | } |
|
|
167 | |
|
|
168 | static void |
|
|
169 | clear_map (player *pl) |
|
|
170 | { |
|
|
171 | NewSocket &socket = pl->socket; |
|
|
172 | |
|
|
173 | memset (&socket.lastmap, 0, sizeof (socket.lastmap)); |
|
|
174 | |
|
|
175 | if (socket.newmapcmd == 1) |
|
|
176 | Write_String_To_Socket (&socket, "newmap", 6); |
|
|
177 | |
|
|
178 | socket.update_look = 1; |
|
|
179 | socket.look_position = 0; |
|
|
180 | } |
|
|
181 | |
109 | /** check for map change and send new map data */ |
182 | /** check for map change and send new map data */ |
110 | static void |
183 | static void |
111 | check_map_change (player *pl) |
184 | check_map_change (player *pl) |
112 | { |
185 | { |
|
|
186 | NewSocket &socket = pl->socket; |
|
|
187 | object *ob = pl->ob; |
113 | char buf[MAX_BUF]; /* eauugggh */ |
188 | char buf[MAX_BUF]; /* eauugggh */ |
114 | |
189 | |
115 | object *ob = pl->ob; |
|
|
116 | |
|
|
117 | if (!pl->socket.mapinfocmd) |
|
|
118 | return; |
|
|
119 | |
|
|
120 | if (pl->socket.current_map != ob->map) |
190 | if (socket.current_map != ob->map) |
121 | { |
191 | { |
122 | pl->socket.current_map = ob->map; |
192 | socket.current_map = ob->map; |
123 | |
193 | |
124 | if (ob->map && ob->map->path [0]) |
194 | clear_map (pl); |
|
|
195 | |
|
|
196 | if (socket.mapinfocmd) |
125 | { |
197 | { |
|
|
198 | if (ob->map && ob->map->path [0]) |
|
|
199 | { |
126 | int flags = 0; |
200 | int flags = 0; |
127 | |
201 | |
128 | if (ob->map->tile_path [0]) flags |= 1; |
202 | if (ob->map->tile_path [0]) flags |= 1; |
129 | if (ob->map->tile_path [1]) flags |= 2; |
203 | if (ob->map->tile_path [1]) flags |= 2; |
130 | if (ob->map->tile_path [2]) flags |= 4; |
204 | if (ob->map->tile_path [2]) flags |= 4; |
131 | if (ob->map->tile_path [3]) flags |= 8; |
205 | if (ob->map->tile_path [3]) flags |= 8; |
132 | |
206 | |
133 | snprintf (buf, MAX_BUF, "mapinfo - spatial %d %d %d %d %d %s", |
207 | snprintf (buf, MAX_BUF, "mapinfo - spatial %d %d %d %d %d %s", |
134 | flags, pl->socket.mapx / 2 - ob->x, pl->socket.mapy / 2 - ob->y, |
208 | flags, socket.mapx / 2 - ob->x, socket.mapy / 2 - ob->y, |
135 | ob->map->width, ob->map->height, ob->map->path); |
209 | ob->map->width, ob->map->height, ob->map->path); |
|
|
210 | } |
|
|
211 | else |
|
|
212 | snprintf (buf, MAX_BUF, "mapinfo current"); |
|
|
213 | |
|
|
214 | Write_String_To_Socket (&socket, buf, strlen (buf)); |
|
|
215 | } |
|
|
216 | } |
|
|
217 | else if (socket.current_x != ob->x || socket.current_y != ob->y) |
|
|
218 | { |
|
|
219 | int dx = ob->x - socket.current_x; |
|
|
220 | int dy = ob->y - socket.current_y; |
|
|
221 | |
|
|
222 | if (socket.buggy_mapscroll && (abs (dx) > 8 || abs (dy) > 8)) |
|
|
223 | clear_map (pl); // current (<= 1.9.1) clients have unchecked buffer overflows |
|
|
224 | else |
|
|
225 | { |
|
|
226 | socket_map_scroll (&socket, ob->x - socket.current_x, ob->y - socket.current_y); |
|
|
227 | socket.update_look = 1; |
|
|
228 | socket.look_position = 0; |
136 | } |
229 | } |
137 | else |
|
|
138 | snprintf (buf, MAX_BUF, "mapinfo current"); |
|
|
139 | |
|
|
140 | Write_String_To_Socket (&pl->socket, buf, strlen (buf)); |
|
|
141 | } |
230 | } |
|
|
231 | |
|
|
232 | socket.current_x = ob->x; |
|
|
233 | socket.current_y = ob->y; |
142 | } |
234 | } |
143 | |
235 | |
144 | void ExtCmd (char *buf, int len, player *pl) |
236 | void ExtCmd (char *buf, int len, player *pl) |
145 | { |
237 | { |
146 | execute_global_event (EVENT_EXTCMD, pl, buf, len); |
238 | INVOKE_PLAYER (EXTCMD, pl, ARG_DATA (buf, len)); |
147 | } |
239 | } |
148 | |
240 | |
149 | void MapInfoCmd (char *buf, int len, player *pl) |
241 | void MapInfoCmd (char *buf, int len, player *pl) |
150 | { |
242 | { |
151 | // <mapinfo tag spatial tile-path |
243 | // <mapinfo tag spatial tile-path |
… | |
… | |
293 | ns->mapinfocmd = atoi(param); |
385 | ns->mapinfocmd = atoi(param); |
294 | safe_strcat(cmdback, "1", &slen, HUGE_BUF); |
386 | safe_strcat(cmdback, "1", &slen, HUGE_BUF); |
295 | } else if (!strcmp(cmd,"extcmd")) { |
387 | } else if (!strcmp(cmd,"extcmd")) { |
296 | ns->extcmd = atoi(param); |
388 | ns->extcmd = atoi(param); |
297 | safe_strcat(cmdback, "1", &slen, HUGE_BUF); |
389 | safe_strcat(cmdback, "1", &slen, HUGE_BUF); |
|
|
390 | } else if (!strcmp(cmd,"extmap")) { |
|
|
391 | ns->extmap = atoi(param); |
|
|
392 | safe_strcat(cmdback, "1", &slen, HUGE_BUF); |
298 | } else if (!strcmp(cmd,"facecache")) { |
393 | } else if (!strcmp(cmd,"facecache")) { |
299 | ns->facecache = atoi(param); |
394 | ns->facecache = atoi(param); |
300 | safe_strcat(cmdback, param, &slen, HUGE_BUF); |
395 | safe_strcat(cmdback, param, &slen, HUGE_BUF); |
301 | } else if (!strcmp(cmd,"faceset")) { |
396 | } else if (!strcmp(cmd,"faceset")) { |
302 | char tmpbuf[20]; |
397 | char tmpbuf[20]; |
… | |
… | |
745 | } |
840 | } |
746 | cp = strchr(cp+1, ' '); |
841 | cp = strchr(cp+1, ' '); |
747 | if (cp) { |
842 | if (cp) { |
748 | LOG(llevDebug,"CS: connection from client of type <%s>, ip %s\n", cp, ns->host); |
843 | LOG(llevDebug,"CS: connection from client of type <%s>, ip %s\n", cp, ns->host); |
749 | |
844 | |
|
|
845 | snprintf (ns->client, sizeof (ns->client), "%s", cp + 1); |
|
|
846 | |
750 | /* This is first implementation - i skip all beta DX clients with it |
847 | /* This is first implementation - i skip all beta DX clients with it |
751 | * Add later stuff here for other clients |
848 | * Add later stuff here for other clients |
752 | */ |
849 | */ |
753 | |
850 | |
754 | /* these are old dxclients */ |
851 | /* these are old dxclients */ |
… | |
… | |
787 | */ |
884 | */ |
788 | memset(&pl->socket.lastmap, 0, sizeof(struct Map)); |
885 | memset(&pl->socket.lastmap, 0, sizeof(struct Map)); |
789 | draw_client_map(pl->ob); |
886 | draw_client_map(pl->ob); |
790 | #endif |
887 | #endif |
791 | } |
888 | } |
792 | |
|
|
793 | /** Newmap command */ |
|
|
794 | void MapNewmapCmd( player *pl) |
|
|
795 | { |
|
|
796 | if( pl->socket.newmapcmd == 1) { |
|
|
797 | memset(&pl->socket.lastmap, 0, sizeof(pl->socket.lastmap)); |
|
|
798 | Write_String_To_Socket( &pl->socket, "newmap", 6); |
|
|
799 | } |
|
|
800 | pl->socket.current_map = 0; |
|
|
801 | } |
|
|
802 | |
|
|
803 | |
|
|
804 | |
889 | |
805 | /** |
890 | /** |
806 | * Moves an object (typically, container to inventory). |
891 | * Moves an object (typically, container to inventory). |
807 | * syntax is: move (to) (tag) (nrof) |
892 | * syntax is: move (to) (tag) (nrof) |
808 | */ |
893 | */ |
… | |
… | |
1202 | |
1287 | |
1203 | |
1288 | |
1204 | /** Clears a map cell */ |
1289 | /** Clears a map cell */ |
1205 | static void map_clearcell(struct MapCell *cell, int face0, int face1, int face2, int count) |
1290 | static void map_clearcell(struct MapCell *cell, int face0, int face1, int face2, int count) |
1206 | { |
1291 | { |
1207 | cell->count=count; |
|
|
1208 | cell->faces[0] = face0; |
1292 | cell->faces[0] = face0; |
1209 | cell->faces[1] = face1; |
1293 | cell->faces[1] = face1; |
1210 | cell->faces[2] = face2; |
1294 | cell->faces[2] = face2; |
|
|
1295 | cell->count = count; |
|
|
1296 | cell->stat_hp = 0; |
|
|
1297 | cell->player = 0; |
1211 | } |
1298 | } |
1212 | |
1299 | |
1213 | #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y) |
1300 | #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y) |
1214 | #define MAX_LAYERS 3 |
1301 | #define MAX_LAYERS 3 |
1215 | |
1302 | |
… | |
… | |
1240 | * basically, it only checks the that the head on space ax,ay at layer |
1327 | * basically, it only checks the that the head on space ax,ay at layer |
1241 | * needs to get sent - if so, it adds the data, sending the head |
1328 | * needs to get sent - if so, it adds the data, sending the head |
1242 | * if needed, and returning 1. If this no data needs to get |
1329 | * if needed, and returning 1. If this no data needs to get |
1243 | * sent, it returns zero. |
1330 | * sent, it returns zero. |
1244 | */ |
1331 | */ |
1245 | static inline int check_head(SockList *sl, NewSocket *ns, int ax, int ay, int layer) |
1332 | static int check_head (SockList &sl, NewSocket &ns, int ax, int ay, int layer) |
1246 | { |
1333 | { |
1247 | short face_num; |
1334 | short face_num; |
1248 | |
1335 | |
1249 | if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]) |
1336 | if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]) |
1250 | face_num = heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]->face->number; |
1337 | face_num = heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]->face->number; |
1251 | else |
1338 | else |
1252 | face_num = 0; |
1339 | face_num = 0; |
1253 | |
1340 | |
1254 | if (face_num != ns->lastmap.cells[ax][ay].faces[layer]) { |
1341 | if (face_num != ns.lastmap.cells[ax][ay].faces[layer]) { |
1255 | SockList_AddShort(sl, face_num); |
1342 | SockList_AddShort (&sl, face_num); |
1256 | if (face_num && !(ns->faces_sent[face_num] & NS_FACESENT_FACE)) |
1343 | if (face_num && !(ns.faces_sent[face_num] & NS_FACESENT_FACE)) |
1257 | esrv_send_face(ns, face_num, 0); |
1344 | esrv_send_face (&ns, face_num, 0); |
1258 | heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer] = NULL; |
1345 | heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer] = NULL; |
1259 | ns->lastmap.cells[ax][ay].faces[layer] = face_num; |
1346 | ns.lastmap.cells[ax][ay].faces[layer] = face_num; |
1260 | return 1; |
1347 | return 1; |
1261 | } |
1348 | } |
1262 | |
1349 | |
1263 | return 0; /* No change */ |
1350 | return 0; /* No change */ |
1264 | } |
1351 | } |
… | |
… | |
1281 | * the map command, where the faces stack up. Sinces that is no longer |
1368 | * the map command, where the faces stack up. Sinces that is no longer |
1282 | * the case, it seems to make more sense to have these layer values |
1369 | * the case, it seems to make more sense to have these layer values |
1283 | * actually match. |
1370 | * actually match. |
1284 | */ |
1371 | */ |
1285 | |
1372 | |
1286 | static inline int update_space(SockList *sl, NewSocket *ns, mapstruct *mp, int mx, int my, int sx, int sy, int layer) |
1373 | static int update_space(SockList *sl, NewSocket *ns, mapstruct *mp, int mx, int my, int sx, int sy, int layer) |
1287 | { |
1374 | { |
1288 | object *ob, *head; |
1375 | object *ob, *head; |
1289 | uint16 face_num; |
1376 | uint16 face_num; |
1290 | int bx, by,i; |
1377 | int bx, by,i; |
1291 | |
1378 | |
… | |
… | |
1560 | uint16 mask,emask; |
1647 | uint16 mask,emask; |
1561 | uint8 eentrysize; |
1648 | uint8 eentrysize; |
1562 | uint16 ewhatstart,ewhatflag; |
1649 | uint16 ewhatstart,ewhatflag; |
1563 | uint8 extendedinfos; |
1650 | uint8 extendedinfos; |
1564 | mapstruct *m; |
1651 | mapstruct *m; |
|
|
1652 | NewSocket &socket = pl->contr->socket; |
|
|
1653 | |
|
|
1654 | check_map_change (pl->contr); |
1565 | |
1655 | |
1566 | sl.buf=(unsigned char*)malloc(MAXSOCKBUF); |
1656 | sl.buf=(unsigned char*)malloc(MAXSOCKBUF); |
1567 | if (pl->contr->socket.mapmode == Map1Cmd) |
1657 | if (socket.mapmode == Map1Cmd) |
1568 | strcpy((char*)sl.buf,"map1 "); |
1658 | strcpy((char*)sl.buf,"map1 "); |
1569 | else |
1659 | else |
1570 | strcpy((char*)sl.buf,"map1a "); |
1660 | strcpy((char*)sl.buf,"map1a "); |
1571 | sl.len=strlen((char*)sl.buf); |
1661 | sl.len=strlen((char*)sl.buf); |
1572 | startlen = sl.len; |
1662 | startlen = sl.len; |
1573 | /*Extendedmapinfo structure initialisation*/ |
1663 | /*Extendedmapinfo structure initialisation*/ |
1574 | if (pl->contr->socket.ext_mapinfos){ |
1664 | if (socket.ext_mapinfos){ |
1575 | esl.buf=(unsigned char*)malloc(MAXSOCKBUF); |
1665 | esl.buf=(unsigned char*)malloc(MAXSOCKBUF); |
1576 | strcpy((char*)esl.buf,"mapextended "); |
1666 | strcpy((char*)esl.buf,"mapextended "); |
1577 | esl.len=strlen((char*)esl.buf); |
1667 | esl.len=strlen((char*)esl.buf); |
1578 | extendedinfos=EMI_NOREDRAW; |
1668 | extendedinfos=EMI_NOREDRAW; |
1579 | if (pl->contr->socket.EMI_smooth) |
1669 | if (socket.EMI_smooth) |
1580 | extendedinfos|=EMI_SMOOTH; |
1670 | extendedinfos|=EMI_SMOOTH; |
1581 | ewhatstart=esl.len; |
1671 | ewhatstart=esl.len; |
1582 | ewhatflag=extendedinfos; /*The EMI_NOREDRAW bit |
1672 | ewhatflag=extendedinfos; /*The EMI_NOREDRAW bit |
1583 | could need to be taken away*/ |
1673 | could need to be taken away*/ |
1584 | SockList_AddChar(&esl, extendedinfos); |
1674 | SockList_AddChar(&esl, extendedinfos); |
1585 | eentrysize=getExtendedMapInfoSize(&(pl->contr->socket)); |
1675 | eentrysize=getExtendedMapInfoSize(&socket); |
1586 | SockList_AddChar(&esl, eentrysize); |
1676 | SockList_AddChar(&esl, eentrysize); |
1587 | estartlen = esl.len; |
1677 | estartlen = esl.len; |
1588 | } else { |
1678 | } else { |
1589 | /* suppress compiler warnings */ |
1679 | /* suppress compiler warnings */ |
1590 | ewhatstart = 0; |
1680 | ewhatstart = 0; |
… | |
… | |
1600 | ay=0; |
1690 | ay=0; |
1601 | |
1691 | |
1602 | /* We could do this logic as conditionals in the if statement, |
1692 | /* We could do this logic as conditionals in the if statement, |
1603 | * but that started to get a bit messy to look at. |
1693 | * but that started to get a bit messy to look at. |
1604 | */ |
1694 | */ |
1605 | max_x = pl->x+(pl->contr->socket.mapx+1)/2; |
1695 | max_x = pl->x+(socket.mapx+1)/2; |
1606 | max_y = pl->y+(pl->contr->socket.mapy+1)/2; |
1696 | max_y = pl->y+(socket.mapy+1)/2; |
1607 | if (pl->contr->socket.mapmode == Map1aCmd) { |
1697 | if (socket.mapmode == Map1aCmd) { |
1608 | max_x += MAX_HEAD_OFFSET; |
1698 | max_x += MAX_HEAD_OFFSET; |
1609 | max_y += MAX_HEAD_OFFSET; |
1699 | max_y += MAX_HEAD_OFFSET; |
1610 | } |
1700 | } |
1611 | |
1701 | |
1612 | for(y=pl->y-pl->contr->socket.mapy/2; y<max_y; y++,ay++) { |
1702 | for(y=pl->y-socket.mapy/2; y<max_y; y++,ay++) { |
1613 | ax=0; |
1703 | ax=0; |
1614 | for(x=pl->x-pl->contr->socket.mapx/2;x<max_x;x++,ax++) { |
1704 | for(x=pl->x-socket.mapx/2;x<max_x;x++,ax++) { |
1615 | |
1705 | |
1616 | emask = mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; |
1706 | emask = mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; |
1617 | |
1707 | |
1618 | /* If this space is out of the normal viewable area, we only check |
1708 | /* If this space is out of the normal viewable area, we only check |
1619 | * the heads value ax or ay will only be greater than what |
1709 | * the heads value ax or ay will only be greater than what |
1620 | * the client wants if using the map1a command - this is because |
1710 | * the client wants if using the map1a command - this is because |
1621 | * if the map1a command is not used, max_x and max_y will be |
1711 | * if the map1a command is not used, max_x and max_y will be |
1622 | * set to lower values. |
1712 | * set to lower values. |
1623 | */ |
1713 | */ |
1624 | if (ax >= pl->contr->socket.mapx || ay >= pl->contr->socket.mapy) { |
1714 | if (ax >= socket.mapx || ay >= socket.mapy) { |
1625 | int i, got_one; |
1715 | int i, got_one; |
1626 | |
1716 | |
1627 | oldlen = sl.len; |
1717 | oldlen = sl.len; |
1628 | |
1718 | |
1629 | |
|
|
1630 | SockList_AddShort(&sl, mask); |
1719 | SockList_AddShort(&sl, mask); |
1631 | |
1720 | |
1632 | if (check_head(&sl, &pl->contr->socket, ax, ay, 2)) |
1721 | if (check_head (sl, socket, ax, ay, 2)) |
1633 | mask |= 0x4; |
1722 | mask |= 0x4; |
1634 | if (check_head(&sl, &pl->contr->socket, ax, ay, 1)) |
1723 | if (check_head (sl, socket, ax, ay, 1)) |
1635 | mask |= 0x2; |
1724 | mask |= 0x2; |
1636 | if (check_head(&sl, &pl->contr->socket, ax, ay, 0)) |
1725 | if (check_head (sl, socket, ax, ay, 0)) |
1637 | mask |= 0x1; |
1726 | mask |= 0x1; |
1638 | |
1727 | |
1639 | /* If all we are doing is sending 0 (blank) faces, we don't |
1728 | /* If all we are doing is sending 0 (blank) faces, we don't |
1640 | * actually need to send that - just the coordinates |
1729 | * actually need to send that - just the coordinates |
1641 | * with no faces tells the client to blank out the |
1730 | * with no faces tells the client to blank out the |
… | |
… | |
1647 | } |
1736 | } |
1648 | |
1737 | |
1649 | if (got_one && (mask & 0xf)) { |
1738 | if (got_one && (mask & 0xf)) { |
1650 | sl.buf[oldlen+1] = mask & 0xff; |
1739 | sl.buf[oldlen+1] = mask & 0xff; |
1651 | } else { /*either all faces blank, either no face at all*/ |
1740 | } else { /*either all faces blank, either no face at all*/ |
1652 | if (mask & 0xf) /*at least 1 face, we know it's blank, only send coordinates*/ |
1741 | if (mask & 0xf) /*at least 1 face, we know it's blank, only send coordinates*/ |
1653 | sl.len = oldlen + 2; |
1742 | sl.len = oldlen + 2; |
1654 | else |
1743 | else |
1655 | sl.len = oldlen; |
1744 | sl.len = oldlen; |
1656 | } |
1745 | } |
1657 | /*What concerns extendinfos, nothing to be done for now |
1746 | /*What concerns extendinfos, nothing to be done for now |
1658 | * (perhaps effects layer later) |
1747 | * (perhaps effects layer later) |
1659 | */ |
1748 | */ |
1660 | continue; /* don't do processing below */ |
1749 | continue; /* don't do processing below */ |
1661 | } |
1750 | } |
|
|
1751 | |
|
|
1752 | MapCell &lastcell = socket.lastmap.cells[ax][ay]; |
1662 | |
1753 | |
1663 | d = pl->contr->blocked_los[ax][ay]; |
1754 | d = pl->contr->blocked_los[ax][ay]; |
1664 | |
1755 | |
1665 | /* If the coordinates are not valid, or it is too dark to see, |
1756 | /* If the coordinates are not valid, or it is too dark to see, |
1666 | * we tell the client as such |
1757 | * we tell the client as such |
… | |
… | |
1671 | if (!m) { |
1762 | if (!m) { |
1672 | /* space is out of map. Update space and clear values |
1763 | /* space is out of map. Update space and clear values |
1673 | * if this hasn't already been done. If the space is out |
1764 | * if this hasn't already been done. If the space is out |
1674 | * of the map, it shouldn't have a head |
1765 | * of the map, it shouldn't have a head |
1675 | */ |
1766 | */ |
1676 | if (pl->contr->socket.lastmap.cells[ax][ay].count != -1) { |
1767 | if (lastcell.count != -1) { |
1677 | SockList_AddShort(&sl, mask); |
1768 | SockList_AddShort(&sl, mask); |
1678 | map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay],0,0,0,-1); |
1769 | map_clearcell(&lastcell,0,0,0,-1); |
1679 | } |
1770 | } |
1680 | } else if (d>3) { |
1771 | } else if (d>3) { |
1681 | int need_send=0, count; |
1772 | int need_send=0, count; |
1682 | /* This block deals with spaces that are not visible for whatever |
1773 | /* This block deals with spaces that are not visible for whatever |
1683 | * reason. Still may need to send the head for this space. |
1774 | * reason. Still may need to send the head for this space. |
1684 | */ |
1775 | */ |
1685 | |
1776 | |
1686 | oldlen = sl.len; |
1777 | oldlen = sl.len; |
1687 | #if 0 |
1778 | |
1688 | /* First thing we do is blank out this space (clear it) |
|
|
1689 | * if not already done. If the client is using darkness, and |
|
|
1690 | * this space is at the edge, we also include the darkness. |
|
|
1691 | */ |
|
|
1692 | if (d==4) { |
|
|
1693 | if (pl->contr->socket.darkness && pl->contr->socket.lastmap.cells[ax][ay].count != d) { |
|
|
1694 | mask |= 8; |
|
|
1695 | SockList_AddShort(&sl, mask); |
|
|
1696 | SockList_AddChar(&sl, 0); |
|
|
1697 | } |
|
|
1698 | count = d; |
|
|
1699 | } else |
|
|
1700 | #endif |
|
|
1701 | { |
|
|
1702 | SockList_AddShort(&sl, mask); |
1779 | SockList_AddShort(&sl, mask); |
1703 | if (pl->contr->socket.lastmap.cells[ax][ay].count != -1) need_send=1; |
1780 | if (lastcell.count != -1) need_send=1; |
1704 | count = -1; |
1781 | count = -1; |
1705 | } |
|
|
1706 | |
1782 | |
1707 | if (pl->contr->socket.mapmode == Map1aCmd && have_head(ax, ay)) { |
1783 | if (socket.mapmode == Map1aCmd && have_head(ax, ay)) { |
1708 | /* Now check to see if any heads need to be sent */ |
1784 | /* Now check to see if any heads need to be sent */ |
1709 | |
1785 | |
1710 | if (check_head(&sl, &pl->contr->socket, ax, ay, 2)) |
1786 | if (check_head (sl, socket, ax, ay, 2)) |
1711 | mask |= 0x4; |
1787 | mask |= 0x4; |
1712 | if (check_head(&sl, &pl->contr->socket, ax, ay, 1)) |
1788 | if (check_head (sl, socket, ax, ay, 1)) |
1713 | mask |= 0x2; |
1789 | mask |= 0x2; |
1714 | if (check_head(&sl, &pl->contr->socket, ax, ay, 0)) |
1790 | if (check_head (sl, socket, ax, ay, 0)) |
1715 | mask |= 0x1; |
1791 | mask |= 0x1; |
1716 | pl->contr->socket.lastmap.cells[ax][ay].count = count; |
1792 | |
|
|
1793 | lastcell.count = count; |
1717 | |
1794 | |
1718 | } else { |
1795 | } else { |
1719 | struct MapCell *cell = &pl->contr->socket.lastmap.cells[ax][ay]; |
1796 | struct MapCell *cell = &lastcell; |
1720 | /* properly clear a previously sent big face */ |
1797 | /* properly clear a previously sent big face */ |
1721 | if(cell->faces[0] != 0 |
1798 | if(cell->faces[0] != 0 |
1722 | || cell->faces[1] != 0 |
1799 | || cell->faces[1] != 0 |
1723 | || cell->faces[2] != 0) |
1800 | || cell->faces[2] != 0) |
1724 | need_send = 1; |
1801 | need_send = 1; |
1725 | map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0, 0, count); |
1802 | map_clearcell(&lastcell, 0, 0, 0, count); |
1726 | } |
1803 | } |
1727 | |
1804 | |
1728 | if ((mask & 0xf) || need_send) { |
1805 | if ((mask & 0xf) || need_send) { |
1729 | sl.buf[oldlen+1] = mask & 0xff; |
1806 | sl.buf[oldlen+1] = mask & 0xff; |
1730 | } else { |
1807 | } else { |
… | |
… | |
1749 | mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; |
1826 | mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; |
1750 | eoldlen = esl.len; |
1827 | eoldlen = esl.len; |
1751 | emask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; |
1828 | emask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; |
1752 | SockList_AddShort(&sl, mask); |
1829 | SockList_AddShort(&sl, mask); |
1753 | |
1830 | |
1754 | if (pl->contr->socket.ext_mapinfos) |
1831 | if (socket.ext_mapinfos) |
1755 | SockList_AddShort(&esl, emask); |
1832 | SockList_AddShort(&esl, emask); |
1756 | |
1833 | |
|
|
1834 | unsigned char dummy; |
|
|
1835 | unsigned char *last_ext = &dummy; |
|
|
1836 | |
1757 | /* Darkness changed */ |
1837 | /* Darkness changed */ |
1758 | if (pl->contr->socket.lastmap.cells[ax][ay].count != d && pl->contr->socket.darkness) { |
1838 | if (lastcell.count != d && socket.darkness) { |
1759 | pl->contr->socket.lastmap.cells[ax][ay].count = d; |
1839 | mask |= 0x8; |
1760 | mask |= 0x8; /* darkness bit */ |
|
|
1761 | |
1840 | |
1762 | /* Protocol defines 255 full bright, 0 full dark. |
1841 | if (socket.extmap) |
1763 | * We currently don't have that many darkness ranges, |
1842 | { |
1764 | * so we current what limited values we do have. |
1843 | *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, d); |
1765 | */ |
1844 | } |
1766 | if (d==0) SockList_AddChar(&sl, 255); |
1845 | else |
1767 | else if (d==1) SockList_AddChar(&sl, 191); |
1846 | SockList_AddChar (&sl, 255 - 64 * d); |
1768 | else if (d==2) SockList_AddChar(&sl, 127); |
|
|
1769 | else if (d==3) SockList_AddChar(&sl, 63); |
|
|
1770 | } |
1847 | } |
1771 | else { |
1848 | |
1772 | /* need to reset from -1 so that if it does become blocked again, |
1849 | lastcell.count = d; |
1773 | * the code that deals with that can detect that it needs to tell |
1850 | |
1774 | * the client that this space is now blocked. |
1851 | if (socket.extmap) |
1775 | */ |
1852 | { |
1776 | pl->contr->socket.lastmap.cells[ax][ay].count = d; |
1853 | uint8 stat_hp = 0; |
1777 | } |
1854 | uint8 stat_width = 0; |
|
|
1855 | tag_t player = 0; |
|
|
1856 | |
|
|
1857 | // send hp information, if applicable |
|
|
1858 | if (object *op = GET_MAP_FACE_OBJ (m, nx, ny, 0)) |
|
|
1859 | { |
|
|
1860 | if (op->head || op->invisible) |
|
|
1861 | ; // do not show |
|
|
1862 | else if (op->type == PLAYER |
|
|
1863 | || QUERY_FLAG (op, FLAG_MONSTER) |
|
|
1864 | || QUERY_FLAG (op, FLAG_ALIVE) |
|
|
1865 | || QUERY_FLAG (op, FLAG_GENERATOR)) |
|
|
1866 | { |
|
|
1867 | if (op->stats.maxhp > 0 |
|
|
1868 | && (unsigned)op->stats.maxhp > (unsigned)op->stats.hp) |
|
|
1869 | { |
|
|
1870 | stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp; |
|
|
1871 | stat_width = op->arch->tail_x; |
|
|
1872 | } |
|
|
1873 | } |
|
|
1874 | |
|
|
1875 | if (op->type == PLAYER && op != pl) |
|
|
1876 | player = op->count; |
|
|
1877 | } |
|
|
1878 | |
|
|
1879 | if (lastcell.stat_hp != stat_hp && 0) |
|
|
1880 | { |
|
|
1881 | lastcell.stat_hp = stat_hp; |
|
|
1882 | |
|
|
1883 | mask |= 0x8; |
|
|
1884 | *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, 5); |
|
|
1885 | SockList_AddChar (&sl, stat_hp); |
|
|
1886 | |
|
|
1887 | if (stat_width > 1) |
|
|
1888 | { |
|
|
1889 | *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, 6); |
|
|
1890 | SockList_AddChar (&sl, stat_width); |
|
|
1891 | } |
|
|
1892 | } |
|
|
1893 | |
|
|
1894 | if (lastcell.player != player && 0) |
|
|
1895 | { |
|
|
1896 | lastcell.player = player; |
|
|
1897 | mask |= 0x8; |
|
|
1898 | *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, 0x47); |
|
|
1899 | SockList_AddChar (&sl, 4); |
|
|
1900 | SockList_AddInt (&sl, player); |
|
|
1901 | } |
|
|
1902 | } |
1778 | |
1903 | |
1779 | /* Floor face */ |
1904 | /* Floor face */ |
1780 | if (update_space(&sl, &pl->contr->socket, m, nx, ny, ax, ay, 2)) |
1905 | if (update_space(&sl, &socket, m, nx, ny, ax, ay, 2)) |
1781 | mask |= 0x4; |
1906 | mask |= 0x4; |
1782 | |
1907 | |
1783 | if (pl->contr->socket.EMI_smooth) |
1908 | if (socket.EMI_smooth) |
1784 | if (update_smooth(&esl, &pl->contr->socket, m, nx, ny, ax, ay, 2)){ |
1909 | if (update_smooth(&esl, &socket, m, nx, ny, ax, ay, 2)) |
1785 | emask |= 0x4; |
1910 | emask |= 0x4; |
1786 | } |
|
|
1787 | |
1911 | |
1788 | /* Middle face */ |
1912 | /* Middle face */ |
1789 | if (update_space(&sl, &pl->contr->socket, m, nx, ny, ax, ay, 1)) |
1913 | if (update_space(&sl, &socket, m, nx, ny, ax, ay, 1)) |
1790 | mask |= 0x2; |
1914 | mask |= 0x2; |
1791 | |
1915 | |
1792 | if (pl->contr->socket.EMI_smooth) |
1916 | if (socket.EMI_smooth) |
1793 | if (update_smooth(&esl, &pl->contr->socket, m, nx, ny, ax, ay, 1)){ |
1917 | if (update_smooth(&esl, &socket, m, nx, ny, ax, ay, 1)) |
1794 | emask |= 0x2; |
1918 | emask |= 0x2; |
1795 | } |
|
|
1796 | |
|
|
1797 | |
1919 | |
1798 | if(nx == pl->x && ny == pl->y && pl->invisible & (pl->invisible < 50 ? 4 : 1)) { |
1920 | if(nx == pl->x && ny == pl->y && pl->invisible & (pl->invisible < 50 ? 4 : 1)) { |
1799 | if (pl->contr->socket.lastmap.cells[ax][ay].faces[0] != pl->face->number) { |
1921 | if (lastcell.faces[0] != pl->face->number) { |
1800 | pl->contr->socket.lastmap.cells[ax][ay].faces[0] = pl->face->number; |
1922 | lastcell.faces[0] = pl->face->number; |
1801 | mask |= 0x1; |
1923 | mask |= 0x1; |
1802 | if (!(pl->contr->socket.faces_sent[pl->face->number] &NS_FACESENT_FACE)) |
1924 | if (!(socket.faces_sent[pl->face->number] &NS_FACESENT_FACE)) |
1803 | esrv_send_face(&pl->contr->socket, pl->face->number, 0); |
1925 | esrv_send_face(&socket, pl->face->number, 0); |
1804 | SockList_AddShort(&sl, pl->face->number); |
1926 | SockList_AddShort(&sl, pl->face->number); |
1805 | } |
1927 | } |
1806 | } |
1928 | } |
1807 | /* Top face */ |
1929 | /* Top face */ |
1808 | else { |
1930 | else { |
1809 | if (update_space(&sl, &pl->contr->socket, m, nx, ny, ax, ay, 0)) |
1931 | if (update_space(&sl, &socket, m, nx, ny, ax, ay, 0)) |
1810 | mask |= 0x1; |
1932 | mask |= 0x1; |
1811 | if (pl->contr->socket.EMI_smooth) |
1933 | if (socket.EMI_smooth) |
1812 | if (update_smooth(&esl, &pl->contr->socket, m, nx, ny, ax, ay, 0)){ |
1934 | if (update_smooth(&esl, &socket, m, nx, ny, ax, ay, 0)){ |
1813 | emask |= 0x1; |
1935 | emask |= 0x1; |
1814 | } |
1936 | } |
1815 | } |
1937 | } |
1816 | /* Check to see if we are in fact sending anything for this |
1938 | /* Check to see if we are in fact sending anything for this |
1817 | * space by checking the mask. If so, update the mask. |
1939 | * space by checking the mask. If so, update the mask. |
… | |
… | |
1831 | } /* else this is a viewable space */ |
1953 | } /* else this is a viewable space */ |
1832 | } /* for x loop */ |
1954 | } /* for x loop */ |
1833 | } /* for y loop */ |
1955 | } /* for y loop */ |
1834 | |
1956 | |
1835 | /* Verify that we in fact do need to send this */ |
1957 | /* Verify that we in fact do need to send this */ |
1836 | if (pl->contr->socket.ext_mapinfos){ |
1958 | if (socket.ext_mapinfos){ |
1837 | if (!(sl.len>startlen || pl->contr->socket.sent_scroll)){ |
1959 | if (!(sl.len>startlen || socket.sent_scroll)){ |
1838 | /* No map data will follow, so don't say the client |
1960 | /* No map data will follow, so don't say the client |
1839 | * it doesn't need draw! |
1961 | * it doesn't need draw! |
1840 | */ |
1962 | */ |
1841 | ewhatflag&=(~EMI_NOREDRAW); |
1963 | ewhatflag&=(~EMI_NOREDRAW); |
1842 | esl.buf[ewhatstart+1] = ewhatflag & 0xff; |
1964 | esl.buf[ewhatstart+1] = ewhatflag & 0xff; |
1843 | } |
1965 | } |
1844 | if (esl.len>estartlen) { |
1966 | if (esl.len>estartlen) { |
1845 | Send_With_Handling(&pl->contr->socket, &esl); |
1967 | Send_With_Handling(&socket, &esl); |
1846 | } |
1968 | } |
1847 | free(esl.buf); |
1969 | free(esl.buf); |
1848 | } |
1970 | } |
1849 | if (sl.len>startlen || pl->contr->socket.sent_scroll) { |
1971 | if (sl.len>startlen || socket.sent_scroll) { |
1850 | Send_With_Handling(&pl->contr->socket, &sl); |
1972 | Send_With_Handling(&socket, &sl); |
1851 | pl->contr->socket.sent_scroll = 0; |
1973 | socket.sent_scroll = 0; |
1852 | } |
1974 | } |
1853 | free(sl.buf); |
1975 | free(sl.buf); |
1854 | |
|
|
1855 | check_map_change (pl->contr); |
|
|
1856 | } |
1976 | } |
1857 | |
1977 | |
1858 | /** |
1978 | /** |
1859 | * Draws client map. |
1979 | * Draws client map. |
1860 | */ |
1980 | */ |
… | |
… | |
1871 | if (pl->type != PLAYER) { |
1991 | if (pl->type != PLAYER) { |
1872 | LOG(llevError,"draw_client_map called with non player/non eric-server\n"); |
1992 | LOG(llevError,"draw_client_map called with non player/non eric-server\n"); |
1873 | return; |
1993 | return; |
1874 | } |
1994 | } |
1875 | |
1995 | |
1876 | if (pl->contr->transport) { |
|
|
1877 | pm = pl->contr->transport->map; |
|
|
1878 | } |
|
|
1879 | else |
|
|
1880 | pm = pl->map; |
1996 | pm = pl->map; |
1881 | |
1997 | |
1882 | /* If player is just joining the game, he isn't here yet, so the map |
1998 | /* If player is just joining the game, he isn't here yet, so the map |
1883 | * can get swapped out. If so, don't try to send them a map. All will |
1999 | * can get swapped out. If so, don't try to send them a map. All will |
1884 | * be OK once they really log in. |
2000 | * be OK once they really log in. |
1885 | */ |
2001 | */ |
… | |
… | |
1977 | esrv_map_doneredraw(&pl->contr->socket, &newmap); |
2093 | esrv_map_doneredraw(&pl->contr->socket, &newmap); |
1978 | |
2094 | |
1979 | check_map_change (pl->contr); |
2095 | check_map_change (pl->contr); |
1980 | } |
2096 | } |
1981 | |
2097 | |
1982 | |
|
|
1983 | void esrv_map_scroll(NewSocket *ns,int dx,int dy) |
|
|
1984 | { |
|
|
1985 | struct Map newmap; |
|
|
1986 | int x,y, mx, my; |
|
|
1987 | char buf[MAXSOCKBUF]; |
|
|
1988 | |
|
|
1989 | sprintf(buf,"map_scroll %d %d", dx, dy); |
|
|
1990 | Write_String_To_Socket(ns, buf, strlen(buf)); |
|
|
1991 | |
|
|
1992 | /* If we are using the Map1aCmd, we may in fact send |
|
|
1993 | * head information that is outside the viewable map. |
|
|
1994 | * So set the mx,my to the max value we want to |
|
|
1995 | * look for. Removed code to do so - it caused extra |
|
|
1996 | * complexities for the client, and probably doesn't make |
|
|
1997 | * that much difference in bandwidth. |
|
|
1998 | */ |
|
|
1999 | mx = ns->mapx; |
|
|
2000 | my = ns->mapy; |
|
|
2001 | |
|
|
2002 | if (ns->mapmode == Map1aCmd) { |
|
|
2003 | mx += MAX_HEAD_OFFSET; |
|
|
2004 | my += MAX_HEAD_OFFSET; |
|
|
2005 | } |
|
|
2006 | |
|
|
2007 | /* the x and y here are coordinates for the new map, i.e. if we moved |
|
|
2008 | * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason, |
|
|
2009 | * if the destination x or y coordinate is outside the viewable |
|
|
2010 | * area, we clear the values - otherwise, the old values |
|
|
2011 | * are preserved, and the check_head thinks it needs to clear them. |
|
|
2012 | */ |
|
|
2013 | for(x=0; x<mx; x++) { |
|
|
2014 | for(y=0; y<my; y++) { |
|
|
2015 | if(x >= ns->mapx || y >= ns->mapy) { |
|
|
2016 | /* clear cells outside the viewable area */ |
|
|
2017 | memset(&newmap.cells[x][y], 0, sizeof(struct MapCell)); |
|
|
2018 | } |
|
|
2019 | else if ((x+dx) < 0 || (x+dx) >= ns->mapx || (y+dy) < 0 || (y + dy) >= ns->mapy) { |
|
|
2020 | /* clear newly visible tiles within the viewable area */ |
|
|
2021 | memset(&(newmap.cells[x][y]), 0, sizeof(struct MapCell)); |
|
|
2022 | } |
|
|
2023 | else { |
|
|
2024 | memcpy(&(newmap.cells[x][y]), |
|
|
2025 | &(ns->lastmap.cells[x+dx][y+dy]),sizeof(struct MapCell)); |
|
|
2026 | } |
|
|
2027 | } |
|
|
2028 | } |
|
|
2029 | |
|
|
2030 | memcpy(&(ns->lastmap), &newmap,sizeof(struct Map)); |
|
|
2031 | |
|
|
2032 | /* Make sure that the next "map1" command will be sent (even if it is |
|
|
2033 | * empty). |
|
|
2034 | */ |
|
|
2035 | ns->sent_scroll = 1; |
|
|
2036 | } |
|
|
2037 | |
2098 | |
2038 | /*****************************************************************************/ |
2099 | /*****************************************************************************/ |
2039 | /* GROS: The following one is used to allow a plugin to send a generic cmd to*/ |
2100 | /* GROS: The following one is used to allow a plugin to send a generic cmd to*/ |
2040 | /* a player. Of course, the client need to know the command to be able to */ |
2101 | /* a player. Of course, the client need to know the command to be able to */ |
2041 | /* manage it ! */ |
2102 | /* manage it ! */ |