예제 #1
0
/********************************************
 return the type of the tile on map layer at x,y
 Returned string MUST BE FREED
 ********************************************/
char * map_get_tile_type(const char * map, int layer, int x, int y)
{
	char * map_type = nullptr;
	int width;
	int height;
	char layer_name[SMALL_BUF];

	if (entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH,
			nullptr) == RET_NOK)
	{
		return nullptr;
	}

	if (entry_read_int(MAP_TABLE, map, &height, MAP_KEY_HEIGHT,
			nullptr) == RET_NOK)
	{
		return nullptr;
	}

	if (x < 0 || y < 0 || x >= width || y >= height)
	{
		return nullptr;
	}

	sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer);
	entry_read_list_index(MAP_TABLE, map, &map_type, (width * y) + x,
			layer_name, MAP_KEY_TYPE, nullptr);

	if (map_type != nullptr)
	{
		return map_type;
	}

	return map_type;
}
예제 #2
0
/*******************************
Update the memory context by reading the character's data file on disk
Return RET_NOK if there is an error
*******************************/
ret_code_t context_update_from_file(context_t * context)
{
	/* Don't call context_set_* functions here to avoid inter-blocking */

	char * result;
	ret_code_t ret  = RET_OK;

	context_lock_list();

	if( context->id == NULL ) {
		context_unlock_list();
		return RET_NOK;
	}

	if(entry_read_string(CHARACTER_TABLE,context->id,&result, CHARACTER_KEY_NAME,NULL) == RET_OK ) {
		free( context->character_name );
		context->character_name = result;
	} else {
		ret = RET_NOK;
	}


	if(entry_read_string(CHARACTER_TABLE,context->id,&result, CHARACTER_KEY_TYPE,NULL) == RET_OK ) {
		free( context->type );
		context->type = result;
	} else {
		ret = RET_NOK;
	}

	if(entry_read_string(CHARACTER_TABLE,context->id,&result, CHARACTER_KEY_MAP,NULL) == RET_OK ) {
		free( context->map );
		ret = _context_set_map(context, result);
		free(result);
	} else {
		ret = RET_NOK;
	}

	int pos_tx;
	if(entry_read_int(CHARACTER_TABLE,context->id,&pos_tx, CHARACTER_KEY_POS_X,NULL) == RET_NOK ) {
		ret = RET_NOK;
	}
	_context_set_pos_tx(context,pos_tx);

	int pos_ty;
	if(entry_read_int(CHARACTER_TABLE,context->id,&pos_ty, CHARACTER_KEY_POS_Y,NULL) == RET_NOK ) {
		ret = RET_NOK;
	}
	_context_set_pos_ty(context,pos_ty);

	context_unlock_list();
	return ret;
}
예제 #3
0
/*************************************************************
 Move every context on the same coordinate as platform context
 *************************************************************/
static void platform_move(context_t * platform, const char * map, int x, int y,
		bool change_map)
{
	context_t * current = context_get_first();
	int is_platform;

	if (entry_read_int(CHARACTER_TABLE, platform->id, &is_platform,
	CHARACTER_KEY_PLATFORM, nullptr) == RET_NOK)
	{
		return;
	}

	if (!is_platform)
	{
		return;
	}

	while (current)
	{
		if (current == platform)
		{
			current = current->next;
			continue;
		}
		if (platform->pos_tx == current->pos_tx
				&& platform->pos_ty == current->pos_ty
				&& !strcmp(platform->map, current->map))
		{
			do_set_pos(current, map, x, y, change_map);
		}
		current = current->next;
	}
}
예제 #4
0
static void parse_client_conf()
{
	int version;

	if( already_parsed ) {
		return;
	}

	if (entry_read_int(NULL,CLIENT_CONF_FILE,&version,CLIENT_KEY_VERSION,NULL) == RET_NOK ) {
		return;
	}

	entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_over_tile,CLIENT_KEY_CURSOR_OVER_TILE,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_sprite,CLIENT_KEY_CURSOR_SPRITE,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_tile,CLIENT_KEY_CURSOR_TILE,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_equipment,CLIENT_KEY_CURSOR_EQUIPMENT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_inventory,CLIENT_KEY_CURSOR_INVENTORY,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_up,CLIENT_KEY_ACTION_MOVE_UP,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_down,CLIENT_KEY_ACTION_MOVE_DOWN,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_left,CLIENT_KEY_ACTION_MOVE_LEFT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_right,CLIENT_KEY_ACTION_MOVE_RIGHT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_up_left,CLIENT_KEY_ACTION_MOVE_UP_LEFT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_up_right,CLIENT_KEY_ACTION_MOVE_UP_RIGHT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_down_left,CLIENT_KEY_ACTION_MOVE_DOWN_LEFT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_down_right,CLIENT_KEY_ACTION_MOVE_DOWN_RIGHT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_character,CLIENT_KEY_ACTION_SELECT_CHARACTER,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_tile,CLIENT_KEY_ACTION_SELECT_TILE,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_equipment,CLIENT_KEY_ACTION_SELECT_EQUIPMENT,NULL);
	entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_inventory,CLIENT_KEY_ACTION_SELECT_INVENTORY,NULL);

	already_parsed = 1;
}
예제 #5
0
/*********************************************************
  Get NPC value.
  return 0 if not NPC
  return 1 if NPC
 *********************************************************/
