--- deliantra/server/common/map.c 2006/02/03 07:11:37 1.1.1.1 +++ deliantra/server/common/map.c 2006/04/01 15:39:58 1.10 @@ -40,6 +40,9 @@ extern int nrofallocobjects,nroffreeobjects; +void (*load_original_map_callback)(mapstruct *map); +void (*load_temporary_map_callback)(mapstruct *map); +void (*clean_temporary_map_callback)(mapstruct *map); /* * Returns the mapstruct which has a name matching the given argument. @@ -209,7 +212,7 @@ * necessary to make sure the information is in fact logged. */ -void dump_map(mapstruct *m) { +void dump_map(const mapstruct *m) { LOG(llevError,"Map %s status: %d.\n",m->path,m->in_memory); LOG(llevError,"Size: %dx%d Start: %d,%d\n", MAP_WIDTH(m), MAP_HEIGHT(m), @@ -218,6 +221,9 @@ if(m->msg!=NULL) LOG(llevError,"Message:\n%s",m->msg); + if(m->maplore!=NULL) + LOG(llevError,"Lore:\n%s",m->maplore); + if(m->tmpname!=NULL) LOG(llevError,"Tmpname: %s\n",m->tmpname); @@ -306,6 +312,14 @@ */ if (ob->type != PLAYER && ! (mflags & P_IS_ALIVE) && (blocked==0)) return 0; + /* if there isn't anytyhing alive on this space, and this space isn't + * otherwise blocked, we can return now. Only if there is a living + * creature do we need to investigate if it is part of this creature + * or another. Likewise, only if something is blocking us do we + * need to investigate if there is a special circumstance that would + * let the player through (inventory checkers for example) + */ + if (!(mflags & P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(ob, blocked)) return 0; if(ob->head != NULL) ob=ob->head; @@ -383,7 +397,7 @@ * against the move_block values. */ -int ob_blocked(object *ob,mapstruct *m,sint16 x,sint16 y) { +int ob_blocked(const object *ob,mapstruct *m,sint16 x,sint16 y) { archetype *tmp; int flag; mapstruct *m1; @@ -403,10 +417,16 @@ if (flag & P_OUT_OF_MAP) return P_OUT_OF_MAP; if (flag & P_IS_ALIVE) return P_IS_ALIVE; + /* find_first_free_spot() calls this function. However, often + * ob doesn't have any move type (when used to place exits) + * so the AND operation in OB_TYPE_MOVE_BLOCK doesn't work. + */ + + if (ob->move_type == 0 && GET_MAP_MOVE_BLOCK(m1, sx, sy) != MOVE_ALL) continue; + /* Note it is intentional that we check ob - the movement type of the * head of the object should correspond for the entire object. */ - if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m1, sx, sy))) return AB_NO_PASS; @@ -572,14 +592,12 @@ */ void save_objects (mapstruct *m, FILE *fp, FILE *fp2, int flag) { int i, j = 0,unique=0; - object *op, *otmp; + object *op; /* first pass - save one-part objects */ for(i = 0; i < MAP_WIDTH(m); i++) for (j = 0; j < MAP_HEIGHT(m); j++) { unique=0; - for(op = get_map_ob (m, i, j); op; op = otmp) { - otmp = op->above; - + for(op = get_map_ob (m, i, j); op; op = op->above) { if (QUERY_FLAG(op,FLAG_IS_FLOOR) && QUERY_FLAG(op, FLAG_UNIQUE)) unique=1; @@ -661,7 +679,7 @@ fatal(OUT_OF_MEMORY); } -/* Creatures and returns a map of the specific size. Used +/* Create and returns a map of the specific size. Used * in random map code and the editor. */ mapstruct *get_empty_map(int sizex, int sizey) { @@ -780,8 +798,9 @@ static int load_map_header(FILE *fp, mapstruct *m) { - char buf[HUGE_BUF], msgbuf[HUGE_BUF], *key=NULL, *value, *end; + char buf[HUGE_BUF], msgbuf[HUGE_BUF], maplorebuf[HUGE_BUF], *key=NULL, *value, *end; int msgpos=0; + int maplorepos=0; while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { buf[HUGE_BUF-1] = 0; @@ -846,6 +865,18 @@ if (msgpos != 0) m->msg = strdup_local(msgbuf); } + else if (!strcmp(key,"maplore")) { + while (fgets(buf, HUGE_BUF-1, fp)!=NULL) { + if (!strcmp(buf,"endmaplore\n")) break; + else { + /* slightly more efficient than strcat */ + strcpy(maplorebuf+maplorepos, buf); + maplorepos += strlen(buf); + } + } + if (maplorepos != 0) + m->maplore = strdup_local(maplorebuf); + } else if (!strcmp(key,"end")) { break; } @@ -1021,6 +1052,8 @@ if (!MAP_DIFFICULTY(m)) MAP_DIFFICULTY(m)=calculate_difficulty(m); set_map_reset_time(m); + if (load_original_map_callback) + load_original_map_callback(m); return (m); } @@ -1070,6 +1103,8 @@ load_objects (m, fp, 0); close_and_delete(fp, comp); m->in_memory=MAP_IN_MEMORY; + if (load_temporary_map_callback) + load_temporary_map_callback(m); return m; } @@ -1115,7 +1150,7 @@ /* This goes through map 'm' and removed any unique items on the map. */ static void delete_unique_items(mapstruct *m) { - int i,j,unique=0; + int i,j,unique; object *op, *next; for(i=0; ienter_x) fprintf(fp,"enter_x %d\n", m->enter_x); if (m->enter_y) fprintf(fp,"enter_y %d\n", m->enter_y); if (m->msg) fprintf(fp,"msg\n%sendmsg\n", m->msg); + if (m->maplore) fprintf(fp,"maplore\n%sendmaplore\n", m->maplore); if (m->unique) fprintf(fp,"unique %d\n", m->unique); if (m->template) fprintf(fp,"template %d\n", m->template); if (m->outdoor) fprintf(fp,"outdoor %d\n", m->outdoor); @@ -1397,6 +1433,7 @@ if (m->name) FREE_AND_CLEAR(m->name); if (m->spaces) FREE_AND_CLEAR(m->spaces); if (m->msg) FREE_AND_CLEAR(m->msg); + if (m->maplore) FREE_AND_CLEAR(m->maplore); if (m->shopitems) FREE_AND_CLEAR(m->shopitems); if (m->shoprace) FREE_AND_CLEAR(m->shoprace); if (m->buttons) @@ -1627,6 +1664,8 @@ void clean_tmp_map(mapstruct *m) { if(m->tmpname == NULL) return; + if (clean_temporary_map_callback) + clean_temporary_map_callback (m); (void) unlink(m->tmpname); } @@ -1664,9 +1703,9 @@ /* inform all players on the map */ if (change>0) - new_info_map(NDI_BLACK, m,"It becomes darker."); + new_info_map(NDI_BLACK|NDI_UNIQUE, m,"It becomes darker."); else - new_info_map(NDI_BLACK, m,"It becomes brighter."); + new_info_map(NDI_BLACK|NDI_UNIQUE, m,"It becomes brighter."); /* Do extra checking. since m->darkness is a unsigned value, * we need to be extra careful about negative values. @@ -1694,7 +1733,7 @@ uint8 flags = 0, oldflags, light=0, anywhere=0; New_Face *top,*floor, *middle; object *top_obj, *floor_obj, *middle_obj; - MoveType move_block=0, move_slow=0, move_on=0, move_off=0; + MoveType move_block=0, move_slow=0, move_on=0, move_off=0, move_allow=0; oldflags = GET_MAP_FLAGS(m,x,y); if (!(oldflags & P_NEED_UPDATE)) { @@ -1767,6 +1806,7 @@ move_block |= tmp->move_block; move_on |= tmp->move_on; move_off |= tmp->move_off; + move_allow |= tmp->move_allow; if (QUERY_FLAG(tmp,FLAG_ALIVE)) flags |= P_IS_ALIVE; @@ -1790,7 +1830,7 @@ (oldflags & ~P_NEED_UPDATE), flags); } SET_MAP_FLAGS(m, x, y, flags); - SET_MAP_MOVE_BLOCK(m, x, y, move_block); + SET_MAP_MOVE_BLOCK(m, x, y, move_block & ~move_allow); SET_MAP_MOVE_ON(m, x, y, move_on); SET_MAP_MOVE_OFF(m, x, y, move_off); SET_MAP_MOVE_SLOW(m, x, y, move_slow); @@ -1920,12 +1960,6 @@ */ if (!m) return 0; - /* Simple case - coordinates are within this local - * map. - */ - if ( x>=0 && x=0 && y < MAP_HEIGHT(m)) - return 0; - if (x<0) { if (!m->tile_path[3]) return 1; if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) { @@ -1954,7 +1988,11 @@ } return (out_of_map(m->tile_map[2], x, y - MAP_HEIGHT(m))); } - return 1; + + /* Simple case - coordinates are within this local + * map. + */ + return 0; } /* This is basically the same as out_of_map above, but @@ -1968,13 +2006,6 @@ mapstruct *get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y) { - /* Simple case - coordinates are within this local - * map. - */ - - if (*x>=0 && *x=0 && *y < MAP_HEIGHT(m)) - return m; - if (*x<0) { if (!m->tile_path[3]) return NULL; if (!m->tile_map[3] || m->tile_map[3]->in_memory != MAP_IN_MEMORY) @@ -2007,7 +2038,69 @@ *y -= MAP_HEIGHT(m); return (get_map_from_coord(m->tile_map[2], x, y)); } - return NULL; /* Shouldn't get here */ + + /* Simple case - coordinates are within this local + * map. + */ + + return m; +} + +/** + * Return whether map2 is adjacent to map1. If so, store the distance from + * map1 to map2 in dx/dy. + */ +static int adjacent_map(const mapstruct *map1, const mapstruct *map2, int *dx, int *dy) { + if (!map1 || !map2) + return 0; + + if (map1 == map2) { + *dx = 0; + *dy = 0; + + } else if (map1->tile_map[0] == map2) { /* up */ + *dx = 0; + *dy = -MAP_HEIGHT(map2); + } else if (map1->tile_map[1] == map2) { /* right */ + *dx = MAP_WIDTH(map1); + *dy = 0; + } else if (map1->tile_map[2] == map2) { /* down */ + *dx = 0; + *dy = MAP_HEIGHT(map1); + } else if (map1->tile_map[3] == map2) { /* left */ + *dx = -MAP_WIDTH(map2); + *dy = 0; + + } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[1] == map2) { /* up right */ + *dx = MAP_WIDTH(map1->tile_map[0]); + *dy = -MAP_HEIGHT(map1->tile_map[0]); + } else if (map1->tile_map[0] && map1->tile_map[0]->tile_map[3] == map2) { /* up left */ + *dx = -MAP_WIDTH(map2); + *dy = -MAP_HEIGHT(map1->tile_map[0]); + } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[0] == map2) { /* right up */ + *dx = MAP_WIDTH(map1); + *dy = -MAP_HEIGHT(map2); + } else if (map1->tile_map[1] && map1->tile_map[1]->tile_map[2] == map2) { /* right down */ + *dx = MAP_WIDTH(map1); + *dy = MAP_HEIGHT(map1->tile_map[1]); + } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[1] == map2) { /* down right */ + *dx = MAP_WIDTH(map1->tile_map[2]); + *dy = MAP_HEIGHT(map1); + } else if (map1->tile_map[2] && map1->tile_map[2]->tile_map[3] == map2) { /* down left */ + *dx = -MAP_WIDTH(map2); + *dy = MAP_HEIGHT(map1); + } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[0] == map2) { /* left up */ + *dx = -MAP_WIDTH(map1->tile_map[3]); + *dy = -MAP_HEIGHT(map2); + } else if (map1->tile_map[3] && map1->tile_map[3]->tile_map[2] == map2) { /* left down */ + *dx = -MAP_WIDTH(map1->tile_map[3]); + *dy = MAP_HEIGHT(map1->tile_map[3]); + + } else { /* not "adjacent" enough */ + return 0; + } + + return 1; } /* From map.c @@ -2031,62 +2124,50 @@ * closest body part of 'op1' */ -void get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) -{ - object *best; - - if (op1->map->tile_map[0] == op2->map) { - retval->distance_x = op2->x - op1->x; - retval->distance_y = -(op1->y +(MAP_HEIGHT(op2->map)- op2->y)); - - } - else if (op1->map->tile_map[1] == op2->map) { - retval->distance_y = op2->y - op1->y; - retval->distance_x = (MAP_WIDTH(op1->map) - op1->x) + op2->x; - } - else if (op1->map->tile_map[2] == op2->map) { - retval->distance_x = op2->x - op1->x; - retval->distance_y = (MAP_HEIGHT(op1->map) - op1->y) +op2->y; - - } - else if (op1->map->tile_map[3] == op2->map) { - retval->distance_y = op2->y - op1->y; - retval->distance_x = -(op1->x +(MAP_WIDTH(op2->map)- op2->x)); - } - else if (op1->map == op2->map) { - retval->distance_x = op2->x - op1->x; - retval->distance_y = op2->y - op1->y; +void get_rangevector(object *op1, object *op2, rv_vector *retval, int flags) { + if (!adjacent_map(op1->map, op2->map, &retval->distance_x, &retval->distance_y)) { + /* be conservative and fill in _some_ data */ + retval->distance = 100000; + retval->distance_x = 32767; + retval->distance_y = 32767; + retval->direction = 0; + retval->part = 0; + } else { + object *best; - } - best = op1; - /* If this is multipart, find the closest part now */ - if (!(flags & 0x1) && op1->more) { - object *tmp; - int best_distance = retval->distance_x * retval->distance_x + - retval->distance_y * retval->distance_y, tmpi; + retval->distance_x += op2->x-op1->x; + retval->distance_y += op2->y-op1->y; - /* we just tkae the offset of the piece to head to figure - * distance instead of doing all that work above again - * since the distance fields we set above are positive in the - * same axis as is used for multipart objects, the simply arithemetic - * below works. - */ - for (tmp=op1->more; tmp; tmp=tmp->more) { - tmpi = (op1->x - tmp->x + retval->distance_x) * (op1->x - tmp->x + retval->distance_x) + - (op1->y - tmp->y + retval->distance_y) * (op1->y - tmp->y + retval->distance_y); - if (tmpi < best_distance) { - best_distance = tmpi; - best = tmp; - } - } - if (best != op1) { - retval->distance_x += op1->x - best->x; - retval->distance_y += op1->y - best->y; - } + best = op1; + /* If this is multipart, find the closest part now */ + if (!(flags&0x1) && op1->more) { + object *tmp; + int best_distance = retval->distance_x*retval->distance_x+ + retval->distance_y*retval->distance_y, tmpi; + + /* we just take the offset of the piece to head to figure + * distance instead of doing all that work above again + * since the distance fields we set above are positive in the + * same axis as is used for multipart objects, the simply arithmetic + * below works. + */ + for (tmp = op1->more; tmp != NULL; tmp = tmp->more) { + tmpi = (op1->x-tmp->x+retval->distance_x)*(op1->x-tmp->x+retval->distance_x)+ + (op1->y-tmp->y+retval->distance_y)*(op1->y-tmp->y+retval->distance_y); + if (tmpi < best_distance) { + best_distance = tmpi; + best = tmp; + } + } + if (best != op1) { + retval->distance_x += op1->x-best->x; + retval->distance_y += op1->y-best->y; + } + } + retval->part = best; + retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y); + retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); } - retval->part = best; - retval->distance = isqrt(retval->distance_x*retval->distance_x + retval->distance_y*retval->distance_y); - retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); } /* this is basically the same as get_rangevector above, but instead of @@ -2100,34 +2181,22 @@ * field of the rv_vector is set to NULL. */ -void get_rangevector_from_mapcoord(mapstruct *m, int x, int y, object *op2, rv_vector *retval,int flags) -{ - if (m->tile_map[0] == op2->map) { - retval->distance_x = op2->x - x; - retval->distance_y = -(y +(MAP_HEIGHT(op2->map)- op2->y)); - - } - else if (m->tile_map[1] == op2->map) { - retval->distance_y = op2->y - y; - retval->distance_x = (MAP_WIDTH(m) - x) + op2->x; - } - else if (m->tile_map[2] == op2->map) { - retval->distance_x = op2->x - x; - retval->distance_y = (MAP_HEIGHT(m) - y) +op2->y; - - } - else if (m->tile_map[3] == op2->map) { - retval->distance_y = op2->y - y; - retval->distance_x = -(x +(MAP_WIDTH(op2->map)- op2->y)); - } - else if (m == op2->map) { - retval->distance_x = op2->x - x; - retval->distance_y = op2->y - y; +void get_rangevector_from_mapcoord(const mapstruct *m, int x, int y, const object *op2, rv_vector *retval, int flags) { + if (!adjacent_map(m, op2->map, &retval->distance_x, &retval->distance_y)) { + /* be conservative and fill in _some_ data */ + retval->distance = 100000; + retval->distance_x = 32767; + retval->distance_y = 32767; + retval->direction = 0; + retval->part = 0; + } else { + retval->distance_x += op2->x-x; + retval->distance_y += op2->y-y; + retval->part = NULL; + retval->distance = isqrt(retval->distance_x*retval->distance_x+retval->distance_y*retval->distance_y); + retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); } - retval->part = NULL; - retval->distance = isqrt(retval->distance_x*retval->distance_x + retval->distance_y*retval->distance_y); - retval->direction = find_dir_2(-retval->distance_x, -retval->distance_y); } /* Returns true of op1 and op2 are effectively on the same map @@ -2138,44 +2207,8 @@ * and efficient. This could probably be a macro. * MSW 2001-08-05 */ -int on_same_map(object *op1, object *op2) -{ - mapstruct *tmp; - - /* If the object isn't on a map, can't be on the same map, now can it? - * this check also prevents crashes below. - */ - if (op1->map == NULL || op2->map == NULL) return FALSE; - - /* on same map? */ - if (op1->map == op2->map) return TRUE; - - /* on adjacent map? */ - if (op1->map->tile_map[0] == op2->map) return TRUE; - if (op1->map->tile_map[1] == op2->map) return TRUE; - if (op1->map->tile_map[2] == op2->map) return TRUE; - if (op1->map->tile_map[3] == op2->map) return TRUE; - - /* on diagonally adjacent map? */ - tmp = op1->map->tile_map[0]; - if (tmp != NULL) { - if (tmp->tile_map[1] == op2->map || tmp->tile_map[3] == op2->map) return TRUE; - } - - tmp = op1->map->tile_map[1]; - if (tmp != NULL) { - if (tmp->tile_map[0] == op2->map || tmp->tile_map[2] == op2->map) return TRUE; - } - - tmp = op1->map->tile_map[2]; - if (tmp != NULL) { - if (tmp->tile_map[1] == op2->map || tmp->tile_map[3] == op2->map) return TRUE; - } - - tmp = op1->map->tile_map[3]; - if (tmp != NULL) { - if (tmp->tile_map[0] == op2->map || tmp->tile_map[2] == op2->map) return TRUE; - } +int on_same_map(const object *op1, const object *op2) { + int dx, dy; - return FALSE; + return adjacent_map(op1->map, op2->map, &dx, &dy); }