version 1.2 | | version 1.3 |
---|
| | |
/* | | /* |
* static char *rcsid_build_map = | | * static char *rcsid_build_map = |
* "$Id: build_map.c,v 1.2 2004/01/19 21:12:30 ryo_saeba Exp $"; | | * "$Id: build_map.c,v 1.3 2004/05/16 08:42:51 ryo_saeba Exp $"; |
*/ | | */ |
/* | | /* |
CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
* If found, returns the connection value associated | | * If found, returns the connection value associated |
* else searches a new connection value, and adds the force to the player. | | * else searches a new connection value, and adds the force to the player. |
*/ | | */ |
int find_or_create_connection_for_map( object* player, short x, short y ) | | int find_or_create_connection_for_map( object* pl, short x, short y ) |
{ | | { |
object* rune; | | object* rune; |
object* force; | | object* force; |
int connected; | | int connected; |
| | |
rune = GET_MAP_OB( player->map, x, y ); | | rune = GET_MAP_OB( pl->map, x, y ); |
while ( rune && ( ( rune->type != SIGN ) || ( strcmp( rune->arch->name, "rune_mark" ) ) ) ) | | while ( rune && ( ( rune->type != SIGN ) || ( strcmp( rune->arch->name, "rune_mark" ) ) ) ) |
rune = rune->above; | | rune = rune->above; |
| | |
if ( !rune ) | | if ( !rune ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "You need to put a marking rune with the group name." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You need to put a marking rune with the group name." ); |
return -1; | | return -1; |
} | | } |
| | |
/* Now, find force in player's inventory */ | | /* Now, find force in player's inventory */ |
force = player->inv; | | force = pl->inv; |
while ( force && ( ( force->type != FORCE ) || ( !force->slaying ) || ( strcmp( force->slaying, player->map->path ) ) || ( !force->msg ) || ( strcmp( force->msg, rune->msg ) ) ) ) | | while ( force && ( ( force->type != FORCE ) || ( !force->slaying ) || ( strcmp( force->slaying, pl->map->path ) ) || ( !force->msg ) || ( strcmp( force->msg, rune->msg ) ) ) ) |
force = force->below; | | force = force->below; |
| | |
if ( !force ) | | if ( !force ) |
/* No force, need to create & insert one */ | | /* No force, need to create & insert one */ |
{ | | { |
/* Find unused value */ | | /* Find unused value */ |
connected = find_unused_connected_value( player->map ); | | connected = find_unused_connected_value( pl->map ); |
if ( connected == -1 ) | | if ( connected == -1 ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "Could not create more groups." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Could not create more groups." ); |
return -1; | | return -1; |
} | | } |
| | |
force = get_archetype( "force" ); | | force = get_archetype( "force" ); |
force->speed = 0; | | force->speed = 0; |
update_ob_speed( force ); | | update_ob_speed( force ); |
force->slaying = add_string( player->map->path ); | | force->slaying = add_string( pl->map->path ); |
force->msg = add_string( rune->msg ); | | force->msg = add_string( rune->msg ); |
force->path_attuned = connected; | | force->path_attuned = connected; |
insert_ob_in_ob( force, player ); | | insert_ob_in_ob( force, pl ); |
| | |
return connected; | | return connected; |
} | | } |
| | |
* Note: this function will inconditionally change squares around (x, y) | | * Note: this function will inconditionally change squares around (x, y) |
* so don't call it with x == 0 for instance! | | * so don't call it with x == 0 for instance! |
*/ | | */ |
void apply_builder_floor(object* player, object* material, short x, short y ) | | void apply_builder_floor(object* pl, object* material, short x, short y ) |
{ | | { |
object* tmp, *above; | | object* tmp, *above; |
object* above_floor; /* Item above floor, if any */ | | object* above_floor; /* Item above floor, if any */ |
| | |
above_floor = NULL; | | above_floor = NULL; |
new_wall = NULL; | | new_wall = NULL; |
floor_removed = 0; | | floor_removed = 0; |
tmp = GET_MAP_OB( player->map, x, y ); | | tmp = GET_MAP_OB( pl->map, x, y ); |
if ( tmp ) | | if ( tmp ) |
{ | | { |
while ( tmp ) | | while ( tmp ) |
| | |
SET_FLAG( tmp, FLAG_IS_BUILDABLE ); | | SET_FLAG( tmp, FLAG_IS_BUILDABLE ); |
SET_FLAG( tmp, FLAG_UNIQUE ); | | SET_FLAG( tmp, FLAG_UNIQUE ); |
tmp->type = FLOOR; | | tmp->type = FLOOR; |
insert_ob_in_map_at( tmp, player->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y ); | | insert_ob_in_map_at( tmp, pl->map, above_floor, above_floor ? INS_BELOW_ORIGINATOR : INS_ON_TOP, x, y ); |
| | |
/* | | /* |
* Next step: make sure there are either walls or floors around the new square | | * Next step: make sure there are either walls or floors around the new square |
| | |
{ | | { |
xt = x + freearr_x[ i ]; | | xt = x + freearr_x[ i ]; |
yt = y + freearr_y[ i ]; | | yt = y + freearr_y[ i ]; |
tmp = GET_MAP_OB( player->map, xt, yt ); | | tmp = GET_MAP_OB( pl->map, xt, yt ); |
if ( !tmp ) | | if ( !tmp ) |
{ | | { |
/* Must insert floor & wall */ | | /* Must insert floor & wall */ |
| | |
SET_FLAG( tmp, FLAG_UNIQUE ); | | SET_FLAG( tmp, FLAG_UNIQUE ); |
SET_FLAG( tmp, FLAG_IS_BUILDABLE ); | | SET_FLAG( tmp, FLAG_IS_BUILDABLE ); |
tmp->type = FLOOR; | | tmp->type = FLOOR; |
insert_ob_in_map_at( tmp, player->map, 0, 0, xt, yt ); | | insert_ob_in_map_at( tmp, pl->map, 0, 0, xt, yt ); |
/* Insert wall if exists. Note: if it doesn't, the map is weird... */ | | /* Insert wall if exists. Note: if it doesn't, the map is weird... */ |
if ( new_wall ) | | if ( new_wall ) |
{ | | { |
tmp = arch_to_object( new_wall ); | | tmp = arch_to_object( new_wall ); |
SET_FLAG( tmp, FLAG_IS_BUILDABLE ); | | SET_FLAG( tmp, FLAG_IS_BUILDABLE ); |
tmp->type = WALL; | | tmp->type = WALL; |
insert_ob_in_map_at( tmp, player->map, 0, 0, xt, yt ); | | insert_ob_in_map_at( tmp, pl->map, 0, 0, xt, yt ); |
} | | } |
} | | } |
} | | } |
| | |
for ( xt = x - 2; xt <= x + 2; xt++ ) | | for ( xt = x - 2; xt <= x + 2; xt++ ) |
for ( yt = y - 2; yt <= y + 2; yt++ ) | | for ( yt = y - 2; yt <= y + 2; yt++ ) |
{ | | { |
if ( !OUT_OF_REAL_MAP( player->map, xt, yt ) ) | | if ( !OUT_OF_REAL_MAP( pl->map, xt, yt ) ) |
fix_walls( player->map, xt, yt ); | | fix_walls( pl->map, xt, yt ); |
} | | } |
| | |
/* Now remove raw item from inventory */ | | /* Now remove raw item from inventory */ |
decrease_ob( material ); | | decrease_ob( material ); |
| | |
/* And tell player about the fix */ | | /* And tell player about the fix */ |
new_draw_info( NDI_UNIQUE, 0, player, message ); | | new_draw_info( NDI_UNIQUE, 0, pl, message ); |
} | | } |
| | |
/** | | /** |
| | |
* - on a floor without anything else | | * - on a floor without anything else |
* - on an existing wall, with or without a floor | | * - on an existing wall, with or without a floor |
*/ | | */ |
void apply_builder_wall( object* player, object* material, short x, short y ) | | void apply_builder_wall( object* pl, object* material, short x, short y ) |
{ | | { |
object* current_wall; | | object* current_wall; |
object* tmp; | | object* tmp; |
| | |
struct archt* new_wall; | | struct archt* new_wall; |
char message[ MAX_BUF ]; | | char message[ MAX_BUF ]; |
| | |
remove_marking_runes( player->map, x, y ); | | remove_marking_runes( pl->map, x, y ); |
| | |
/* Grab existing wall, if any */ | | /* Grab existing wall, if any */ |
current_wall = NULL; | | current_wall = NULL; |
tmp = GET_MAP_OB( player->map, x, y ); | | tmp = GET_MAP_OB( pl->map, x, y ); |
while ( tmp && !current_wall ) | | while ( tmp && !current_wall ) |
{ | | { |
if ( WALL == tmp->type ) | | if ( WALL == tmp->type ) |
| | |
tmp = arch_to_object( new_wall ); | | tmp = arch_to_object( new_wall ); |
tmp->type = WALL; | | tmp->type = WALL; |
SET_FLAG( tmp, FLAG_IS_BUILDABLE ); | | SET_FLAG( tmp, FLAG_IS_BUILDABLE ); |
insert_ob_in_map_at( tmp, player->map, 0, INS_ABOVE_FLOOR_ONLY, x, y ); | | insert_ob_in_map_at( tmp, pl->map, 0, INS_ABOVE_FLOOR_ONLY, x, y ); |
| | |
/* If existing wall, remove it, no need to fix other walls */ | | /* If existing wall, remove it, no need to fix other walls */ |
if ( current_wall ) | | if ( current_wall ) |
{ | | { |
remove_ob( current_wall ); | | remove_ob( current_wall ); |
free_object( current_wall ); | | free_object( current_wall ); |
fix_walls( player->map, x, y ); | | fix_walls( pl->map, x, y ); |
sprintf( message, "You redecorate the wall to better suit your tastes." ); | | sprintf( message, "You redecorate the wall to better suit your tastes." ); |
} | | } |
else | | else |
| | |
for ( xt = x - 1; xt <= x + 1; xt++ ) | | for ( xt = x - 1; xt <= x + 1; xt++ ) |
for ( yt = y - 1; yt <= y + 1; yt++ ) | | for ( yt = y - 1; yt <= y + 1; yt++ ) |
{ | | { |
if ( OUT_OF_REAL_MAP( player->map, xt, yt ) ) | | if ( OUT_OF_REAL_MAP( pl->map, xt, yt ) ) |
continue; | | continue; |
| | |
fix_walls( player->map, xt, yt ); | | fix_walls( pl->map, xt, yt ); |
} | | } |
} | | } |
| | |
| | |
decrease_ob( material ); | | decrease_ob( material ); |
| | |
/* And tell player what happened */ | | /* And tell player what happened */ |
new_draw_info( NDI_UNIQUE, 0, player, message ); | | new_draw_info( NDI_UNIQUE, 0, pl, message ); |
} | | } |
| | |
/** | | /** |
| | |
* Type of inserted item is tested for specific cases (doors & such). | | * Type of inserted item is tested for specific cases (doors & such). |
* Item is inserted above the floor, unless Str == 1 (only for detectors i guess) | | * Item is inserted above the floor, unless Str == 1 (only for detectors i guess) |
*/ | | */ |
void apply_builder_item( object* player, object* item, short x, short y ) | | void apply_builder_item( object* pl, object* item, short x, short y ) |
{ | | { |
object* tmp; | | object* tmp; |
struct archt* arch; | | struct archt* arch; |
| | |
int connected; | | int connected; |
| | |
/* Find floor */ | | /* Find floor */ |
floor = GET_MAP_OB( player->map, x, y ); | | floor = GET_MAP_OB( pl->map, x, y ); |
if ( !floor ) | | if ( !floor ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "Invalid square." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Invalid square." ); |
return; | | return; |
} | | } |
| | |
| | |
| | |
if ( !floor ) | | if ( !floor ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "This square has no floor, you can't build here." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "This square has no floor, you can't build here." ); |
return; | | return; |
} | | } |
| | |
if ( ( floor->above ) && ( strcmp( floor->above->arch->name, "rune_mark" ) ) ) | | if ( ( floor->above ) && ( strcmp( floor->above->arch->name, "rune_mark" ) ) ) |
/* Floor has something on top, and it isn't a marking rune */ | | /* Floor has something on top, and it isn't a marking rune */ |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "You can't build here." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You can't build here." ); |
return; | | return; |
} | | } |
| | |
| | |
SET_FLAG( tmp, FLAG_IS_BUILDABLE ); | | SET_FLAG( tmp, FLAG_IS_BUILDABLE ); |
SET_FLAG( tmp, FLAG_NO_PICK ); | | SET_FLAG( tmp, FLAG_NO_PICK ); |
| | |
| | /*
|
| | * This doesn't work on non unique maps. pedestals under floor will not be saved... |
insert_flag = ( item->stats.Str == 1 ) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY; | | insert_flag = ( item->stats.Str == 1 ) ? INS_BELOW_ORIGINATOR : INS_ABOVE_FLOOR_ONLY; |
| | */
|
| | insert_flag = INS_ABOVE_FLOOR_ONLY; |
| | |
connected = 0; | | connected = 0; |
| | |
| | |
case PEDESTAL: | | case PEDESTAL: |
case CF_HANDLE: | | case CF_HANDLE: |
/* Those items require a valid connection */ | | /* Those items require a valid connection */ |
connected = find_or_create_connection_for_map( player, x, y ); | | connected = find_or_create_connection_for_map( pl, x, y ); |
if ( connected == -1 ) | | if ( connected == -1 ) |
{ | | { |
/* Player already informed of failure by the previous function */ | | /* Player already informed of failure by the previous function */ |
| | |
return; | | return; |
} | | } |
/* Remove marking rune */ | | /* Remove marking rune */ |
remove_marking_runes( player->map, x, y ); | | remove_marking_runes( pl->map, x, y ); |
} | | } |
| | |
insert_ob_in_map_at( tmp, player->map, floor, insert_flag, x, y ); | | insert_ob_in_map_at( tmp, pl->map, floor, insert_flag, x, y ); |
if ( connected != 0 ) | | if ( connected != 0 ) |
add_button_link( tmp, player->map, connected ); | | add_button_link( tmp, pl->map, connected ); |
| | |
new_draw_info_format( NDI_UNIQUE, 0, player, "You build the %s", query_name( tmp ) ); | | new_draw_info_format( NDI_UNIQUE, 0, pl, "You build the %s", query_name( tmp ) ); |
decrease_ob_nr( item, 1 ); | | decrease_ob_nr( item, 1 ); |
} | | } |
| | |
| | |
* | | * |
* Removes first buildable item, either under or above the floor | | * Removes first buildable item, either under or above the floor |
*/ | | */ |
void apply_builder_remove( object* player, int dir ) | | void apply_builder_remove( object* pl, int dir ) |
{ | | { |
object* item; | | object* item; |
short x, y; | | short x, y; |
| | |
x = player->x + freearr_x[ dir ]; | | x = pl->x + freearr_x[ dir ]; |
y = player->y + freearr_y[ dir ]; | | y = pl->y + freearr_y[ dir ]; |
| | |
/* Check square */ | | /* Check square */ |
item = GET_MAP_OB( player->map, x, y ); | | item = GET_MAP_OB( pl->map, x, y ); |
if ( !item ) | | if ( !item ) |
{ | | { |
/* Should not happen with previous tests, but we never know */ | | /* Should not happen with previous tests, but we never know */ |
new_draw_info( NDI_UNIQUE, 0, player, "Invalid square." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Invalid square." ); |
LOG( llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, player->map->path ); | | LOG( llevError, "apply_builder_remove: (null) square at (%d, %d, %s)\n", x, y, pl->map->path ); |
return; | | return; |
} | | } |
| | |
| | |
| | |
if ( !item ) | | if ( !item ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "Nothing to remove." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Nothing to remove." ); |
return; | | return; |
} | | } |
| | |
| | |
switch ( item->type ) | | switch ( item->type ) |
{ | | { |
case WALL: | | case WALL: |
new_draw_info( NDI_UNIQUE, 0, player, "Can't remove a wall with that, build a floor." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Can't remove a wall with that, build a floor." ); |
return; | | return; |
| | |
case DOOR: | | case DOOR: |
| | |
| | |
default: | | default: |
/* Remove generic item */ | | /* Remove generic item */ |
new_draw_info_format( NDI_UNIQUE, 0, player, "You remove the %s", query_name( item ) ); | | new_draw_info_format( NDI_UNIQUE, 0, pl, "You remove the %s", query_name( item ) ); |
remove_ob( item ); | | remove_ob( item ); |
free_object( item ); | | free_object( item ); |
} | | } |
| | |
* This is the general map building function. Called when the player 'fires' a builder | | * This is the general map building function. Called when the player 'fires' a builder |
* or remover object. | | * or remover object. |
*/ | | */ |
void apply_map_builder( object* player, int dir ) | | void apply_map_builder( object* pl, int dir ) |
{ | | { |
object* builder; | | object* builder; |
object* tmp; | | object* tmp; |
short x, y; | | short x, y; |
| | |
if ( !player->type == PLAYER ) | | if ( !pl->type == PLAYER ) |
return; | | return; |
| | |
/*if ( !player->map->unique ) | | /*if ( !player->map->unique ) |
| | |
| | |
if ( dir == 0 ) | | if ( dir == 0 ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "You can't build or destroy under yourself." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You can't build or destroy under yourself." ); |
return; | | return; |
} | | } |
| | |
x = player->x + freearr_x[ dir ]; | | x = pl->x + freearr_x[ dir ]; |
y = player->y + freearr_y[ dir ]; | | y = pl->y + freearr_y[ dir ]; |
| | |
if ( ( 1 > x ) || ( 1 > y ) || ( ( MAP_WIDTH( player->map ) - 2 ) < x ) || ( ( MAP_HEIGHT( player->map ) - 2 ) < y ) ) | | if ( ( 1 > x ) || ( 1 > y ) || ( ( MAP_WIDTH( pl->map ) - 2 ) < x ) || ( ( MAP_HEIGHT( pl->map ) - 2 ) < y ) ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "Can't build on map edge..." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Can't build on map edge..." ); |
return; | | return; |
} | | } |
| | |
| | |
* since they are used for special things like connecting doors / buttons | | * since they are used for special things like connecting doors / buttons |
*/ | | */ |
| | |
tmp = GET_MAP_OB( player->map, x, y ); | | tmp = GET_MAP_OB( pl->map, x, y ); |
if ( !tmp ) | | if ( !tmp ) |
{ | | { |
/* Nothing, meaning player is standing next to an undefined square... */ | | /* Nothing, meaning player is standing next to an undefined square... */ |
LOG( llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, player->map->path ); | | LOG( llevError, "apply_map_builder: undefined square at (%d, %d, %s)\n", x, y, pl->map->path ); |
new_draw_info( NDI_UNIQUE, 0, player, "You'd better not build here, it looks weird." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You'd better not build here, it looks weird." ); |
return; | | return; |
} | | } |
| | |
| | |
{ | | { |
if ( !QUERY_FLAG( tmp, FLAG_IS_BUILDABLE ) && ( ( tmp->type != SIGN ) || ( strcmp( tmp->arch->name, "rune_mark" ) ) ) ) | | if ( !QUERY_FLAG( tmp, FLAG_IS_BUILDABLE ) && ( ( tmp->type != SIGN ) || ( strcmp( tmp->arch->name, "rune_mark" ) ) ) ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "You can't build here." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You can't build here." ); |
return; | | return; |
} | | } |
tmp = tmp->above; | | tmp = tmp->above; |
} | | } |
| | |
/* Now we know the square is ok */ | | /* Now we know the square is ok */ |
builder = player->contr->ranges[ range_builder ]; | | builder = pl->contr->ranges[ range_builder ]; |
| | |
if ( builder->subtype == ST_BD_REMOVE ) | | if ( builder->subtype == ST_BD_REMOVE ) |
/* Remover -> call specific function and bail out */ | | /* Remover -> call specific function and bail out */ |
{ | | { |
apply_builder_remove( player, dir ); | | apply_builder_remove( pl, dir ); |
return; | | return; |
} | | } |
| | |
| | |
* Find marked item to build, call specific function | | * Find marked item to build, call specific function |
*/ | | */ |
{ | | { |
tmp = find_marked_object( player ); | | tmp = find_marked_object( pl ); |
if ( !tmp ) | | if ( !tmp ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "You need to mark raw materials to use." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You need to mark raw materials to use." ); |
return; | | return; |
} | | } |
| | |
if ( tmp->type != MATERIAL ) | | if ( tmp->type != MATERIAL ) |
{ | | { |
new_draw_info( NDI_UNIQUE, 0, player, "You can't use the marked item to build." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "You can't use the marked item to build." ); |
return; | | return; |
} | | } |
| | |
switch( tmp->subtype ) | | switch( tmp->subtype ) |
{ | | { |
case ST_MAT_FLOOR: | | case ST_MAT_FLOOR: |
apply_builder_floor( player, tmp, x, y ); | | apply_builder_floor( pl, tmp, x, y ); |
return; | | return; |
| | |
case ST_MAT_WALL: | | case ST_MAT_WALL: |
apply_builder_wall( player, tmp, x, y ); | | apply_builder_wall( pl, tmp, x, y ); |
return; | | return; |
| | |
case ST_MAT_ITEM: | | case ST_MAT_ITEM: |
apply_builder_item( player, tmp, x, y ); | | apply_builder_item( pl, tmp, x, y ); |
return; | | return; |
| | |
default: | | default: |
new_draw_info( NDI_UNIQUE, 0, player, "Don't know how to apply this material, sorry." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Don't know how to apply this material, sorry." ); |
LOG( llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype ); | | LOG( llevError, "apply_map_builder: invalid material subtype %d\n", tmp->subtype ); |
return; | | return; |
} | | } |
} | | } |
| | |
/* Here, it means the builder has an invalid type */ | | /* Here, it means the builder has an invalid type */ |
new_draw_info( NDI_UNIQUE, 0, player, "Don't know how to apply this tool, sorry." ); | | new_draw_info( NDI_UNIQUE, 0, pl, "Don't know how to apply this tool, sorry." ); |
LOG( llevError, "apply_map_builder: invalid builder subtype %d\n", builder->subtype ); | | LOG( llevError, "apply_map_builder: invalid builder subtype %d\n", builder->subtype ); |
} | | } |