int character_get_npc(const char * id)
{
	int npc;

	if(entry_read_int(CHARACTER_TABLE,id,&npc,CHARACTER_KEY_NPC,NULL) == RET_NOK ) {
		return 0;
	}

	return npc;
}
예제 #6
0
/**********************************
Draw the "list" keyword of a layer
**********************************/
static void compose_map_scenery(context_t * ctx, int layer_index)
{
	int i = 0;
	int x = 0;
	int y = 0;
	char * image_name = NULL;
	anim_t * anim;
	item_t * item;
	char ** scenery_list = NULL;
	char layer_name[SMALL_BUF];

	sprintf(layer_name,"%s%d",MAP_KEY_LAYER,layer_index);
	if(entry_get_group_list(MAP_TABLE, ctx->map, &scenery_list,layer_name,MAP_KEY_SCENERY,NULL) == RET_NOK ) {
		return;
	}

	while(scenery_list[i] != NULL ) {
		if(entry_read_int(MAP_TABLE, ctx->map, &x,layer_name,MAP_KEY_SCENERY,scenery_list[i],MAP_KEY_SCENERY_X,NULL) == RET_NOK ) {
			i++;
			continue;
		}
		if(entry_read_int(MAP_TABLE, ctx->map, &y,layer_name,MAP_KEY_SCENERY,scenery_list[i],MAP_KEY_SCENERY_Y,NULL) == RET_NOK ) {
			i++;
			continue;
		}
		if(entry_read_string(MAP_TABLE, ctx->map, &image_name,layer_name,MAP_KEY_SCENERY,scenery_list[i],MAP_KEY_SCENERY_IMAGE,NULL) == RET_NOK ) {
			i++;
			continue;
		}

		anim = imageDB_get_anim(ctx,image_name);

		item = item_list_add(&item_list);
		item_set_pos(item, x, y);
		item_set_anim(item,anim,0);
		//item_set_anim(item, x*ctx->tile_width, y*ctx->tile_height, anim,0);

		i++;
	}

	deep_free(scenery_list);
}
예제 #7
0
/****************************************
get the specified attribute's value
return -1 if fails
****************************************/
int attribute_get(const char * table, const char *id, const char * attribute)
{
	int current = -1;

	SDL_LockMutex(attribute_mutex);

	entry_read_int(table,id,&current,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL);

	SDL_UnlockMutex(attribute_mutex);

	return current;
}
예제 #8
0
/*****************************
 return the quantity of a resource
 return -1 on error
*****************************/
int resource_get_quantity(const char * item_id)
{
	int quantity;
	char * my_template;

	if((my_template=item_is_resource(item_id))==NULL) {
		return 1; /* unique item */
	}
	free(my_template);

	if(entry_read_int(ITEM_TABLE,item_id,&quantity,ITEM_QUANTITY, NULL) == RET_NOK ) {
		return -1;
	}

	return quantity;
}
예제 #9
0
/**********************************
Compose sprites
**********************************/
static void compose_sprite(context_t * ctx,int layer_index)
{
	int layer;

	context_lock_list();

	while(ctx != NULL ) {
		layer = 0;
		entry_read_int(CHARACTER_TABLE,ctx->id,&layer,CHARACTER_LAYER,NULL);

		if( layer == layer_index ) {
			set_up_sprite(ctx,NULL);
		}
		ctx = ctx->next;
	}

	context_unlock_list();
}
예제 #10
0
/***********************************
 Write a new tile type into a map file
 return RET_NOK if fails
 ***********************************/
ret_code_t map_set_tile_type(const char * map, int layer, const char * type,
		int x, int y, int network_broadcast)
{
	char * previous_type = nullptr;
	int width = -1;
	int index;
	char layer_name[SMALL_BUF];

	if (map == nullptr || type == nullptr)
	{
		return RET_NOK;
	}

	if (x < 0 || y < 0)
	{
		return RET_NOK;
	}

	sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer);

	// Manage concurrent access to map files
	SDL_LockMutex(map_mutex);

	// read size of map grid
	if (entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH,
			nullptr) == RET_NOK)
	{
		SDL_UnlockMutex(map_mutex);
		return RET_NOK;
	}

	index = width * y + x;

	// read previous map type
	if (entry_read_list_index(MAP_TABLE, map, &previous_type, index, layer_name,
			MAP_KEY_TYPE, nullptr) == RET_OK)
	{
		/* Do not change the type if it already the requested type
		 Avoid calling useless context_broadcast_file */
		if (strcmp(previous_type, type) == 0)
		{
			free(previous_type);
			SDL_UnlockMutex(map_mutex);
			return RET_OK;
		}
		free(previous_type);
	}

	if (entry_write_list_index(MAP_TABLE, map, type, index, layer_name,
			MAP_KEY_TYPE, nullptr) == RET_OK)
	{
		if (network_broadcast)
		{
			context_broadcast_map(map);
		}
	}

	SDL_UnlockMutex(map_mutex);

	return RET_OK;
}
예제 #11
0
/******************************************************
 return 0 if new position OK or if position has not changed.
 return -1 if the position was not set (because tile not allowed or out of bound)
 ******************************************************/
