Beispiel #1
0
/**
 * Sends a message to a channel.
 *
 * @param chan The destination channel.
 * @param sd   The source character.
 * @param msg  The message to send.
 *
 * If no source character is specified, it'll send an anonymous message.
 */
void channel_send(struct channel_data *chan, struct map_session_data *sd, const char *msg)
{
	char message[150];
	nullpo_retv(chan);
	nullpo_retv(msg);

	if (sd && chan->msg_delay != 0
	 && DIFF_TICK(sd->hchsysch_tick + chan->msg_delay*1000, timer->gettick()) > 0
	 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) {
		clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1455));
		return;
	} else if (sd) {
		safesnprintf(message, 150, "[ #%s ] %s : %s", chan->name, sd->status.name, msg);
		clif->channel_msg(chan,sd,message);
		if (chan->type == HCS_TYPE_IRC)
			ircbot->relay(sd->status.name,msg);
		if (chan->msg_delay != 0)
			sd->hchsysch_tick = timer->gettick();
	} else {
		safesnprintf(message, 150, "[ #%s ] %s", chan->name, msg);
		clif->channel_msg2(chan, message);
		if (chan->type == HCS_TYPE_IRC)
			ircbot->relay(NULL, msg);
	}
}
Beispiel #2
0
/*==========================================
 * Pet Attack Skill [Skotlex]
 *------------------------------------------*/
int pet_attackskill(struct pet_data *pd, int target_id)
{
	struct block_list *bl;
	int inf;

	if (!battle_config.pet_status_support || !pd->a_skill || 
		(battle_config.pet_equip_required && !pd->pet.equip))
		return 0;

	if (DIFF_TICK(pd->ud.canact_tick, gettick()) > 0)
		return 0;
	
	if (rand()%100 < (pd->a_skill->rate +pd->pet.intimate*pd->a_skill->bonusrate/1000))
	{	//Skotlex: Use pet's skill 
		bl=map_id2bl(target_id);
		if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL || status_isdead(bl) ||
			!check_distance_bl(&pd->bl, bl, pd->db->range3))
			return 0;

		inf = skill_get_inf(pd->a_skill->id);
		if (inf & INF_GROUND_SKILL)
			unit_skilluse_pos(&pd->bl, bl->x, bl->y, pd->a_skill->id, pd->a_skill->lv);
		else	//Offensive self skill? Could be stuff like GX.
			unit_skilluse_id(&pd->bl,(inf&INF_SELF_SKILL?pd->bl.id:bl->id), pd->a_skill->id, pd->a_skill->lv);
		return 1; //Skill invoked.
	}
	return 0;
}
Beispiel #3
0
/*======================================
 *	CORE : Timer Heap
 *--------------------------------------
 */
static void push_timer_heap(int index)
{
	int i,h;

	if(timer_heap==NULL || timer_heap[0]+1>=timer_heap_max){
		int first = timer_heap==NULL;

		timer_heap_max += 256;
		timer_heap = realloc(timer_heap,sizeof(int)*timer_heap_max);
		if(timer_heap==NULL){
			printf("out of memory : push_timer_heap\n");
			exit(1);
		}
		if(first)
			timer_heap[0]=0;
	}

	timer_heap[0]++;

	for(h=timer_heap[0]-1,i=(h-1)/2;
		h>0 && DIFF_TICK(timer_data[index].tick , timer_data[timer_heap[i+1]].tick)<0;
		i=(h-1)/2) {
		timer_heap[h+1]=timer_heap[i+1],h=i;
	}
	timer_heap[h+1]=index;
}
Beispiel #4
0
int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the player and sends it to the char-server for saving. [Skotlex]

#ifdef ENABLE_SC_SAVING
	int i, count=0;
	unsigned int tick;
	struct status_change_data data;
	struct status_change *sc = &sd->sc;
	const struct TimerData *timer;

	chrif_check(-1);
	tick = gettick();
	
	WFIFOHEAD(char_fd, 14 + SC_MAX*sizeof(struct status_change_data));
	WFIFOW(char_fd,0) = 0x2b1c;
	WFIFOL(char_fd,4) = sd->status.account_id;
	WFIFOL(char_fd,8) = sd->status.char_id;
	
	for (i = 0; i < SC_MAX; i++) {
		if (!sc->data[i])
			continue;
		if (sc->data[i]->timer != INVALID_TIMER) {
			timer = get_timer(sc->data[i]->timer);
			if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0)
				continue;
			data.tick = DIFF_TICK(timer->tick,tick); //Duration that is left before ending.
		} else
			data.tick = -1; //Infinite duration
		data.type = i;
		data.val1 = sc->data[i]->val1;
		data.val2 = sc->data[i]->val2;
		data.val3 = sc->data[i]->val3;
		data.val4 = sc->data[i]->val4;
		memcpy(WFIFOP(char_fd,14 +count*sizeof(struct status_change_data)),
			&data, sizeof(struct status_change_data));
		count++;
	}
	
	if (count == 0)
		return 0; //Nothing to save.
	
	WFIFOW(char_fd,12) = count;
	WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size
	WFIFOSET(char_fd,WFIFOW(char_fd,2));