int character_set_pos(context_t * ctx, const char * map, int x, int y)
{
	char ** event_id;
	char * script;
	char ** param = nullptr;
	int i;
	bool change_map = false;
	int width = x + 1;
	int height = y + 1;
	int warpx = 0;
	int warpy = 0;
	int ctx_layer = 0;
	char layer_name[SMALL_BUF];
	char buf[SMALL_BUF];
	char * coord[3];
	int ret_value;
	int layer;

	if (ctx == nullptr)
	{
		return -1;
	}

	// Do nothing if no move
	if (!strcmp(ctx->map, map) && ctx->pos_tx == x && ctx->pos_ty == y)
	{
		return 0;
	}

	ctx_layer = 0;
	entry_read_int(CHARACTER_TABLE, ctx->id, &ctx_layer, CHARACTER_LAYER,
			nullptr);
	sprintf(layer_name, "%s%d", MAP_KEY_LAYER, ctx_layer);

	entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH, nullptr);
	entry_read_int(MAP_TABLE, map, &height, MAP_KEY_HEIGHT, nullptr);
	entry_read_int(MAP_TABLE, map, &warpx, MAP_KEY_WARP_X, nullptr);
	entry_read_int(MAP_TABLE, map, &warpy, MAP_KEY_WARP_Y, nullptr);

	// Offscreen script
	entry_read_string(MAP_TABLE, map, &script, MAP_OFFSCREEN, nullptr);
	if (script != nullptr && (x < 0 || y < 0 || x >= width || y >= height))
	{
		snprintf(buf, SMALL_BUF, "%d", x);
		coord[0] = strdup(buf);
		snprintf(buf, SMALL_BUF, "%d", y);
		coord[1] = strdup(buf);
		coord[2] = nullptr;

		ret_value = action_execute_script(ctx, script, (const char **) coord);

		free(coord[0]);
		free(coord[1]);
		free(script);

		return ret_value;
	}
	if (script)
	{
		free(script);
	}

	// Coordinates warping
	if (x < 0)
	{
		if (warpy == 0)
		{
			return -1;
		}
		x = width - 1;
	}
	if (y < 0)
	{
		if (warpy == 0)
		{
			return -1;
		}
		y = height - 1;
	}
	if (x >= width)
	{
		if (warpx == 0)
		{
			return -1;
		}
		x = 0;
	}
	if (y >= height)
	{
		if (warpy == 0)
		{
			return -1;
		}
		y = 0;
	}

	// Check if this character is allowed to go to the target tile
	layer = ctx_layer;
	while (layer >= 0)
	{
		ret_value = map_check_tile(ctx, ctx->id, map, layer, x, y);
		/* not allowed */
		if (ret_value == 0)
		{
			return -1;
		}
		/* allowed */
		if (ret_value == 1)
		{
			break;
		}
		layer--;
	}

	if (layer < 0)
	{
		return -1;
	}

	if (strcmp(ctx->map, map))
	{
		change_map = true;
	}

	/* If this character is a platform, move all characters on it */
	platform_move(ctx, map, x, y, change_map);

	do_set_pos(ctx, map, x, y, change_map);

	event_id = map_get_event(map, ctx_layer, x, y);

	if (event_id)
	{
		i = 0;
		while (event_id[i])
		{
			script = nullptr;
			if (entry_read_string(MAP_TABLE, map, &script, layer_name,
			MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_SCRIPT,
					nullptr) == RET_OK)
			{
				entry_read_list(MAP_TABLE, map, &param, layer_name,
				MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_PARAM, nullptr);
			}
			else if (entry_read_string(MAP_TABLE, map, &script,
			MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_SCRIPT,
					nullptr) == RET_OK)
			{
				entry_read_list(MAP_TABLE, map, &param, MAP_ENTRY_EVENT_LIST,
						event_id[i], MAP_EVENT_PARAM, nullptr);
			}

			if (script == nullptr)
			{
				i++;
				continue;
			}

			action_execute_script(ctx, script, (const char **) param);

			free(script);
			deep_free(param);
			param = nullptr;

			i++;
		}
		deep_free(event_id);
	}

	character_update_aggro(ctx);
	return 0;
}
예제 #12
0
/**********************************
Draw a single sprite
if image_file_name is not NULL, this file is used as an image rather than the normal sprite image
**********************************/
static void set_up_sprite(context_t * ctx, const char * image_file_name)
{
	anim_t ** sprite_list;
	anim_t ** sprite_move_list;
	item_t * item;
	int px;
	int py;
	int opx;
	int opy;
	Uint32 current_time;
	int angle;
	int flip;
	int force_flip;
	int move_status;
	char * zoom_str = NULL;
	double zoom = 1.0;
	int sprite_align = ALIGN_CENTER;
	int sprite_offset_y = 0;
	bool force_position = false;

	context_t * player_context = context_get_player();

	if( ctx->map == NULL ) {
		return;
	}
	if( ctx->in_game == false ) {
		return;
	}
	if( strcmp(ctx->map,player_context->map)) {
		return;
	}

	item = item_list_add(&item_list);

	current_time = sdl_get_global_time();

	// Force position when the player has changed map
	if( change_map == true ) {
		ctx->move_start_tick = current_time;
		ctx->animation_tick = current_time;
		force_position = true;
	}
	// Force position when this context has changed map
	if( ctx->change_map == true ) {
		ctx->move_start_tick = current_time;
		ctx->animation_tick = current_time;
		ctx->change_map = false;
		force_position = true;
	}

	if( ctx->animation_tick == 0 ) {
		ctx->animation_tick = current_time;
	}

	if( ctx->cur_pos_px == INT_MAX || ctx->cur_pos_py == INT_MAX ) {
		force_position = true;
	}

	// Detect sprite movement, initiate animation
	if( ctx->pos_changed && force_position == false ) {
		ctx->pos_changed = false;
		ctx->move_start_tick = current_time;
		ctx->start_pos_px = ctx->cur_pos_px;
		ctx->start_pos_py = ctx->cur_pos_py;

		/* flip need to remember previous direction to avoid resetting a
		   east -> west flip when a sprite goes to north for instance.
		   On the contrary rotation must not remember previous state, or
		   the rotation will be wrong.
		   Hence the distinction between orientation (no memory) and
		   direction (memory). */
		ctx->orientation = 0;
		// Compute direction
		if( ctx->pos_tx > ctx->prev_pos_tx ) {
			ctx->direction &= ~WEST;
			ctx->direction |= EAST;
			ctx->orientation |= EAST;
		}
		if( ctx->pos_tx < ctx->prev_pos_tx ) {
			ctx->direction &= ~EAST;
			ctx->direction |= WEST;
			ctx->orientation |= WEST;
		}
		if( ctx->pos_ty > ctx->prev_pos_ty ) {
			ctx->direction &= ~NORTH;
			ctx->direction |= SOUTH;
			ctx->orientation |= SOUTH;
		}
		if( ctx->pos_ty < ctx->prev_pos_ty ) {
			ctx->direction &= ~SOUTH;
			ctx->direction |= NORTH;
			ctx->orientation |= NORTH;
		}
	}

	// Select sprite to display
	sprite_list = select_sprite(ctx,image_file_name);
	if( sprite_list == NULL ) {
		return;
	}
	if( sprite_list[0] == NULL ) {
		free(sprite_list);
		return;
	}
	sprite_move_list = select_sprite_move(ctx,image_file_name);

	// Get position in pixel
	px = map_t2p_x(ctx->pos_tx,ctx->pos_ty,default_layer);
	py = map_t2p_y(ctx->pos_tx,ctx->pos_ty,default_layer);

	// Get per sprite zoom
	if(entry_read_string(CHARACTER_TABLE,ctx->id,&zoom_str,CHARACTER_KEY_ZOOM,NULL) == RET_OK ) {
		zoom = atof(zoom_str);
		free(zoom_str);
	}

	// Align sprite on tile
	entry_read_int(CHARACTER_TABLE,ctx->id,&sprite_align,CHARACTER_KEY_ALIGN,NULL);
	if( sprite_align == ALIGN_CENTER ) {
		px -= ((sprite_list[0]->w*default_layer->map_zoom*zoom)-default_layer->tile_width)/2;
		py -= ((sprite_list[0]->h*default_layer->map_zoom*zoom)-default_layer->tile_height)/2;
	}
	if( sprite_align == ALIGN_LOWER ) {
		px -= ((sprite_list[0]->w*default_layer->map_zoom*zoom)-default_layer->tile_width)/2;
		py -= (sprite_list[0]->h*default_layer->map_zoom*zoom)-default_layer->tile_height ;
	}

	// Add Y offset
	entry_read_int(CHARACTER_TABLE,ctx->id,&sprite_offset_y,CHARACTER_KEY_OFFSET_Y,NULL);
	py += sprite_offset_y;

	// Set sprite to item
	item_set_anim_start_tick(item,ctx->animation_tick);

	if( force_position == true ) {
		ctx->start_pos_px = px;
		ctx->cur_pos_px = px;
		ctx->start_pos_py = py;
		ctx->cur_pos_py = py;
	}

	opx = ctx->start_pos_px;
	opy = ctx->start_pos_py;

	item_set_move(item,opx,opy,px,py,ctx->move_start_tick,VIRTUAL_ANIM_DURATION);
	item_set_save_coordinate(item,&ctx->cur_pos_px,&ctx->cur_pos_py);
	item_set_anim_array(item,sprite_list);
	free(sprite_list);
	item_set_anim_move_array(item,sprite_move_list);
	free(sprite_move_list);

	// Get rotation configuration
	angle = 0;
	if( ctx->orientation & NORTH && ctx->orientation & EAST ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_NE_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & SOUTH && ctx->orientation & EAST ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_SE_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & SOUTH && ctx->orientation & WEST ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_SW_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & NORTH && ctx->orientation & WEST ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_NW_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & NORTH ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_N_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & SOUTH ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_S_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & WEST ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_W_ROT,NULL);
		item_set_angle(item,(double)angle);
	} else if ( ctx->orientation & EAST ) {
		entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_E_ROT,NULL);
		item_set_angle(item,(double)angle);
	}

	// Get flip configuration
	force_flip = 0;
	entry_read_int(CHARACTER_TABLE,ctx->id,&force_flip,CHARACTER_KEY_FORCE_FLIP,NULL);
	move_status = ctx->direction;
	if( force_flip == true ) {
		move_status = ctx->orientation;
	}

	flip = 0;
	if( angle == 0 ) {
		if( move_status & NORTH ) {
			entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_N_FLIP,NULL);
		}
		if( move_status & SOUTH ) {
			entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_S_FLIP,NULL);
		}
		if( move_status & WEST ) {
			entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_W_FLIP,NULL);
		}
		if( move_status & EAST ) {
			entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_E_FLIP,NULL);
		}

		switch(flip) {
		case 1:
			item_set_flip(item,SDL_FLIP_HORIZONTAL);
			break;
		case 2:
			item_set_flip(item,SDL_FLIP_VERTICAL);
			break;
		case 3:
			item_set_flip(item,SDL_FLIP_HORIZONTAL|SDL_FLIP_VERTICAL);
			break;
		default:
			item_set_flip(item,SDL_FLIP_NONE);
		}
	}

	item_set_click_left(item,cb_select_sprite,ctx->id,NULL);
	item_set_click_right(item,cb_redo_sprite,item,NULL);

	item_set_zoom_x(item,zoom * default_layer->map_zoom );
	item_set_zoom_y(item,zoom * default_layer->map_zoom );
}
예제 #13
0
/***********************************************************************
 Call aggro script for each context in every npc context aggro dist
 ***********************************************************************/
void character_update_aggro(context_t * agressor)
{
	context_t * target = nullptr;
	context_t * npc = nullptr;
	int aggro_dist;
	char * aggro_script;

	if (agressor == nullptr)
	{
		return;
	}

	if (agressor->map == nullptr)
	{
		return;
	}

	if (agressor->id == nullptr)
	{
		return;
	}

	/* If the current context is an NPC it might be an aggressor: compute its aggro */
	if (character_get_npc(agressor->id) && agressor->luaVM != nullptr)
	{
		if (entry_read_int(CHARACTER_TABLE, agressor->id, &aggro_dist,
		CHARACTER_KEY_AGGRO_DIST, nullptr) == RET_OK)
		{
			if (entry_read_string(CHARACTER_TABLE, agressor->id, &aggro_script,
			CHARACTER_KEY_AGGRO_SCRIPT, nullptr) == RET_OK)
			{
				target = context_get_first();

				while (target != nullptr)
				{
					/* Skip current context */
					if (agressor == target)
					{
						target = target->next;
						continue;
					}
					if (target->id == nullptr)
					{
						target = target->next;
						continue;
					}
					if (target->map == nullptr)
					{
						target = target->next;
						continue;
					}
					/* Skip if not on the same map */
					if (strcmp(agressor->map, target->map) != 0)
					{
						target = target->next;
						continue;
					}
					execute_aggro(agressor, target, aggro_script, aggro_dist);
					target = target->next;
				}
				free(aggro_script);
			}
		}
	}

	/* Compute aggro of all other NPC to the current context */
	target = agressor;
	npc = context_get_first();

	while (npc != nullptr)
	{
		/* Skip current context */
		if (target == npc)
		{
			npc = npc->next;
			continue;
		}
		if (npc->id == nullptr)
		{
			npc = npc->next;
			continue;
		}
		if (npc->map == nullptr)
		{
			npc = npc->next;
			continue;
		}
		if (npc->luaVM == nullptr)
		{
			npc = npc->next;
			continue;
		}
		/* Skip if not on the same map */
		if (strcmp(npc->map, target->map) != 0)
		{
			npc = npc->next;
			continue;
		}
		if (entry_read_int(CHARACTER_TABLE, npc->id, &aggro_dist,
		CHARACTER_KEY_AGGRO_DIST, nullptr) == RET_NOK)
		{
			npc = npc->next;
			continue;
		}
		if (entry_read_string(CHARACTER_TABLE, npc->id, &aggro_script,
		CHARACTER_KEY_AGGRO_SCRIPT, nullptr) == RET_NOK)
		{
			npc = npc->next;
			continue;
		}

		execute_aggro(npc, target, aggro_script, aggro_dist);

		free(aggro_script);

		npc = npc->next;
	}
}
예제 #14
0
/**********************************
Compose item on map
**********************************/
static void compose_item(context_t * ctx,int layer_index)
{
	char * sprite_name = NULL;
	int sprite_align = ALIGN_CENTER;
	int sprite_offset_y = 0;
	anim_t * anim;
	item_t * item;
	int x;
	int y;
	int temp_x;
	int temp_y;
	char ** item_id;
	int i;
	static TTF_Font * font = NULL;
	char * mytemplate;
	int quantity;
	char buf[SMALL_BUF];
	char layer_name[SMALL_BUF];

	sprintf(layer_name,"%s%d",MAP_KEY_LAYER,layer_index);

	if(entry_get_group_list(MAP_TABLE,ctx->map,&item_id,layer_name,MAP_ENTRY_ITEM_LIST,NULL) == RET_NOK ) {
		return;
	}

	font = font_get(ctx,ITEM_FONT, ITEM_FONT_SIZE);

	i=0;
	while( item_id[i] != NULL ) {
		sprite_align = ALIGN_CENTER;

		if(entry_read_int(MAP_TABLE,ctx->map,&x,layer_name,MAP_ENTRY_ITEM_LIST,item_id[i],MAP_ITEM_POS_X,NULL) == RET_NOK ) {
			i++;
			continue;
		}

		if(entry_read_int(MAP_TABLE,ctx->map,&y,layer_name,MAP_ENTRY_ITEM_LIST,item_id[i],MAP_ITEM_POS_Y,NULL) == RET_NOK ) {
			i++;
			continue;
		}

		mytemplate = item_is_resource(item_id[i]);

		if ( mytemplate == NULL ) {
			if(entry_read_string(ITEM_TABLE,item_id[i],&sprite_name,ITEM_SPRITE,NULL) == RET_NOK ) {
				i++;
				continue;
			}
			entry_read_int(ITEM_TABLE,item_id[i],&sprite_align,ITEM_ALIGN,NULL);
			entry_read_int(ITEM_TABLE,item_id[i],&sprite_offset_y,ITEM_OFFSET_Y,NULL);
		} else {
			if(entry_read_string(ITEM_TEMPLATE_TABLE,mytemplate,&sprite_name,ITEM_SPRITE,NULL) == RET_NOK ) {
				free(mytemplate);
				i++;
				continue;
			}
			entry_read_int(ITEM_TEMPLATE_TABLE,mytemplate,&sprite_align,ITEM_ALIGN,NULL);
			entry_read_int(ITEM_TEMPLATE_TABLE,mytemplate,&sprite_offset_y,ITEM_OFFSET_Y,NULL);
			free(mytemplate);
		}

		item = item_list_add(&item_list);

		anim = imageDB_get_anim(ctx,sprite_name);
		free(sprite_name);

		temp_x = map_t2p_x(x,y,default_layer);
		temp_y = map_t2p_y(x,y,default_layer);
		x = temp_x;
		y = temp_y;
		/* Align on tile */
		if( sprite_align == ALIGN_CENTER ) {
			x -= ((anim->w*default_layer->map_zoom)-default_layer->tile_width)/2;
			y -= ((anim->h*default_layer->map_zoom)-default_layer->tile_height)/2;
		}
		if( sprite_align == ALIGN_LOWER ) {
			x -= ((anim->w*default_layer->map_zoom)-default_layer->tile_width)/2;
			y -= (anim->h*default_layer->map_zoom)-default_layer->tile_height;
		}

		y += sprite_offset_y;

		item_set_pos(item,x,y);
		item_set_anim(item,anim,0);
		item_set_zoom_x(item, default_layer->map_zoom );
		item_set_zoom_y(item, default_layer->map_zoom );
		if(font) {
			quantity = resource_get_quantity(item_id[i]);
			sprintf(buf,"%d",quantity);
			item_set_string(item,buf);
			item_set_font(item,font);
		}

		i++;
	}

	deep_free(item_id);
}
예제 #15
0
/**********************************************
 Delete an event on map at given coordinate
 return RET_NOK if fails
 **********************************************/