#endif
	
	return 0;
}
Beispiel #5
0
/**
* Get current Mercenary lifetime
* @param md The Mercenary
* @return The Lifetime
**/
int mercenary_get_lifetime(struct mercenary_data *md) {
	const struct TimerData * td;
	if( md == NULL || md->contract_timer == INVALID_TIMER )
		return 0;

	td = get_timer(md->contract_timer);
	return (td != NULL) ? DIFF_TICK(td->tick, gettick()) : 0;
}
Beispiel #6
0
int elemental_get_lifetime(struct elemental_data *ed) {
	const struct TimerData * td;
	if( ed == NULL || ed->summon_timer == INVALID_TIMER )
		return 0;

	td = get_timer(ed->summon_timer);
	return (td != NULL) ? DIFF_TICK(td->tick, gettick()) : 0;
}
Beispiel #7
0
int bg_send_xy_timer_sub(DBKey key, void *data, va_list ap)
{
	struct battleground_data *bg = (struct battleground_data *)data;
	struct map_session_data *sd;
	char output[128];
	int i, m;

	nullpo_ret(bg);
	m = map_mapindex2mapid(bg->mapindex);
	bg->reveal_flag = !bg->reveal_flag; // Switch

	for( i = 0; i < MAX_BG_MEMBERS; i++ )
	{
		if( (sd = bg->members[i].sd) == NULL )
			continue;
		if( battle_config.bg_idle_autokick && DIFF_TICK(last_tick, sd->idletime) >= battle_config.bg_idle_autokick && bg->g )
		{
			sprintf(output, "- AFK [%s] Kicked -", sd->status.name);
			clif_broadcast2(&sd->bl, output, (int)strlen(output)+1, bg->color, 0x190, 20, 0, 0, BG);

			bg_team_leave(sd,3);
			clif_displaymessage(sd->fd, "You have been kicked from Battleground because of your AFK status.");
			pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
			continue;
		}

		if( sd->bl.x != bg->members[i].x || sd->bl.y != bg->members[i].y )
		{ // xy update
			bg->members[i].x = sd->bl.x;
			bg->members[i].y = sd->bl.y;
			clif_bg_xy(sd);
		}
		if( bg->reveal_pos && bg->reveal_flag && sd->bl.m == m ) // Reveal each 4 seconds
			map_foreachinmap(bg_reveal_pos,m,BL_PC,sd,1,bg->color);
		if( battle_config.bg_idle_announce && !sd->state.bg_afk && DIFF_TICK(last_tick, sd->idletime) >= battle_config.bg_idle_announce && bg->g )
		{ // Idle announces
			sd->state.bg_afk = 1;
			sprintf(output, "%s : %s seens to be away. AFK Warning - Can be kicked out with @reportafk", bg->g->name, sd->status.name);
			clif_bg_message(bg, bg->bg_id, bg->g->name, output, strlen(output) + 1);
		}
	}
	return 0;
}
Beispiel #8
0
// Existence check of WISP data
int check_ttl_wisdata_sub(void *key, void *data, va_list ap) {
	unsigned long tick;
	struct WisData *wd = (struct WisData *)data;
	tick = va_arg(ap, unsigned long);

	if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX)
		wis_dellist[wis_delnum++] = wd->id;

	return 0;
}
Beispiel #9
0
/**
 * Existence check of WISP data
 * @see DBApply
 */