ret_code_t map_delete_event(const char * map, int layer, const char * script,
		int x, int y)
{
	char ** eventlist;
	int i = 0;
	int mapx;
	int mapy;
	char * map_script = nullptr;
	const char * id = nullptr;
	char layer_name[SMALL_BUF];

	if (x < 0 || y < 0)
	{
		return RET_NOK;
	}

	sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer);

	/* Manage concurrent acces to map files */
	SDL_LockMutex(map_mutex);
	/* Search events on the specified tile */
	if (entry_get_group_list(MAP_TABLE, map, &eventlist, layer_name,
			MAP_ENTRY_EVENT_LIST, nullptr) == RET_NOK)
	{
		SDL_UnlockMutex(map_mutex);
		return RET_NOK;
	}

	while (eventlist[i] != nullptr)
	{
		if (entry_read_int(MAP_TABLE, map, &mapx, layer_name,
				MAP_ENTRY_EVENT_LIST, eventlist[i], MAP_EVENT_POS_X,
				nullptr) == RET_NOK)
		{
			i++;
			continue;
		}
		if (entry_read_int(MAP_TABLE, map, &mapy, layer_name,
				MAP_ENTRY_EVENT_LIST, eventlist[i], MAP_EVENT_POS_Y,
				nullptr) == RET_NOK)
		{
			i++;
			continue;
		}
		if (entry_read_string(MAP_TABLE, map, &map_script, layer_name,
				MAP_ENTRY_EVENT_LIST, eventlist[i], MAP_EVENT_SCRIPT,
				nullptr) == RET_NOK)
		{
			i++;
			continue;
		}
		if (x == mapx && y == mapy && !strcmp(map_script, script))
		{
			id = eventlist[i];
			free(map_script);
			break;
		}
		free(map_script);
		i++;
	}

	if (id == nullptr)
	{
		SDL_UnlockMutex(map_mutex);
		return RET_NOK;
	}

	/* remove the event from the events list of the map */
	if (entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_EVENT_LIST,
			nullptr) == RET_NOK)
	{
		SDL_UnlockMutex(map_mutex);
		return RET_NOK;
	}

	deep_free(eventlist);

	SDL_UnlockMutex(map_mutex);

	/* Send network notifications */
	context_broadcast_map(map);

	return RET_OK;
}
예제 #16
0
/***********************************
 check if id is allowed to go on a tile
 return 1 if the context is allowed to go to the tile at coord x,y
 return 0 if the context is NOT allowed to go to the tile at coord x,y
 return RET_NOK on error or no data found
 *************************************/
ret_code_t map_check_tile(context_t * ctx, char * id, const char * map,
		int layer, int x, int y)
{
	char * script;
	char sx[64];
	char sy[64];
	char * param[5];
	int res;
	char * tile_type;
	char ** allowed_tile;
	int i = 0;
	int width = 0;
	int height = 0;

	if (entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH,
			nullptr) == RET_NOK)
	{
		return RET_NOK;
	}
	if (entry_read_int(MAP_TABLE, map, &height, MAP_KEY_HEIGHT,
			nullptr) == RET_NOK)
	{
		return RET_NOK;
	}

	if (x < 0 || y < 0 || x >= width || y >= height)
	{
		return 0;
	}

	// If there is an allowed_tile_script, run it
	if (entry_read_string(CHARACTER_TABLE, id, &script,
			CHARACTER_KEY_ALLOWED_TILE_SCRIPT, nullptr) == RET_OK)
	{
		param[0] = id;
		param[1] = (char *) map;
		sprintf(sx, "%d", x);
		sprintf(sy, "%d", y);
		param[2] = sx;
		param[3] = sy;
		param[4] = nullptr;
		res = action_execute_script(ctx, script, (const char**) param);
		free(script);
		return res;
	}

	// Read tile at given index on this map
	entry_read_int(CHARACTER_TABLE, id, &layer, CHARACTER_LAYER, nullptr);
	tile_type = get_tile_type_through_layer(map, layer, x, y);

	// Allow tile if no type defined
	if (tile_type == nullptr)
	{
		return 1;
	}

	// Allow tile if its type is empty (i.e. "")
	if (tile_type[0] == 0)
	{
		free(tile_type);
		return 1;
	}

	// If there is allowed_tile list, check it
	if (entry_read_list(CHARACTER_TABLE, id, &allowed_tile,
			CHARACTER_KEY_ALLOWED_TILE, nullptr) == RET_OK)
	{
		i = 0;
		while (allowed_tile[i] != nullptr)
		{
			if (strcmp(allowed_tile[i], tile_type) == 0)
			{
				deep_free(allowed_tile);
				free(tile_type);
				return 1;
			}
			i++;
		}

		deep_free(allowed_tile);
		free(tile_type);
		return 0;
	}

	free(tile_type);
	// Allow all tiles by default
	return 1;
}
예제 #17
0
/***************************************************************************
Add the specified value to the specified attribute
Check on max and min are done and call to on_* scripts are done if set
ctx is the context of the source of the attribute change request
id is the id of the target of the change
return -1 if fails
***************************************************************************/
int attribute_change(context_t * context, const char * table, const char * id, const char * attribute, int value)
{
	int current;
	int old;
	int min;
	int max;
	char buf[SMALL_BUF];
	bool do_min_action = false;
	bool do_down_action = false;
	bool do_max_action = false;
	bool do_up_action = false;
	char * action;
	char * min_action = NULL;
	char * down_action = NULL;
	char * max_action = NULL;
	char * up_action = NULL;

	SDL_LockMutex(attribute_mutex);

	if(entry_read_int(table,id,&current,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL) == RET_NOK) {
		SDL_UnlockMutex(attribute_mutex);
		return -1;
	}

	if(entry_read_int(table,id,&min,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_MIN, NULL) == RET_NOK) {
		min = -1;
	}

	if(entry_read_int(table,id,&max,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_MAX, NULL) == RET_NOK) {
		max = -1;
	}

	old = current;
	current = current + value;
	if( min != -1 ) {
		if(current <= min) {
			do_min_action = true;
			current = min;
		}
	}

	if( max != -1 ) {
		if(current >= max) {
			do_max_action = true;
			current = max;
		}
	}

	if(entry_write_int(table,id,current,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL) == RET_NOK ) {
		SDL_UnlockMutex(attribute_mutex);
		return -1;
	}
	if(entry_write_int(table,id,old,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_PREVIOUS, NULL) == RET_NOK ) {
		SDL_UnlockMutex(attribute_mutex);
		return -1;
	}

	// Check automatic actions
	if( value < 0 ) {
		if( do_min_action == true ) {
			if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_MIN, NULL) == RET_NOK ) {
				do_min_action = false;
			} else {
				min_action = action;
			}
		}

		if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_DOWN, NULL) == RET_OK ) {
			do_down_action = true;
			down_action = action;
		}
	}

	if( value > 0 ) {
		if( do_max_action == true ) {
			if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_MAX, NULL) == RET_NOK ) {
				do_max_action = false;
			} else {
				max_action = action;
			}
		}

		if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_UP, NULL) == RET_OK ) {
			do_up_action = true;
			up_action = action;
		}
	}

	SDL_UnlockMutex(attribute_mutex);

	// do automatic actions
	if( do_down_action == true && down_action != NULL ) {
		action_execute_script(context,down_action,NULL);
	}
	if( down_action ) {
		free(down_action);
	}

	if( do_min_action == true && min_action != NULL ) {
		action_execute_script(context,min_action,NULL);
	}
	if( min_action ) {
		free(min_action);
	}

	if( do_up_action == true && up_action != NULL ) {
		action_execute_script(context,up_action,NULL);
	}
	if( min_action ) {
		free(up_action);
	}

	if( do_max_action == true && max_action != NULL ) {
		action_execute_script(context,max_action,NULL);
		free(max_action);
	}
	if( max_action ) {
		free(max_action);
	}

	sprintf(buf,"%s.%s.%s",ATTRIBUTE_GROUP,attribute,ATTRIBUTE_CURRENT);
	network_broadcast_entry_int(table,id,buf,current,true);
	sprintf(buf,"%s.%s.%s",ATTRIBUTE_GROUP,attribute,ATTRIBUTE_PREVIOUS);
	network_broadcast_entry_int(table,id,buf,old,true);
	return 0;
}
예제 #18
0
/**************************************
 delete an item on context's map
 **************************************/