int check_ttl_wisdata_sub(DBKey key, DBData *data, va_list ap)
{
	int64 tick;
	struct WisData *wd = DB->data2ptr(data);
	tick = va_arg(ap, int64);

	if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX)
		wis_dellist[wis_delnum++] = wd->id;

	return 0;
}
Beispiel #10
0
int auth_db_cleanup_sub(DBKey key,void *data,va_list ap)
{
	struct auth_node *node=(struct auth_node*)data;

	if(DIFF_TICK(gettick(),node->node_created)>30000) {
		ShowNotice("Character (aid: %d) not authed within 30 seconds of character select!\n", node->account_id);
		if (node->char_dat)
			aFree(node->char_dat);
		db_remove(auth_db, key);
		return 1;
	}
	return 0;
}
Beispiel #11
0
// Wisリストの生存チェック
int check_ttl_wislist()
{
	unsigned long tick=gettick();
	struct WisList* p=wis_list, **prev=&wis_list;
	for( ; p; prev=&p->next,p=p->next ){
		if( DIFF_TICK(tick,p->tick)>WISLIST_TTL ){
			*prev=p->next;
			free(p);
			p=*prev;
		}
	}
	return 0;
}
Beispiel #12
0
void bg_block_skill_status(struct battleground_data *bg, int skillnum)
{
	const struct TimerData * td;
	char output[128];
	int seconds, idx;

	idx = battle_config.guild_skills_separed_delay ? skillnum - GD_SKILLBASE : 0;
	if( bg == NULL || bg->g == NULL || idx < 0 || idx >= MAX_GUILDSKILL || bg->skill_block_timer[idx] == INVALID_TIMER )
		return;

	if( (td = get_timer(bg->skill_block_timer[idx])) == NULL )
		return;

	seconds = DIFF_TICK(td->tick,gettick())/1000;
	sprintf(output, "%s : Cannot use team skill %s. %d seconds remaining...", bg->g->name, skill_get_desc(skillnum), seconds);
	clif_bg_message(bg, bg->bg_id, bg->g->name, output, strlen(output) + 1);
}
Beispiel #13
0
/**
* Attempt to send mail
* @param sd Sender
* @param dest_name Destination name
* @param title Mail title
* @param body_msg Mail message
* @param body_len Message's length
*/
void mail_send(struct map_session_data *sd, const char *dest_name, const char *title, const char *body_msg, int body_len) {
	struct mail_message msg;

	nullpo_retv(sd);

	if( sd->state.trading )
		return;

	if( DIFF_TICK(sd->cansendmail_tick, gettick()) > 0 ) {
		clif_displaymessage(sd->fd,msg_txt(sd,675)); //"Cannot send mails too fast!!."
		clif_Mail_send(sd->fd, true); // fail
		return;
	}

	if( body_len > MAIL_BODY_LENGTH )
		body_len = MAIL_BODY_LENGTH;

	if( !mail_setattachment(sd, &msg) ) { // Invalid Append condition
		clif_Mail_send(sd->fd, true); // fail
		mail_removeitem(sd,0);
		mail_removezeny(sd,0);
		return;
	}

	msg.id = 0; // id will be assigned by charserver
	msg.send_id = sd->status.char_id;
	msg.dest_id = 0; // will attempt to resolve name
	safestrncpy(msg.send_name, sd->status.name, NAME_LENGTH);
	safestrncpy(msg.dest_name, (char*)dest_name, NAME_LENGTH);
	safestrncpy(msg.title, (char*)title, MAIL_TITLE_LENGTH);

	if (msg.title[0] == '\0') {
		return; // Message has no length and somehow client verification was skipped.
	}

	if (body_len)
		safestrncpy(msg.body, (char*)body_msg, body_len + 1);
	else
		memset(msg.body, 0x00, MAIL_BODY_LENGTH);

	msg.timestamp = time(NULL);
	if( !intif_Mail_send(sd->status.account_id, &msg) )
		mail_deliveryfail(sd, &msg);

	sd->cansendmail_tick = gettick() + battle_config.mail_delay; // Flood Protection
}
Beispiel #14
0
/**
 * Format message from player to send to the channel
 * - Also truncate extra characters if message is too long
 * @param channel: Channel data
 * @param sd: Player data
 * @param msg: Message to send
 * @return
 *  0: Success
 * -1: Invalid player, channel, or message
 * -2: Delay message from last message
 */
int channel_send(struct Channel *channel, struct map_session_data *sd, const char *msg) {
	int idx = 0;

	if(!channel || !sd || !msg || (idx = channel_pc_haschan(sd, channel)) < 0)
		return -1;

	if(!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && channel->msg_delay != 0 && DIFF_TICK(sd->channel_tick[idx] + channel->msg_delay, gettick()) > 0) {
		clif_messagecolor(&sd->bl,color_table[COLOR_RED],msg_txt(sd,1455),false,SELF); //You're talking too fast!
		return -2;
	}
	else {
		char output[CHAT_SIZE_MAX];
		unsigned long color = channel->color;
		if((channel->opt&CHAN_OPT_COLOR_OVERRIDE) && sd->fontcolor && sd->fontcolor < channel_config.colors_count && channel_config.colors[sd->fontcolor])
			color = channel_config.colors[sd->fontcolor];
		safesnprintf(output, CHAT_SIZE_MAX, "%s %s : %s", channel->alias, sd->status.name, msg);
		clif_channel_msg(channel,output,color);
		sd->channel_tick[idx] = gettick();
	}
	return 0;
}
Beispiel #15
0
/**
 * This can still happen (client times out while waiting for char to confirm auth data)
 * @see DBApply
 */
int auth_db_cleanup_sub(DBKey key, DBData *data, va_list ap) {
	struct auth_node *node = DB->data2ptr(data);
	const char* states[] = { "Login", "Logout", "Map change" };
	
	if(DIFF_TICK(gettick(),node->node_created)>60000) {
		switch (node->state) {
			case ST_LOGOUT:
				//Re-save attempt (->sd should never be null here).
				node->node_created = gettick(); //Refresh tick (avoid char-server load if connection is really bad)
				chrif_save(node->sd, 1);
				break;
			default:
				//Clear data. any connected players should have timed out by now.
				ShowInfo("auth_db: Node (state %s) timed out for %d:%d\n", states[node->state], node->account_id, node->char_id);
				chrif_char_offline_nsd(node->account_id, node->char_id);
				chrif_auth_delete(node->account_id, node->char_id, node->state);
				break;
		}
		return 1;
	}
	return 0;
}
Beispiel #16
0
/*===============================================================
 * Action that elemental perform after changing mode.
 * Activates one of the skills of the new mode.
 *-------------------------------------------------------------*/