char * map_delete_item(const char * map, int layer, int x, int y)
{
	char ** itemlist;
	int i = 0;
	int mapx;
	int mapy;
	const char * id = nullptr;
	char * saved_item = nullptr;
	char layer_name[SMALL_BUF];

	if (x < 0 || y < 0)
	{
		return nullptr;
	}

	sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer);
	/* Manage concurrent acces to map files */
	SDL_LockMutex(map_mutex);
	/* Search the items on the specified tile */
	if (entry_get_group_list(MAP_TABLE, map, &itemlist, layer_name,
			MAP_ENTRY_ITEM_LIST, nullptr) == RET_NOK)
	{
		SDL_UnlockMutex(map_mutex);
		return nullptr;
	}

	while (itemlist[i] != nullptr)
	{
		if (entry_read_int(MAP_TABLE, map, &mapx, layer_name,
				MAP_ENTRY_ITEM_LIST, itemlist[i], MAP_ITEM_POS_X,
				nullptr) == RET_NOK)
		{
			SDL_UnlockMutex(map_mutex);
			deep_free(itemlist);
			return nullptr;
		}

		if (entry_read_int(MAP_TABLE, map, &mapy, layer_name,
				MAP_ENTRY_ITEM_LIST, itemlist[i], MAP_ITEM_POS_Y,
				nullptr) == RET_NOK)
		{
			SDL_UnlockMutex(map_mutex);
			deep_free(itemlist);
			return nullptr;
		}

		if (x == mapx && y == mapy)
		{
			id = itemlist[i];
			saved_item = strdup(itemlist[i]);
			break;
		}

		i++;
	}

	if (id == nullptr)
	{
		deep_free(itemlist);
		if (saved_item)
		{
			free(saved_item);
		}
		SDL_UnlockMutex(map_mutex);
		return nullptr;
	}

	/* remove the item from the item list of the map */
	if (entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_ITEM_LIST,
			nullptr) == RET_NOK)
	{
		deep_free(itemlist);
		free(saved_item);
		SDL_UnlockMutex(map_mutex);
		return nullptr;
	}

	deep_free(itemlist);

	SDL_UnlockMutex(map_mutex);

	/* Send network notifications */
	context_broadcast_map(map);

	return saved_item;
}
예제 #19
0
/******************************************
 Add a layer filled with image_name on map
 return RET_NOK on failure
 ***********************************************/
ret_code_t map_add_layer(const char * map_name, int layer, int w, int h,
		int tile_w, int tile_h, const char * default_tile,
		const char * default_type)
{
	char layer_name[SMALL_BUF];

	sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer);

	if (w > 0)
	{
		if (entry_write_int(MAP_TABLE, map_name, w, layer_name, MAP_KEY_WIDTH,
				nullptr) == RET_NOK)
		{
			return RET_NOK;
		}
	}
	else
	{ // No specific dimension, take the map's global one
		if (entry_read_int(MAP_TABLE, map_name, &w, MAP_KEY_WIDTH,
				nullptr) == RET_NOK)
		{
			return RET_NOK;
		}
	}

	if (h > 0)
	{
		if (entry_write_int(MAP_TABLE, map_name, h, layer_name, MAP_KEY_HEIGHT,
				nullptr) == RET_NOK)
		{
			return RET_NOK;
		}
	}
	else
	{ // No specific dimension, take the map's global one
		if (entry_read_int(MAP_TABLE, map_name, &h, MAP_KEY_HEIGHT,
				nullptr) == RET_NOK)
		{
			return RET_NOK;
		}
	}

	if (tile_w > 0)
	{
		if (entry_write_int(MAP_TABLE, map_name, tile_w, layer_name,
				MAP_KEY_TILE_WIDTH, nullptr) == RET_NOK)
		{
			return RET_NOK;
		}
	}
	if (tile_h > 0)
	{
		if (entry_write_int(MAP_TABLE, map_name, tile_h, layer_name,
				MAP_KEY_TILE_HEIGHT, nullptr) == RET_NOK)
		{
			return RET_NOK;
		}
	}

	int i;
	char ** tile_array = (char**) malloc(((w * h) + 1) * sizeof(char *));

	// Write default tile
	for (i = 0; i < (w * h); i++)
	{
		tile_array[i] = (char *) default_tile;
	}
	tile_array[i] = nullptr; // End of list

	if (entry_write_list(MAP_TABLE, map_name, tile_array, layer_name,
			MAP_KEY_SET, nullptr) == RET_NOK)
	{
		free(tile_array);
		return RET_NOK;
	}

	// Write default type
	for (i = 0; i < (w * h); i++)
	{
		tile_array[i] = (char *) default_type;
	}
	tile_array[i] = nullptr; // End of list

	if (entry_write_list(MAP_TABLE, map_name, tile_array, layer_name,
			MAP_KEY_TYPE, nullptr) == RET_NOK)
	{
		free(tile_array);
		return RET_NOK;
	}

	free(tile_array);
	return RET_OK;
}
예제 #20
0
/**********************************
Compose the character select screen
**********************************/
item_t * scr_play_compose(context_t * ctx)
{
	int bg_red = 0;
	int bg_blue = 0;
	int bg_green = 0;
	char * map_filename;
	int layer_index = 0;
	char * old_sfx = NULL;

	option = option_get();

	if(item_list) {
		item_list_free(item_list);
		item_list = NULL;
	}

	if(ctx->map == NULL ) {
		if(context_update_from_file(ctx) == RET_NOK) {
			return NULL;
		}
	}

	if(init) {
		/* Register this character to receive server notifications */
		network_request_start(ctx,ctx->id);
		ui_play_init();
		init = false;
	}

	sdl_free_keycb();
	sdl_free_mousecb();
	sdl_add_mousecb(MOUSE_WHEEL_UP,cb_zoom);
	sdl_add_mousecb(MOUSE_WHEEL_DOWN,cb_unzoom);

	change_map = ctx->change_map;

	if( change_map == true ) {
		map_filename = strconcat( MAP_TABLE,"/",ctx->map,NULL);
		network_send_req_file(ctx,map_filename);
		free(map_filename);
		if(default_layer) {
			map_layer_delete(default_layer);
		}
		default_layer = map_layer_new(ctx->map,DEFAULT_LAYER,NULL);
	}

	if( default_layer && default_layer->active ) { // Make sure map data are available
		for(layer_index = 0; layer_index < MAX_LAYER; layer_index++) {
			compose_map_set(ctx,layer_index);
			compose_map_scenery(ctx,layer_index);
			compose_item(ctx,layer_index);
			compose_sprite(ctx,layer_index);
			compose_type(ctx,layer_index);
		}
		compose_map_button(ctx);
		compose_select(ctx);

		ui_play_compose(ctx,item_list);

		// force virtual coordinate on map change
		if( change_map == true ) {
			sdl_force_virtual_x(map_t2p_x(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_width[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_width[ctx->pos_ty%default_layer->row_num]/2 );
			sdl_force_virtual_y(map_t2p_y(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_height[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_height[ctx->pos_ty%default_layer->row_num]/2 );
		}
		// set virtual coordinate on the same map
		else {
			sdl_set_virtual_x(map_t2p_x(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_width[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_width[ctx->pos_ty%default_layer->row_num]/2 );
			sdl_set_virtual_y(map_t2p_y(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_height[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_height[ctx->pos_ty%default_layer->row_num]/2 );
		}
	}

	entry_read_int(MAP_TABLE,ctx->map,&bg_red,MAP_KEY_BG_RED,NULL);
	entry_read_int(MAP_TABLE,ctx->map,&bg_blue,MAP_KEY_BG_BLUE,NULL);
	entry_read_int(MAP_TABLE,ctx->map,&bg_green,MAP_KEY_BG_GREEN,NULL);
	SDL_SetRenderDrawColor(ctx->render, bg_red, bg_blue, bg_green, 255);

	old_sfx = sfx;
	sfx = NULL;

	entry_read_string(MAP_TABLE,ctx->map,&sfx,MAP_SFX,NULL);

	if(old_sfx)  {
		if( sfx ) {
			if( strcmp(old_sfx,sfx) ) {
				sfx_stop(ctx,old_sfx);
			}
		} else  { // sfx == NULL
			sfx_stop(ctx,old_sfx);
		}
		free(old_sfx);
	}

	if( sfx && sfx[0]!=0 ) {
		sfx_play(ctx,sfx,NO_RESTART);
	}

	return item_list;
}