int elemental_change_mode_ack(struct elemental_data *ed, int mode)
{
	struct block_list *bl = &ed->master->bl;
	short skillnum, skilllv;
	int i;

	nullpo_ret(ed);
	
	if( !bl )
		return 0;

	// Select a skill.
	ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&mode));
	if( i == MAX_ELESKILLTREE )
		return 0;

	skillnum = ed->db->skill[i].id;
	skilllv = ed->db->skill[i].lv;

	if( elemental_skillnotok(skillnum, ed) )
		return 0;

	if( ed->ud.skilltimer != -1 )
		return 0;
	else if( DIFF_TICK(gettick(), ed->ud.canact_tick) < 0 )
		return 0;

	ed->target_id = bl->id;	// Set new target
	ed->last_thinktime = gettick();
	
	if( skill_get_inf(skillnum) & INF_GROUND_SKILL )
		unit_skilluse_pos(&ed->bl, bl->x, bl->y, skillnum, skilllv);
	else
		unit_skilluse_id(&ed->bl,bl->id,skillnum,skilllv);
	
	ed->target_id = 0;	// Reset target after casting the skill  to avoid continious attack.

	return 1;
}
Beispiel #17
0
//This can still happen (client times out while waiting for char to confirm auth data)
int auth_db_cleanup_sub(DBKey key,void *data,va_list ap)
{
	struct auth_node *node=(struct auth_node*)data;
	const char* states[] = { "Iniciar Sessao", "Encerrar Sessao", "Mudanca de Mapa" };
	if(DIFF_TICK(gettick(),node->node_created)>60000) {
		switch (node->state)
		{
		case ST_LOGOUT:
			//Re-save attempt (->sd should never be null here).
			node->node_created = gettick(); //Refresh tick (avoid char-server load if connection is really bad)
			chrif_save(node->sd, 1);
			break;
		default:
			//Clear data. any connected players should have timed out by now.
			ShowInfo("auth_db: No (estado %s) tempo esgotado para %d:%d\n", states[node->state], node->account_id, node->char_id);
			chrif_char_offline_nsd(node->account_id, node->char_id);
			chrif_auth_delete(node->account_id, node->char_id, node->state);
			break;
		}
		return 1;
	}
	return 0;
}
Beispiel #18
0
int bg_team_join(int bg_id, struct map_session_data *sd)
{ // Player joins team
	int i;
	struct battleground_data *bg = bg_team_search(bg_id);
	struct map_session_data *pl_sd;

	if( bg == NULL || sd == NULL || sd->bg_id ) return 0;

	ARR_FIND(0, MAX_BG_MEMBERS, i, bg->members[i].sd == NULL);
	if( i == MAX_BG_MEMBERS ) return 0; // No free slots

	pc_update_last_action(sd,0); // Start count from here...
	sd->bg_id = bg_id;
	sd->bg_kills = 0;
	sd->state.bg_afk = 0;
	bg->members[i].sd = sd;
	bg->members[i].x = sd->bl.x;
	bg->members[i].y = sd->bl.y;
	bg->count++;

	if( bg->creation_tick == 0 ) bg->creation_tick = last_tick; // Creation Tick = First member joined.

	if( bg->leader_char_id == 0 )
	{ // First Join = Team Leader
		bg->leader_char_id = sd->status.char_id;
		sd->bmaster_flag = bg;
	}

	if( battle_config.bg_ranked_mode && sd->status.bgstats.rank_games < battle_config.bg_ranked_max_games && DIFF_TICK(last_tick,bg->creation_tick) < 60 )
	{
		char output[128];
		bg->members[i].ranked = true;
		sd->status.bgstats.rank_games++;
		sprintf(output,"-- RANKED BATTLEGROUND MATCH %d OF %d --", sd->status.bgstats.rank_games, battle_config.bg_ranked_max_games);
		clif_displaymessage(sd->fd,output);
	}

	guild_send_dot_remove(sd);
	if( battle_config.bg_eAmod_mode )
	{
		clif_bg_belonginfo(sd);
		clif_charnameupdate(sd);
	}

	for( i = 0; i < MAX_BG_MEMBERS; i++ )
	{
		if( (pl_sd = bg->members[i].sd) == NULL )
			continue;

		if( battle_config.bg_eAmod_mode )
		{ // Simulate Guild Information
			clif_guild_basicinfo(pl_sd);
			clif_bg_emblem(pl_sd, bg->g);
			clif_bg_memberlist(pl_sd);
		}

		if( pl_sd != sd )
			clif_bg_hp_single(sd->fd,pl_sd);
	}

	if( battle_config.bg_eAmod_mode ) clif_guild_emblem_area(&sd->bl);
	clif_bg_hp(sd);
	clif_bg_xy(sd);
	return 1;
}
Beispiel #19
0
/*==========================================
 *
 *------------------------------------------*/
int chrif_parse(int fd) {
	int packet_len, cmd;

	// only process data from the char-server
	if ( fd != char_fd ) {
		ShowDebug("chrif_parse: Disconnecting invalid session #%d (is not the char-server)\n", fd);
		do_close(fd);
		return 0;
	}

	if ( session[fd]->flag.eof ) {
		do_close(fd);
		char_fd = -1;
		chrif_on_disconnect();
		return 0;
	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
			set_eof(fd);
			return 0;
		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
			chrif_keepalive(fd);
			session[fd]->flag.ping = 2;
		}
	}

	while ( RFIFOREST(fd) >= 2 ) {
		cmd = RFIFOW(fd,0);
		if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) {
			int r = intif_parse(fd); // Passed on to the intif

			if (r == 1) continue;	// Treated in intif 
			if (r == 2) return 0;	// Didn't have enough data (len==-1)

			ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd);
			set_eof(fd);
			return 0;
		}

		if ( ( packet_len = packet_len_table[cmd-0x2af8] ) == -1) { // dynamic-length packet, second WORD holds the length
			if (RFIFOREST(fd) < 4)
				return 0;
			packet_len = RFIFOW(fd,2);
		}

		if ((int)RFIFOREST(fd) < packet_len)
			return 0;

		//ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd);

		switch(cmd) {
			case 0x2af9: chrif_connectack(fd); break;
			case 0x2afb: chrif_sendmapack(fd); break;
			case 0x2afd: chrif_authok(fd); break;
			case 0x2b00: map_setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break;
			case 0x2b03: clif->charselectok(RFIFOL(fd,2), RFIFOB(fd,6)); break;
			case 0x2b04: chrif_recvmap(fd); break;
			case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break;
			case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
			case 0x2b0a: socket_datasync(fd, false); break;
			case 0x2b0d: chrif_changedsex(fd); break;
			case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break;
			case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break;
			case 0x2b14: chrif_accountban(fd); break;
			case 0x2b1b: chrif_recvfamelist(fd); break;
			case 0x2b1d: chrif_load_scdata(fd); break;
			case 0x2b1e: chrif_update_ip(fd); break;
			case 0x2b1f: chrif_disconnectplayer(fd); break;
			case 0x2b20: chrif_removemap(fd); break;
			case 0x2b21: chrif_save_ack(fd); break;
			case 0x2b22: chrif_updatefamelist_ack(fd); break;
			case 0x2b24: chrif_keepalive_ack(fd); break;
			case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
			case 0x2b27: chrif_authfail(fd); break;
			default:
				ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);
				set_eof(fd);
				return 0;
		}
		if ( fd == char_fd ) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex]
			RFIFOSKIP(fd, packet_len);
	}

	return 0;
}
Beispiel #20
0
static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_data *sd, unsigned int tick)
{
	struct block_list *target = NULL;
	int master_dist, view_range, mode;

	nullpo_ret(ed);
	nullpo_ret(sd);

	if( ed->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL )
		return 0;

	if( DIFF_TICK(tick,ed->last_thinktime) < MIN_ELETHINKTIME )
		return 0;

	ed->last_thinktime = tick;

	if( ed->ud.skilltimer != -1 )
		return 0;

	if( ed->ud.walktimer != -1 && ed->ud.walkpath.path_pos <= 2 )
		return 0; //No thinking when you just started to walk.
	
	if(ed->ud.walkpath.path_pos < ed->ud.walkpath.path_len && ed->ud.target == sd->bl.id)
		return 0; //No thinking until be near the master.

	if( ed->sc.count && ed->sc.data[SC_BLIND] )
		view_range = 3;
	else
		view_range = ed->db->range2;

	mode = status_get_mode(&ed->bl);
	
	master_dist = distance_bl(&sd->bl, &ed->bl);
	if( master_dist > AREA_SIZE )
	{	// Master out of vision range.
		elemental_unlocktarget(ed);
		unit_warp(&ed->bl,sd->bl.m,sd->bl.x,sd->bl.y,3);
		return 0;
	}
	else if( master_dist > MAX_ELEDISTANCE )
	{	// Master too far, chase.
		short x = sd->bl.x, y = sd->bl.y;
		if( ed->target_id )
			elemental_unlocktarget(ed);
		if( ed->ud.walktimer != -1 && ed->ud.target == sd->bl.id )
			return 0; //Already walking to him
		if( DIFF_TICK(tick, ed->ud.canmove_tick) < 0 )
			return 0; //Can't move yet.
		if( map_search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1) 
			&& unit_walktoxy(&ed->bl, x, y, 0) )
		return 0;
	}
	
	if( mode == EL_MODE_AGGRESSIVE )
	{
		target = map_id2bl(ed->ud.target);

		if( !target )
			map_foreachinrange(elemental_ai_sub_timer_activesearch, &ed->bl, ed->db->range2, BL_CHAR, ed, &target, status_get_mode(&ed->bl));

		if( !target )
		{ //No targets available.
			elemental_unlocktarget(ed);
			return 1;
		}
		
		if( battle_check_range(&ed->bl,target,ed->db->range2) && rand()%100 < 2 ) // 2% chance to cast attack skill.
		{
			if(	elemental_action(ed,target,tick) )
				return 1;
		}
	
		//Attempt to attack.
		//At this point we know the target is attackable, we just gotta check if the range matches.
		if( ed->ud.target == target->id && ed->ud.attacktimer != -1 ) //Already locked.
			return 1;
	
		if( battle_check_range(&ed->bl, target, ed->base_status.rhw.range) )
		{	//Target within range, engage
			unit_attack(&ed->bl,target->id,1);
			return 1;
		}

		//Follow up if possible.
		if( !unit_walktobl(&ed->bl, target, ed->base_status.rhw.range, 2) )
			elemental_unlocktarget(ed);
	}

	return 0;
}
Beispiel #21
0
int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned int tick)
{
	short skillnum, skilllv;
	int i;

	nullpo_ret(ed);
	nullpo_ret(bl);

	if( !ed->master )
		return 0;

	if( ed->target_id )
		elemental_unlocktarget(ed);	// Remove previous target.
	
	ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&EL_SKILLMODE_AGGRESSIVE));
	if( i == MAX_ELESKILLTREE )
		return 0;
	
	skillnum = ed->db->skill[i].id;
	skilllv = ed->db->skill[i].lv;

	if( elemental_skillnotok(skillnum, ed) )
		return 0;

	if( ed->ud.skilltimer != -1 )
		return 0;
	else if( DIFF_TICK(tick, ed->ud.canact_tick) < 0 )
		return 0;

	ed->target_id = ed->ud.skilltarget = bl->id;	// Set new target
	ed->last_thinktime = tick;

	// Not in skill range.
	if( !battle_check_range(&ed->bl,bl,skill_get_range(skillnum,skilllv)) )
	{
		// Try to walk to the target.
		if( !unit_walktobl(&ed->bl, bl, skill_get_range(skillnum,skilllv), 2) )
			elemental_unlocktarget(ed);
		else
		{
			// Walking, waiting to be in range. Client don't handle it, then we must handle it here.
			int walk_dist = distance_bl(&ed->bl,bl) - skill_get_range(skillnum,skilllv);
			ed->ud.skillid = skillnum;
			ed->ud.skilllv = skilllv;

			if( skill_get_inf(skillnum) & INF_GROUND_SKILL )
				ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_pos, ed->bl.id, 0 );
			else
				ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_id, ed->bl.id, 0 );
		}
		return 1;

	}
	//Otherwise, just cast the skill.
	if( skill_get_inf(skillnum) & INF_GROUND_SKILL )
		unit_skilluse_pos(&ed->bl, bl->x, bl->y, skillnum, skilllv);
	else
		unit_skilluse_id(&ed->bl, bl->id, skillnum, skilllv);

	// Reset target.
	ed->target_id = 0;

	return 1;
}
int chlogif_parse(int fd) {
	struct char_session_data* sd = NULL;

	// only process data from the login-server
	if( fd != login_fd ) {
		ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd);
		do_close(fd);
		return 0;
	}

	if( session[fd]->flag.eof ) {
		do_close(fd);
		login_fd = -1;
		chlogif_on_disconnect();
		return 0;
	} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
		if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
			set_eof(fd);
			return 0;
		} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
			WFIFOHEAD(fd,2);// sends a ping packet to login server (will receive pong 0x2718)
			WFIFOW(fd,0) = 0x2719;
			WFIFOSET(fd,2);

			session[fd]->flag.ping = 2;
		}
	}

	sd = (struct char_session_data*)session[fd]->session_data;

	while(RFIFOREST(fd) >= 2) {
		int next=1;
		uint16 command = RFIFOW(fd,0);
		switch( command )
		{
			case 0x2741: next = chlogif_parse_BankingAck(fd); break;
			case 0x2743: next = chlogif_parse_vipack(fd); break;
			// acknowledgement of connect-to-loginserver request
			case 0x2711: next = chlogif_parse_ackconnect(fd,sd); break;
			// acknowledgement of account authentication request
			case 0x2713: next = chlogif_parse_ackaccreq(fd, sd); break;
			// account data
			case 0x2717: next = chlogif_parse_reqaccdata(fd, sd); break;
			// login-server alive packet
			case 0x2718: next = chlogif_parse_keepalive(fd, sd); break;
			// changesex reply
			case 0x2723: next = chlogif_parse_ackchangesex(fd, sd); break;
			// reply to an account_reg2 registry request
			case 0x2729: next = chlogif_parse_ackacc2req(fd, sd); break;
			// State change of account/ban notification (from login-server)
			case 0x2731: next = chlogif_parse_accbannotification(fd, sd); break;
			// Login server request to kick a character out. [Skotlex]
			case 0x2734: next = chlogif_parse_askkick(fd,sd); break;
			// ip address update signal from login server
			case 0x2735: next = chlogif_parse_updip(fd,sd); break;
			// @accinfo result
			case 0x2721: next = chlogif_parse_AccInfoAck(fd); break;
			default:
				ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
				set_eof(fd);
				return 0;
		}
		if(next==0) return 0; //do not parse next data
	}

	RFIFOFLUSH(fd);
	return 0;
}
Beispiel #23
0
int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned int tick) {
	struct skill_condition req;
	uint16 skill_id, skill_lv;
	int i;

	nullpo_ret(ed);
	nullpo_ret(bl);

	if( !ed->master )
		return 0;

	if( ed->target_id )
		elemental_unlocktarget(ed);	// Remove previous target.

	ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&EL_SKILLMODE_AGGRESSIVE));
	if( i == MAX_ELESKILLTREE )
		return 0;

	skill_id = ed->db->skill[i].id;
	skill_lv = ed->db->skill[i].lv;

	if( elemental_skillnotok(skill_id, ed) )
		return 0;

	if( ed->ud.skilltimer != INVALID_TIMER )
		return 0;
	else if( DIFF_TICK(tick, ed->ud.canact_tick) < 0 )
		return 0;

	ed->target_id = ed->ud.skilltarget = bl->id;	// Set new target
	ed->last_thinktime = tick;

	// Not in skill range.
	if( !battle_check_range(&ed->bl,bl,skill_get_range(skill_id,skill_lv)) ) {
		// Try to walk to the target.
		if( !unit_walktobl(&ed->bl, bl, skill_get_range(skill_id,skill_lv), 2) )
			elemental_unlocktarget(ed);
		else {
			// Walking, waiting to be in range. Client don't handle it, then we must handle it here.
			int walk_dist = distance_bl(&ed->bl,bl) - skill_get_range(skill_id,skill_lv);
			ed->ud.skill_id = skill_id;
			ed->ud.skill_lv = skill_lv;

			if( skill_get_inf(skill_id) & INF_GROUND_SKILL )
				ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_pos, ed->bl.id, 0 );
			else
				ed->ud.skilltimer = add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill_castend_id, ed->bl.id, 0 );
		}
		return 1;

	}

	req = elemental_skill_get_requirements(skill_id, skill_lv);

	if(req.hp || req.sp){
		struct map_session_data *sd = BL_CAST(BL_PC, battle_get_master(&ed->bl));
		if( sd ){
			if( sd->skill_id_old != SO_EL_ACTION && //regardless of remaining HP/SP it can be cast
				(status_get_hp(&ed->bl) < req.hp || status_get_sp(&ed->bl) < req.sp) )
				return 1;
			else
				status_zap(&ed->bl, req.hp, req.sp);
		}
	}

	//Otherwise, just cast the skill.
	if( skill_get_inf(skill_id) & INF_GROUND_SKILL )
		unit_skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv);
	else
		unit_skilluse_id(&ed->bl, bl->id, skill_id, skill_lv);

	// Reset target.
	ed->target_id = 0;

	return 1;
}
Beispiel #24
0
/**
* Attempt to send mail
* @param sd Sender
* @param dest_name Destination name
* @param title Mail title
* @param body_msg Mail message
* @param body_len Message's length
*/
void mail_send(struct map_session_data *sd, const char *dest_name, const char *title, const char *body_msg, int body_len) {
	struct mail_message msg;

	nullpo_retv(sd);

	if( sd->state.trading )
		return;

	if( DIFF_TICK(sd->cansendmail_tick, gettick()) > 0 ) {
		clif_displaymessage(sd->fd,msg_txt(sd,675)); //"Cannot send mails too fast!!."
		clif_Mail_send(sd, WRITE_MAIL_FAILED); // fail
		return;
	}

	if( battle_config.mail_daily_count ){
		mail_refresh_remaining_amount(sd);

		// After calling mail_refresh_remaining_amount the status should always be there
		if( sd->sc.data[SC_DAILYSENDMAILCNT] == NULL || sd->sc.data[SC_DAILYSENDMAILCNT]->val2 >= battle_config.mail_daily_count ){
			clif_Mail_send(sd, WRITE_MAIL_FAILED_CNT);
			return;
		}else{
			sc_start2( &sd->bl, &sd->bl, SC_DAILYSENDMAILCNT, 100, date_get_dayofyear(), sd->sc.data[SC_DAILYSENDMAILCNT]->val2 + 1, -1 );
		}
	}

	if( body_len > MAIL_BODY_LENGTH )
		body_len = MAIL_BODY_LENGTH;

	if( !mail_setattachment(sd, &msg) ) { // Invalid Append condition
		int i;

		clif_Mail_send(sd, WRITE_MAIL_FAILED); // fail
		for( i = 0; i < MAIL_MAX_ITEM; i++ ){
			mail_removeitem(sd,0,sd->mail.item[i].index + 2, sd->mail.item[i].amount);
		}
		mail_removezeny(sd,false);
		return;
	}

	msg.id = 0; // id will be assigned by charserver
	msg.send_id = sd->status.char_id;
	msg.dest_id = 0; // will attempt to resolve name
	safestrncpy(msg.send_name, sd->status.name, NAME_LENGTH);
	safestrncpy(msg.dest_name, (char*)dest_name, NAME_LENGTH);
	safestrncpy(msg.title, (char*)title, MAIL_TITLE_LENGTH);
	msg.type = MAIL_INBOX_NORMAL;

	if (msg.title[0] == '\0') {
		return; // Message has no length and somehow client verification was skipped.
	}

	if (body_len)
		safestrncpy(msg.body, (char*)body_msg, body_len + 1);
	else
		memset(msg.body, 0x00, MAIL_BODY_LENGTH);

	msg.timestamp = time(NULL);
	if( !intif_Mail_send(sd->status.account_id, &msg) )
		mail_deliveryfail(sd, &msg);

	sd->cansendmail_tick = gettick() + battle_config.mail_delay; // Flood Protection
}
Beispiel #25
0
static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_data *sd, unsigned int tick) {
	struct block_list *target = NULL;
	int master_dist, view_range, mode;

	nullpo_ret(ed);
	nullpo_ret(sd);

	if( ed->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL )
		return 0;

	// Check if caster can sustain the summoned elemental
	if( DIFF_TICK(tick,ed->last_spdrain_time) >= 10000 ){// Drain SP every 10 seconds
		int sp = 5;

		switch(ed->vd->class_){
			case ELEMENTALID_AGNI_M:	case ELEMENTALID_AQUA_M:
			case ELEMENTALID_VENTUS_M:	case ELEMENTALID_TERA_M:
				sp = 8;
				break;
			case ELEMENTALID_AGNI_L:	case ELEMENTALID_AQUA_L:
			case ELEMENTALID_VENTUS_L:	case ELEMENTALID_TERA_L:
				sp = 11;
				break;
		}

		if( status_get_sp(&sd->bl) < sp ){ // Can't sustain delete it.
			elemental_delete(sd->ed,0);
			return 0;
		}

		status_zap(&sd->bl,0,sp);
		ed->last_spdrain_time = tick;
	}

	if( DIFF_TICK(tick,ed->last_thinktime) < MIN_ELETHINKTIME )
		return 0;

	ed->last_thinktime = tick;

	if( ed->ud.skilltimer != INVALID_TIMER )
		return 0;

	if( ed->ud.walktimer != INVALID_TIMER && ed->ud.walkpath.path_pos <= 2 )
		return 0; //No thinking when you just started to walk.

	if(ed->ud.walkpath.path_pos < ed->ud.walkpath.path_len && ed->ud.target == sd->bl.id)
		return 0; //No thinking until be near the master.

	if( ed->sc.count && ed->sc.data[SC_BLIND] )
		view_range = 3;
	else
		view_range = ed->db->range2;

	mode = status_get_mode(&ed->bl);

	master_dist = distance_bl(&sd->bl, &ed->bl);
	if( master_dist > AREA_SIZE ) {	// Master out of vision range.
		elemental_unlocktarget(ed);
		unit_warp(&ed->bl,sd->bl.m,sd->bl.x,sd->bl.y,CLR_TELEPORT);
		clif_elemental_updatestatus(sd,SP_HP);
		clif_elemental_updatestatus(sd,SP_SP);
		return 0;
	} else if( master_dist > MAX_ELEDISTANCE ) {	// Master too far, chase.
		short x = sd->bl.x, y = sd->bl.y;
		if( ed->target_id )
			elemental_unlocktarget(ed);
		if( ed->ud.walktimer != INVALID_TIMER && ed->ud.target == sd->bl.id )
			return 0; //Already walking to him
		if( DIFF_TICK(tick, ed->ud.canmove_tick) < 0 )
			return 0; //Can't move yet.
		if( map_search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1)
		   && unit_walktoxy(&ed->bl, x, y, 0) )
			return 0;
	}

	if( mode == EL_MODE_AGGRESSIVE ) {
		target = map_id2bl(ed->ud.target);

		if( !target )
			map_foreachinrange(elemental_ai_sub_timer_activesearch, &ed->bl, view_range, BL_CHAR, ed, &target, status_get_mode(&ed->bl));

		if( !target ) { //No targets available.
			elemental_unlocktarget(ed);
			return 1;
		}

		if( battle_check_range(&ed->bl,target,view_range) && rnd()%100 < 2 ) { // 2% chance to cast attack skill.
			if(	elemental_action(ed,target,tick) )
				return 1;
		}

		//Attempt to attack.
		//At this point we know the target is attackable, we just gotta check if the range matches.
		if( ed->ud.target == target->id && ed->ud.attacktimer != INVALID_TIMER ) //Already locked.
			return 1;

		if( battle_check_range(&ed->bl, target, ed->base_status.rhw.range) ) {//Target within range, engage
			unit_attack(&ed->bl,target->id,1);
			return 1;
		}

		//Follow up if possible.
		if( !unit_walktobl(&ed->bl, target, ed->base_status.rhw.range, 2) )
			elemental_unlocktarget(ed);
	}

	return 0;
}
Beispiel #26
0
int do_timer(unsigned int tick)
{
	int i,nextmin=1000;

#if 0
	static int disp_tick=0;
	if(DIFF_TICK(disp_tick,tick)<-5000 || DIFF_TICK(disp_tick,tick)>5000){
		printf("timer %d(%d+%d)\n",timer_data_num,timer_heap[0],free_timer_list_pos);
		disp_tick=tick;
	}
#endif

	while((i=top_timer_heap())>=0){
		if(DIFF_TICK(timer_data[i].tick , tick)>0){
			nextmin=DIFF_TICK(timer_data[i].tick , tick);
			break;
		}
		pop_timer_heap();
		timer_data[i].type |= TIMER_REMOVE_HEAP;
		if(timer_data[i].func){
			if(DIFF_TICK(timer_data[i].tick , tick) < -1000){
				// 1秒以上の大幅な遅延が発生しているので、
				// timer処理タイミングを現在値とする事で
				// 呼び出し時タイミング(引数のtick)相対で処理してる
				// timer関数の次回処理タイミングを遅らせる
				timer_data[i].func(i,tick,timer_data[i].id,timer_data[i].data);
			} else {
				timer_data[i].func(i,timer_data[i].tick,timer_data[i].id,timer_data[i].data);
			}
		}
		if(timer_data[i].type&TIMER_REMOVE_HEAP){
			switch(timer_data[i].type & ~TIMER_REMOVE_HEAP){
			case TIMER_ONCE_AUTODEL:
				timer_data[i].type=0;
				if(free_timer_list_pos>=free_timer_list_max){
					free_timer_list_max+=256;
					free_timer_list=realloc(free_timer_list,free_timer_list_max*sizeof(free_timer_list[0]));
					if(free_timer_list==NULL){
						printf("out of memory : do_timer\n");
						exit(1);
					}
				}
				free_timer_list[free_timer_list_pos++]=i;
				break;
			case TIMER_INTERVAL:
				if(DIFF_TICK(timer_data[i].tick , tick) < -1000){
					timer_data[i].tick = tick+timer_data[i].interval;
				} else {
					timer_data[i].tick += timer_data[i].interval;
				}
				timer_data[i].type &= ~TIMER_REMOVE_HEAP;
				push_timer_heap(i);
				break;
			}
		}
	}

	if(nextmin<10)
		nextmin=10;
	return nextmin;
}