From 620e60eebce2c1f35c5c9a82f6ca365b316587f5 Mon Sep 17 00:00:00 2001 From: Valaris Date: Sun, 29 Jan 2006 16:10:48 +0000 Subject: AS OF SVN REV. 5901, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. EVERYTHING ELSE GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5094 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/guild.c | 1976 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1976 insertions(+) create mode 100644 src/map/guild.c (limited to 'src/map/guild.c') diff --git a/src/map/guild.c b/src/map/guild.c new file mode 100644 index 000000000..9a12b0425 --- /dev/null +++ b/src/map/guild.c @@ -0,0 +1,1976 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include +#include +#include + +#include "map.h" +#include "guild.h" +#include "storage.h" +#include "timer.h" +#include "socket.h" +#include "nullpo.h" +#include "malloc.h" +#include "battle.h" +#include "npc.h" +#include "pc.h" +#include "status.h" +#include "mob.h" +#include "intif.h" +#include "clif.h" +#include "skill.h" +#include "showmsg.h" +#include "log.h" + +static struct guild* guild_cache; //For fast retrieval of the same guild over and over. [Skotlex] +static struct dbt *guild_db; +static struct dbt *castle_db; +static struct dbt *guild_expcache_db; +static struct dbt *guild_infoevent_db; +static struct dbt *guild_castleinfoevent_db; + +struct eventlist { + char name[50]; + struct eventlist *next; +}; + +// ギルドのEXPキャッシュのフラッシュに関連する定数 +#define GUILD_SEND_XY_INVERVAL 5000 // 座標やHP送信の間隔 +#define GUILD_PAYEXP_INVERVAL 10000 // 間隔(キャッシュの最大生存時間、ミリ秒) +#define GUILD_PAYEXP_LIST 8192 // キャッシュの最大数 + +// ギルドのEXPキャッシュ +struct guild_expcache { + int guild_id, account_id, char_id, exp; +}; + +struct{ + int id; + int max; + struct{ + short id; + short lv; + }need[6]; +} guild_skill_tree[MAX_GUILDSKILL]; + +// timer for auto saving guild data during WoE +#define GUILD_SAVE_INTERVAL 300000 +int guild_save_timer = -1; + +int guild_payexp_timer(int tid,unsigned int tick,int id,int data); +int guild_gvg_eliminate_timer(int tid,unsigned int tick,int id,int data); +int guild_save_sub(int tid,unsigned int tick,int id,int data); +static int guild_send_xy_timer(int tid,unsigned int tick,int id,int data); + +// ギルドスキルdbのアクセサ(今は直打ちで代用) +// Modified for new skills [Sara] +int guild_skill_get_inf(int id) +{ + switch(id) { + case GD_BATTLEORDER: + case GD_REGENERATION: + case GD_RESTORE: + case GD_EMERGENCYCALL: + return 4; + } + return 0; +} + + // Modified [Komurka] +int guild_skill_get_max (int id) +{ + if (id < GD_SKILLBASE || id > GD_SKILLBASE+MAX_GUILDSKILL) + return 0; + return guild_skill_tree[id-GD_SKILLBASE].max; +} + +// ギルドスキルがあるか確認 +int guild_checkskill(struct guild *g,int id) +{ + int idx = id-GD_SKILLBASE; + if (idx < 0 || idx >= MAX_GUILDSKILL) + return 0; + return g->skill[idx].lv; +} + +/*========================================== + * guild_skill_tree.txt reading - from jA [Komurka] + *------------------------------------------ + */ +int guild_read_guildskill_tree_db(void) +{ + int i,k,id=0,ln=0; + FILE *fp; + char line[1024],*p; + + memset(guild_skill_tree,0,sizeof(guild_skill_tree)); + sprintf(line, "%s/guild_skill_tree.txt", db_path); + if( (fp=fopen(line,"r"))==NULL){ + ShowError("can't read %s\n", line); + return -1; + } + while(fgets(line,1020,fp)){ + char *split[50]; + if(line[0]=='/' && line[1]=='/') + continue; + for(i=0,p=line;i<12 && p;i++){ + split[i]=p; + p=strchr(p,','); + if(p) *p++=0; + } + if(i<12) + continue; + id = atoi(split[0]) - GD_SKILLBASE; + if(id<0 || id>=MAX_GUILDSKILL) + continue; + guild_skill_tree[id].id=atoi(split[0]); + guild_skill_tree[id].max=atoi(split[1]); + if (guild_skill_tree[id].id==GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[id].max==0) guild_skill_tree[id].max=1; + for(k=0;k<5;k++){ + guild_skill_tree[id].need[k].id=atoi(split[k*2+2]); + guild_skill_tree[id].need[k].lv=atoi(split[k*2+3]); + } + ln++; + } + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"guild_skill_tree.txt"); + + return 0; +} + +/*========================================== + * Guild skill check - from jA [Komurka] + *------------------------------------------ + */ +int guild_check_skill_require(struct guild *g,int id) +{ + int i; + int idx = id-GD_SKILLBASE; + + if(g == NULL) + return 0; + + if (idx < 0 || idx >= MAX_GUILDSKILL) + return 0; + + for(i=0;i<5;i++) + { + if(guild_skill_tree[idx].need[i].id == 0) break; + if(guild_skill_tree[idx].need[i].lv > guild_checkskill(g,guild_skill_tree[idx].need[i].id)) + return 0; + } + return 1; +} + +static int guild_read_castledb(void) +{ + FILE *fp; + char line[1024]; + int j,ln=0; + char *str[32],*p; + struct guild_castle *gc; + + sprintf(line, "%s/castle_db.txt", db_path); + if( (fp=fopen(line,"r"))==NULL){ + ShowError("can't read %s\n", line); + return -1; + } + + while(fgets(line,1020,fp)){ + if(line[0]=='/' && line[1]=='/') + continue; + memset(str,0,sizeof(str)); + for(j=0,p=line;j<6 && p;j++){ + str[j]=p; + p=strchr(p,','); + if(p) *p++=0; + } + if (j < 4) //Insufficient data for castle. [Skotlex] + { + ShowError("castle_db.txt: invalid line '%s'\n", line); + continue; + } + + gc=(struct guild_castle *)aCalloc(1,sizeof(struct guild_castle)); + gc->castle_id=atoi(str[0]); + memcpy(gc->map_name,str[1],MAP_NAME_LENGTH-1); + memcpy(gc->castle_name,str[2],NAME_LENGTH-1); + memcpy(gc->castle_event,str[3],NAME_LENGTH-1); + + idb_put(castle_db,gc->castle_id,gc); + + //intif_guild_castle_info(gc->castle_id); + + ln++; + } + fclose(fp); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"castle_db.txt"); + return 0; +} + +// 初期化 +void do_init_guild(void) +{ + guild_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); + castle_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); + guild_expcache_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); + guild_infoevent_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int)); + guild_castleinfoevent_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int)); + + guild_read_castledb(); + + guild_read_guildskill_tree_db(); //guild skill tree [Komurka] + + add_timer_func_list(guild_gvg_eliminate_timer,"guild_gvg_eliminate_timer"); + add_timer_func_list(guild_payexp_timer,"guild_payexp_timer"); + add_timer_func_list(guild_save_sub, "guild_save_sub"); + add_timer_func_list(guild_send_xy_timer, "guild_send_xy_timer"); + add_timer_interval(gettick()+GUILD_PAYEXP_INVERVAL,guild_payexp_timer,0,0,GUILD_PAYEXP_INVERVAL); + add_timer_interval(gettick()+GUILD_SEND_XY_INVERVAL,guild_send_xy_timer,0,0,GUILD_SEND_XY_INVERVAL); +} + + +// 検索 +struct guild *guild_search(int guild_id) +{ + if(guild_cache && guild_cache->guild_id == guild_id) + return guild_cache; + guild_cache = idb_get(guild_db,guild_id); + return guild_cache; +} +int guild_searchname_sub(DBKey key,void *data,va_list ap) +{ + struct guild *g=(struct guild *)data,**dst; + char *str; + str=va_arg(ap,char *); + dst=va_arg(ap,struct guild **); + if(strcmpi(g->name,str)==0) + *dst=g; + return 0; +} +// ギルド名検索 +struct guild* guild_searchname(char *str) +{ + struct guild *g=NULL; + guild_db->foreach(guild_db,guild_searchname_sub,str,&g); + return g; +} +struct guild_castle *guild_castle_search(int gcid) +{ + return idb_get(castle_db,gcid); +} + +// mapnameに対応したアジトのgcを返す +struct guild_castle *guild_mapname2gc(char *mapname) +{ + int i; + struct guild_castle *gc=NULL; + for(i=0;imap_name,mapname)==0) return gc; + } + return NULL; +} + +struct guild_castle *guild_mapindex2gc(short mapname) +{ + int i; + struct guild_castle *gc=NULL; + for(i=0;imap_name,mapindex_id2name(mapname))==0) return gc; + } + return NULL; +} + + + +// ログイン中のギルドメンバーの1人のsdを返す +struct map_session_data *guild_getavailablesd(struct guild *g) +{ + int i; + + nullpo_retr(NULL, g); + + for(i=0;imax_member;i++) + if(g->member[i].sd!=NULL) + return g->member[i].sd; + return NULL; +} + +// ギルドメンバーのインデックスを返す +int guild_getindex(struct guild *g,int account_id,int char_id) +{ + int i; + if(g==NULL) + return -1; + for(i=0;imax_member;i++) + if( g->member[i].account_id==account_id && + g->member[i].char_id==char_id ) + return i; + return -1; +} +// ギルドメンバーの役職を返す +int guild_getposition(struct map_session_data *sd,struct guild *g) +{ + int i; + + nullpo_retr(-1, sd); + + if(g==NULL && (g=guild_search(sd->status.guild_id))==NULL) + return -1; + for(i=0;imax_member;i++) + if( g->member[i].account_id==sd->status.account_id && + g->member[i].char_id==sd->status.char_id ) + return g->member[i].position; + return -1; +} + +// メンバー情報の作成 +void guild_makemember(struct guild_member *m,struct map_session_data *sd) +{ + nullpo_retv(sd); + + memset(m,0,sizeof(struct guild_member)); + m->account_id =sd->status.account_id; + m->char_id =sd->status.char_id; + m->hair =sd->status.hair; + m->hair_color =sd->status.hair_color; + m->gender =sd->sex; + m->class_ =sd->status.class_; + m->lv =sd->status.base_level; +// m->exp =0; +// m->exp_payper =0; + m->online =1; + m->position =MAX_GUILDPOSITION-1; + memcpy(m->name,sd->status.name,NAME_LENGTH-1); + return; +} +// ギルド競合確認 +int guild_check_conflict(struct map_session_data *sd) +{ + nullpo_retr(0, sd); + + intif_guild_checkconflict(sd->status.guild_id, + sd->status.account_id,sd->status.char_id); + return 0; +} + +// ギルドのEXPキャッシュをinter鯖にフラッシュする +int guild_payexp_timer_sub(DBKey dataid, void *data, va_list ap) +{ + int i, *dellist, *delp; + struct guild_expcache *c; + struct guild *g; + double exp2; + + c = (struct guild_expcache *)data; + dellist = va_arg(ap,int *); + delp = va_arg(ap,int *); + + if (*delp >= GUILD_PAYEXP_LIST || + (g = guild_search(c->guild_id)) == NULL || + (i = guild_getindex(g, c->account_id, c->char_id)) < 0) + return 0; + + // It is *already* fixed... this would be more appropriate ^^; [celest] + exp2 = g->member[i].exp + c->exp; + g->member[i].exp = (exp2 > 0x7FFFFFFF) ? 0x7FFFFFFF : (int)exp2; + + //fixed a bug in exp overflow [Kevin] + //g->member[i].exp += c->exp; + //if(g->member[i].exp < 0) + //g->member[i].exp = 0x7FFFFFFF; + + intif_guild_change_memberinfo(g->guild_id,c->account_id,c->char_id, + GMI_EXP,&g->member[i].exp,sizeof(g->member[i].exp)); + c->exp=0; + + dellist[(*delp)++]=dataid.i; + return 0; +} + +int guild_payexp_timer(int tid, unsigned int tick, int id, int data) +{ + int dellist[GUILD_PAYEXP_LIST], delp = 0, i; + guild_expcache_db->foreach(guild_expcache_db, guild_payexp_timer_sub, dellist, &delp); + for (i = 0; i < delp; i++) + idb_remove(guild_expcache_db, dellist[i]); + return 0; +} + +//Taken from party_send_xy_timer_sub. [Skotlex] +int guild_send_xy_timer_sub(DBKey key,void *data,va_list ap) +{ + struct guild *g=(struct guild *)data; + int i; + + nullpo_retr(0, g); + + for(i=0;imax_member;i++){ + struct map_session_data *sd; + if((sd=g->member[i].sd)!=NULL){ + if(sd->guild_x!=sd->bl.x || sd->guild_y!=sd->bl.y){ + clif_guild_xy(sd); + sd->guild_x=sd->bl.x; + sd->guild_y=sd->bl.y; + } + } + } + return 0; +} + +//Code from party_send_xy_timer [Skotlex] +static int guild_send_xy_timer(int tid,unsigned int tick,int id,int data) +{ + guild_db->foreach(guild_db,guild_send_xy_timer_sub,tick); + return 0; +} + +int guild_send_dot_remove(struct map_session_data *sd) +{ + if (sd->status.guild_id) + clif_guild_xy_remove(sd); + return 0; +} +//------------------------------------------------------------------------ + +// 作成要求 +int guild_create(struct map_session_data *sd,char *name) +{ + nullpo_retr(0, sd); + + if(sd->status.guild_id==0){ + if(!battle_config.guild_emperium_check || pc_search_inventory(sd,714) >= 0) { + struct guild_member m; + guild_makemember(&m,sd); + m.position=0; + intif_guild_create(name,&m); + } else + clif_guild_created(sd,3); // エンペリウムがいない + }else + clif_guild_created(sd,1); // すでに所属している + + return 0; +} + +// 作成可否 +int guild_created(int account_id,int guild_id) +{ + struct map_session_data *sd=map_id2sd(account_id); + + if(sd==NULL) + return 0; + if(guild_id>0) { + //struct guild *g; + sd->status.guild_id=guild_id; + sd->state.guild_sent=0; + clif_guild_created(sd,0); + if(battle_config.guild_emperium_check) + pc_delitem(sd,pc_search_inventory(sd,714),1,0); // エンペリウム消耗 + } else { + clif_guild_created(sd,2); // 作成失敗(同名ギルド存在) + } + return 0; +} + +// 情報要求 +int guild_request_info(int guild_id) +{ +// if(battle_config.etc_log) +// printf("guild_request_info\n"); + return intif_guild_request_info(guild_id); +} +// イベント付き情報要求 +int guild_npc_request_info(int guild_id,const char *event) +{ + struct eventlist *ev; + + if( guild_search(guild_id) ){ + if(event && *event) + npc_event_do(event); + return 0; + } + + if(event==NULL || *event==0) + return guild_request_info(guild_id); + + ev=(struct eventlist *)aCalloc(1,sizeof(struct eventlist)); + memcpy(ev->name,event,strlen(event)); + //The one in the db becomes the next event from this. + ev->next=idb_put(guild_infoevent_db,guild_id,ev); + return guild_request_info(guild_id); +} + +// 所属キャラの確認 +int guild_check_member(const struct guild *g) +{ + int i, users; + struct map_session_data *sd, **all_sd; + + nullpo_retr(0, g); + + all_sd = map_getallusers(&users); + + for(i=0;istatus.guild_id==g->guild_id){ + int j,f=1; + for(j=0;jmember[j].account_id==sd->status.account_id && + g->member[j].char_id==sd->status.char_id) + f=0; + } + if(f){ + sd->status.guild_id=0; + sd->state.guild_sent=0; + sd->guild_emblem_id=0; + if(battle_config.error_log) + ShowWarning("guild: check_member %d[%s] is not member\n",sd->status.account_id,sd->status.name); + } + } + } + } + return 0; +} +// 情報所得失敗(そのIDのキャラを全部未所属にする) +int guild_recv_noinfo(int guild_id) +{ + int i, users; + struct map_session_data *sd, **all_sd; + + all_sd = map_getallusers(&users); + + for(i=0;istatus.guild_id==guild_id) + sd->status.guild_id=0; + } + } + return 0; +} +// 情報所得 +int guild_recv_info(struct guild *sg) +{ + struct guild *g,before; + int i,bm,m; + struct eventlist *ev,*ev2; + + nullpo_retr(0, sg); + + if((g=idb_get(guild_db,sg->guild_id))==NULL){ + struct map_session_data *sd; + g=(struct guild *)aCalloc(1,sizeof(struct guild)); + idb_put(guild_db,sg->guild_id,g); + before=*sg; + + // 最初のロードなのでユーザーのチェックを行う + guild_check_member(sg); + //If the guild master is online the first time the guild_info is received, that means he was the first to join, + //and as such, his guild skills should be blocked to avoid login/logout abuse [Skotlex] + if ((sd = map_nick2sd(sg->master)) != NULL) + { + guild_block_skill(sd, 300000); + //Also set the guild master flag. + sd->state.gmaster_flag = g; + clif_charnameupdate(sd); // [LuzZza] + } + }else + before=*g; + memcpy(g,sg,sizeof(struct guild)); + + for(i=bm=m=0;imax_member;i++){ // sdの設定と人数の確認 + if(g->member[i].account_id>0){ + struct map_session_data *sd = map_id2sd(g->member[i].account_id); + if (sd && sd->status.char_id == g->member[i].char_id && + sd->status.guild_id == g->guild_id && + !sd->state.waitingdisconnect) { + g->member[i].sd = sd; + clif_charnameupdate(sd); // [LuzZza] + } else g->member[i].sd = NULL; + m++; + }else + g->member[i].sd=NULL; + if(before.member[i].account_id>0) + bm++; + } + + for(i=0;imax_member;i++){ // 情報の送信 + struct map_session_data *sd = g->member[i].sd; + if( sd==NULL ) + continue; + + if( before.guild_lv!=g->guild_lv || bm!=m || + before.max_member!=g->max_member ){ + clif_guild_basicinfo(sd); // 基本情報送信 + clif_guild_emblem(sd,g); // エンブレム送信 + } + + if(bm!=m){ // メンバー情報送信 + clif_guild_memberlist(g->member[i].sd); + } + + if( before.skill_point!=g->skill_point) + clif_guild_skillinfo(sd); // スキル情報送信 + + if( sd->state.guild_sent==0){ // 未送信なら所属情報も送る + clif_guild_belonginfo(sd,g); + clif_guild_notice(sd,g); + sd->guild_emblem_id=g->emblem_id; + sd->state.guild_sent=1; + } + } + + // イベントの発生 + if( (ev=idb_remove(guild_infoevent_db,sg->guild_id))!=NULL ){ + while(ev){ + npc_event_do(ev->name); + ev2=ev->next; + aFree(ev); + ev=ev2; + } + } + + return 0; +} + + +// ギルドへの勧誘 +int guild_invite(struct map_session_data *sd,int account_id) +{ + struct map_session_data *tsd; + struct guild *g; + int i; + + nullpo_retr(0, sd); + + tsd= map_id2sd(account_id); + g=guild_search(sd->status.guild_id); + + if(tsd==NULL || g==NULL) + return 0; + if(!battle_config.invite_request_check) { + if (tsd->party_invite>0 || tsd->trade_partner) { // 相手が取引中かどうか + clif_guild_inviteack(sd,0); + return 0; + } + } + if( tsd->status.guild_id>0 || tsd->guild_invite>0 ){ // 相手の所属確認 + clif_guild_inviteack(sd,0); + return 0; + } + + // 定員確認 + for(i=0;imax_member;i++) + if(g->member[i].account_id==0) + break; + if(i==g->max_member){ + clif_guild_inviteack(sd,3); + return 0; + } + + tsd->guild_invite=sd->status.guild_id; + tsd->guild_invite_account=sd->status.account_id; + + clif_guild_invite(tsd,g); + return 0; +} +// ギルド勧誘への返答 +int guild_reply_invite(struct map_session_data *sd,int guild_id,int flag) +{ + struct map_session_data *tsd; + + nullpo_retr(0, sd); + + //nullpo_retr(0, tsd= map_id2sd( sd->guild_invite_account )); + //I checked the code, and there's no "check" for the case where the guy + //that invites another to a guild quits the map-server before being replied. + //Hence that's a valid null pointer scenario. :) [Skotlex] + if ((tsd= map_id2sd( sd->guild_invite_account )) == NULL) + { //Do we send a "invitation failed" msg or something to the player? + //Or should we accept the invitation and add it to the guild anyway? + //afterall, guild_invite holds the guild id that the player was invited to. + sd->guild_invite=0; + sd->guild_invite_account=0; + return 0; + } + + if(sd->guild_invite!=guild_id) // 勧誘とギルドIDが違う + return 0; + + if(flag==1){ // 承諾 + struct guild_member m; + struct guild *g; + int i; + + // 定員確認 + if( (g=guild_search(tsd->status.guild_id))==NULL ){ + sd->guild_invite=0; + sd->guild_invite_account=0; + return 0; + } + for(i=0;imax_member;i++) + if(g->member[i].account_id==0) + break; + if(i==g->max_member){ + sd->guild_invite=0; + sd->guild_invite_account=0; + clif_guild_inviteack(tsd,3); + return 0; + } + + + //inter鯖へ追加要求 + guild_makemember(&m,sd); + intif_guild_addmember( sd->guild_invite, &m ); + return 0; + }else{ // 拒否 + sd->guild_invite=0; + sd->guild_invite_account=0; + clif_guild_inviteack(tsd,1); + } + return 0; +} +// ギルドメンバが追加された +int guild_member_added(int guild_id,int account_id,int char_id,int flag) +{ + struct map_session_data *sd= map_id2sd(account_id),*sd2; + struct guild *g; + + if( (g=guild_search(guild_id))==NULL ) + return 0; + + if(sd==NULL || sd->guild_invite==0){ + // キャラ側に登録できなかったため脱退要求を出す + if (flag == 0) { + if(battle_config.error_log) + ShowError("guild: member added error %d is not online\n",account_id); + intif_guild_leave(guild_id,account_id,char_id,0,"**登録失敗**"); + } + return 0; + } + sd2 = map_id2sd(sd->guild_invite_account); + sd->guild_invite = 0; + sd->guild_invite_account = 0; + + if(flag==1){ // 失敗 + if( sd2!=NULL ) + clif_guild_inviteack(sd2,3); + return 0; + } + + // 成功 + sd->state.guild_sent=0; + sd->status.guild_id=guild_id; + + if( sd2!=NULL ) + clif_guild_inviteack(sd2,2); + + // いちおう競合確認 + guild_check_conflict(sd); + //Next line commented because it do nothing, look at guild_recv_info [LuzZza] + //clif_charnameupdate(sd); //Update display name [Skotlex] + return 0; +} + +// ギルド脱退要求 +int guild_leave(struct map_session_data *sd,int guild_id, + int account_id,int char_id,const char *mes) +{ + struct guild *g; + int i; + + nullpo_retr(0, sd); + + g = guild_search(sd->status.guild_id); + + if(g==NULL) + return 0; + + if( sd->status.account_id!=account_id || + sd->status.char_id!=char_id || sd->status.guild_id!=guild_id) + return 0; + + for(i=0;imax_member;i++){ // 所属しているか + if( g->member[i].account_id==sd->status.account_id && + g->member[i].char_id==sd->status.char_id ){ + intif_guild_leave(g->guild_id,sd->status.account_id,sd->status.char_id,0,mes); + return 0; + } + } + return 0; +} +// ギルド追放要求 +int guild_explusion(struct map_session_data *sd,int guild_id, + int account_id,int char_id,const char *mes) +{ + struct guild *g; + int i,ps; + + nullpo_retr(0, sd); + + g = guild_search(sd->status.guild_id); + + if(g==NULL) + return 0; + + if( sd->status.guild_id!=guild_id) + return 0; + + if( (ps=guild_getposition(sd,g))<0 || !(g->position[ps].mode&0x0010) ) + return 0; // 処罰権限無し + + for(i=0;imax_member;i++){ // 所属しているか + if( g->member[i].account_id==account_id && + g->member[i].char_id==char_id ){ + intif_guild_leave(g->guild_id,account_id,char_id,1,mes); + memset(&g->member[i],0,sizeof(struct guild_member)); + return 0; + } + } + return 0; +} +// ギルドメンバが脱退した +int guild_member_leaved(int guild_id,int account_id,int char_id,int flag, + const char *name,const char *mes) +{ + struct map_session_data *sd=map_charid2sd(char_id); + struct guild *g=guild_search(guild_id); + + if(g!=NULL){ + int i; + for(i=0;imax_member;i++) { + if( g->member[i].account_id==account_id && + g->member[i].char_id==char_id ){ + struct map_session_data *sd2=sd; + if(sd2==NULL) + sd2=guild_getavailablesd(g); + else + { + if(flag==0) + clif_guild_leave(sd2,name,mes); + else + clif_guild_explusion(sd2,name,mes,account_id); + } + memset(&g->member[i],0,sizeof(struct guild_member)); + } + // メンバーリストを全員に再通知 + for(i=0;imax_member;i++){ + if( g->member[i].sd!=NULL ) + clif_guild_memberlist(g->member[i].sd); + } + } + } + if(sd!=NULL) { + if (sd->status.guild_id==guild_id){ + guild_send_dot_remove(sd); + sd->status.guild_id=0; + sd->guild_emblem_id=0; + sd->state.guild_sent=0; + clif_charnameupdate(sd); //Update display name [Skotlex] + } + } + + return 0; +} +// ギルドメンバのオンライン状態/Lv更新送信 +int guild_send_memberinfoshort(struct map_session_data *sd,int online) +{ + struct guild *g; + + nullpo_retr(0, sd); + + if(sd->status.guild_id<=0) + return 0; + g=guild_search(sd->status.guild_id); + if(g==NULL) + return 0; + + intif_guild_memberinfoshort(g->guild_id, + sd->status.account_id,sd->status.char_id,online,sd->status.base_level,sd->status.class_); + + if( !online ){ // ログアウトするならsdをクリアして終了 + int i=guild_getindex(g,sd->status.account_id,sd->status.char_id); + if(i>=0) + g->member[i].sd=NULL; + return 0; + } + + if( sd->state.guild_sent!=0 ) // ギルド初期送信データは送信済み + return 0; + + // 競合確認 + guild_check_conflict(sd); + + // あるならギルド初期送信データ送信 + if( (g=guild_search(sd->status.guild_id))!=NULL ){ + guild_check_member(g); // 所属を確認する + if(sd->status.guild_id==g->guild_id){ + clif_guild_belonginfo(sd,g); + clif_guild_notice(sd,g); + sd->state.guild_sent=1; + sd->guild_emblem_id=g->emblem_id; + } + } + return 0; +} +// ギルドメンバのオンライン状態/Lv更新通知 +int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int online,int lv,int class_) +{ + int i,alv,c,idx=-1,om=0,oldonline=-1; + struct guild *g=guild_search(guild_id); + if(g==NULL) + return 0; + for(i=0,alv=0,c=0,om=0;imax_member;i++){ + struct guild_member *m=&g->member[i]; + if(m->account_id==account_id && m->char_id==char_id ){ + oldonline=m->online; + m->online=online; + m->lv=lv; + m->class_=class_; + idx=i; + } + if(m->account_id>0){ + alv+=m->lv; + c++; + } + if(m->online) + om++; + } + if(idx == -1 || c == 0) { + // ギルドのメンバー外なので追放扱いする + struct map_session_data *sd = map_id2sd(account_id); + if(sd && sd->char_id == char_id) { + sd->status.guild_id=0; + sd->guild_emblem_id=0; + sd->state.guild_sent=0; + } + if(battle_config.error_log) + ShowWarning("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name); + return 0; + } + g->average_lv=alv/c; + g->connect_member=om; + + if(oldonline!=online) // オンライン状態が変わったので通知 + clif_guild_memberlogin_notice(g,idx,online); + + for(i=0;imax_member;i++){ // sd再設定 + struct map_session_data *sd= map_id2sd(g->member[i].account_id); + if (sd && sd->status.char_id == g->member[i].char_id && + sd->status.guild_id == g->guild_id && + !sd->state.waitingdisconnect) + g->member[i].sd = sd; + else sd = NULL; + } + + // ここにクライアントに送信処理が必要 + + return 0; +} +// ギルド会話送信 +int guild_send_message(struct map_session_data *sd,char *mes,int len) +{ + nullpo_retr(0, sd); + + if(sd->status.guild_id==0) + return 0; + intif_guild_message(sd->status.guild_id,sd->status.account_id,mes,len); + guild_recv_message(sd->status.guild_id,sd->status.account_id,mes,len); + + //Chatlogging type 'G' + if(log_config.chat&1 //we log everything then + || ( log_config.chat&8 //if Guild bit is on + && ( !agit_flag || !(log_config.chat&16) ))) //if WOE ONLY flag is off or AGIT is OFF + log_chat("G", sd->status.guild_id, sd->status.char_id, sd->status.account_id, (char*)mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, mes); + + return 0; +} +// ギルド会話受信 +int guild_recv_message(int guild_id,int account_id,char *mes,int len) +{ + struct guild *g; + if( (g=guild_search(guild_id))==NULL) + return 0; + clif_guild_message(g,account_id,mes,len); + return 0; +} +// ギルドメンバの役職変更 +int guild_change_memberposition(int guild_id,int account_id,int char_id,int idx) +{ + return intif_guild_change_memberinfo( + guild_id,account_id,char_id,GMI_POSITION,&idx,sizeof(idx)); +} +// ギルドメンバの役職変更通知 +int guild_memberposition_changed(struct guild *g,int idx,int pos) +{ + nullpo_retr(0, g); + + g->member[idx].position=pos; + clif_guild_memberpositionchanged(g,idx); + + // Update char position in client [LuzZza] + if(g->member[idx].sd != NULL) + clif_charnameupdate(g->member[idx].sd); + return 0; +} +// ギルド役職変更 +int guild_change_position(struct map_session_data *sd,int idx, + int mode,int exp_mode,const char *name) +{ + struct guild_position p; + + nullpo_retr(0, sd); + + if(exp_mode>battle_config.guild_exp_limit) + exp_mode=battle_config.guild_exp_limit; + if(exp_mode<0)exp_mode=0; + p.mode=mode; + p.exp_mode=exp_mode; + memcpy(p.name,name,NAME_LENGTH-1); + p.name[NAME_LENGTH-1] = '\0'; //Security check... [Skotlex] + return intif_guild_position(sd->status.guild_id,idx,&p); +} +// ギルド役職変更通知 +int guild_position_changed(int guild_id,int idx,struct guild_position *p) +{ + struct guild *g=guild_search(guild_id); + int i; + if(g==NULL) + return 0; + memcpy(&g->position[idx],p,sizeof(struct guild_position)); + clif_guild_positionchanged(g,idx); + + // Update char name in client [LuzZza] + for(i=0;imax_member;i++) + if(g->member[i].position == idx && g->member[i].sd != NULL) + clif_charnameupdate(g->member[i].sd); + return 0; +} +// ギルド告知変更 +int guild_change_notice(struct map_session_data *sd,int guild_id,const char *mes1,const char *mes2) +{ + nullpo_retr(0, sd); + + if(guild_id!=sd->status.guild_id) + return 0; + return intif_guild_notice(guild_id,mes1,mes2); +} +// ギルド告知変更通知 +int guild_notice_changed(int guild_id,const char *mes1,const char *mes2) +{ + int i; + struct map_session_data *sd; + struct guild *g=guild_search(guild_id); + if(g==NULL) + return 0; + + memcpy(g->mes1,mes1,60); + memcpy(g->mes2,mes2,120); + + for(i=0;imax_member;i++){ + if((sd=g->member[i].sd)!=NULL) + clif_guild_notice(sd,g); + } + return 0; +} +// ギルドエンブレム変更 +int guild_change_emblem(struct map_session_data *sd,int len,const char *data) +{ + struct guild *g; + nullpo_retr(0, sd); + + if (battle_config.require_glory_guild && + !((g = guild_search(sd->status.guild_id)) && guild_checkskill(g, GD_GLORYGUILD)>0)) { + clif_skill_fail(sd,GD_GLORYGUILD,0,0); + return 0; + } + + return intif_guild_emblem(sd->status.guild_id,len,data); +} +// ギルドエンブレム変更通知 +int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data) +{ + int i; + struct map_session_data *sd; + struct guild *g=guild_search(guild_id); + if(g==NULL) + return 0; + + memcpy(g->emblem_data,data,len); + g->emblem_len=len; + g->emblem_id=emblem_id; + + for(i=0;imax_member;i++){ + if((sd=g->member[i].sd)!=NULL){ + sd->guild_emblem_id=emblem_id; + clif_guild_belonginfo(sd,g); + clif_guild_emblem(sd,g); + } + } + return 0; +} + +static void* create_expcache(DBKey key, va_list args) { + struct guild_expcache *c; + struct map_session_data *sd = va_arg(args, struct map_session_data*); + c = (struct guild_expcache *)aCallocA(1, sizeof(struct guild_expcache)); + c->guild_id = sd->status.guild_id; + c->account_id = sd->status.account_id; + c->char_id = sd->status.char_id; + return c; +} +// ギルドのEXP上納 +int guild_payexp(struct map_session_data *sd,int exp) +{ + struct guild *g; + struct guild_expcache *c; + int per, exp2; + double tmp; + + nullpo_retr(0, sd); + + if (sd->status.guild_id == 0 || + (g = guild_search(sd->status.guild_id)) == NULL || + (per = g->position[guild_getposition(sd,g)].exp_mode) <= 0) + return 0; + + if (per > 100) per = 100; + + if ((exp2 = exp * per / 100) <= 0) + return 0; + + c = guild_expcache_db->ensure(guild_expcache_db, i2key(sd->status.char_id), create_expcache, sd); + tmp = c->exp; + if (battle_config.guild_exp_rate != 100) + tmp += battle_config.guild_exp_rate*exp2/100; + else + tmp += exp2; + c->exp = (tmp > 0x7fffffff) ? 0x7fffffff : (int)tmp; + return exp2; +} + +// Celest +int guild_getexp(struct map_session_data *sd,int exp) +{ + struct guild *g; + struct guild_expcache *c; + double tmp; + nullpo_retr(0, sd); + + if (sd->status.guild_id == 0 || (g = guild_search(sd->status.guild_id)) == NULL) + return 0; + + c = guild_expcache_db->ensure(guild_expcache_db, i2key(sd->status.char_id), create_expcache, sd); + tmp = c->exp + exp; + c->exp = (tmp > 0x7fffffff) ? 0x7fffffff : (int)tmp; + return exp; +} + +// スキルポイント割り振り +int guild_skillup(struct map_session_data *sd,int skill_num,int flag) +{ + struct guild *g; + int idx = skill_num - GD_SKILLBASE; + + nullpo_retr(0, sd); + + if(idx < 0 || idx >= MAX_GUILDSKILL) + + return 0; + if(sd->status.guild_id==0 || (g=guild_search(sd->status.guild_id))==NULL) + return 0; + if(strcmp(sd->status.name,g->master)) + return 0; + + if( (g->skill_point>0 || flag&1) && + g->skill[idx].id!=0 && + g->skill[idx].lv < guild_skill_get_max(skill_num) ){ + intif_guild_skillup(g->guild_id,skill_num,sd->status.account_id,flag); + } + status_calc_pc (sd, 0); // Celest + + return 0; +} +// スキルポイント割り振り通知 +int guild_skillupack(int guild_id,int skill_num,int account_id) +{ + struct map_session_data *sd=map_id2sd(account_id); + struct guild *g=guild_search(guild_id); + int i; + if(g==NULL) + return 0; + if(sd!=NULL) + clif_guild_skillup(sd,skill_num,g->skill[skill_num-GD_SKILLBASE].lv); + // 全員に通知 + for(i=0;imax_member;i++) + if((sd=g->member[i].sd)!=NULL) + clif_guild_skillinfo(sd); + return 0; +} + +// ギルド同盟数所得 +int guild_get_alliance_count(struct guild *g,int flag) +{ + int i,c; + + nullpo_retr(0, g); + + for(i=c=0;ialliance[i].guild_id>0 && + g->alliance[i].opposition==flag ) + c++; + } + return c; +} + +// Blocks all guild skills which have a common delay time. +void guild_block_skill(struct map_session_data *sd, int time) { + int skill_num[] = { GD_BATTLEORDER, GD_REGENERATION, GD_RESTORE, GD_EMERGENCYCALL }; + int i; + for (i = 0; i < 4; i++) + pc_blockskill_start(sd, skill_num[i], time); +} + +// 同盟関係かどうかチェック +// 同盟なら1、それ以外は0 +int guild_check_alliance(int guild_id1, int guild_id2, int flag) +{ + struct guild *g; + int i; + + g = guild_search(guild_id1); + if (g == NULL) + return 0; + + for (i=0; ialliance[i].guild_id == guild_id2) && (g->alliance[i].opposition == flag)) + return 1; + + return 0; +} +// ギルド同盟要求 +int guild_reqalliance(struct map_session_data *sd,int account_id) +{ + struct map_session_data *tsd= map_id2sd(account_id); + struct guild *g[2]; + int i; + + if(agit_flag) { // Disable alliance creation during woe [Valaris] + clif_displaymessage(sd->fd,"Alliances cannot be made during Guild Wars!"); + return 0; + } // end addition [Valaris] + + + nullpo_retr(0, sd); + + if(tsd==NULL || tsd->status.guild_id<=0) + return 0; + + g[0]=guild_search(sd->status.guild_id); + g[1]=guild_search(tsd->status.guild_id); + + if(g[0]==NULL || g[1]==NULL) + return 0; + + if( guild_get_alliance_count(g[0],0)>=3 ) // 同盟数確認 + clif_guild_allianceack(sd,4); + if( guild_get_alliance_count(g[1],0)>=3 ) + clif_guild_allianceack(sd,3); + + if( tsd->guild_alliance>0 ){ // 相手が同盟要請状態かどうか確認 + clif_guild_allianceack(sd,1); + return 0; + } + + for(i=0;ialliance[i].guild_id==tsd->status.guild_id && + g[0]->alliance[i].opposition==0){ + clif_guild_allianceack(sd,0); + return 0; + } + } + + tsd->guild_alliance=sd->status.guild_id; + tsd->guild_alliance_account=sd->status.account_id; + + clif_guild_reqalliance(tsd,sd->status.account_id,g[0]->name); + return 0; +} +// ギルド勧誘への返答 +int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag) +{ + struct map_session_data *tsd; + + nullpo_retr(0, sd); + nullpo_retr(0, tsd= map_id2sd( account_id )); + + if(sd->guild_alliance!=tsd->status.guild_id) // 勧誘とギルドIDが違う + return 0; + + if(flag==1){ // 承諾 + int i; + + struct guild *g,*tg; // 同盟数再確認 + g=guild_search(sd->status.guild_id); + tg=guild_search(tsd->status.guild_id); + + if(g==NULL || guild_get_alliance_count(g,0)>=3){ + clif_guild_allianceack(sd,4); + clif_guild_allianceack(tsd,3); + return 0; + } + if(tg==NULL || guild_get_alliance_count(tg,0)>=3){ + clif_guild_allianceack(sd,3); + clif_guild_allianceack(tsd,4); + return 0; + } + + for(i=0;ialliance[i].guild_id==tsd->status.guild_id && + g->alliance[i].opposition==1) + intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, + sd->status.account_id,tsd->status.account_id,9 ); + } + for(i=0;ialliance[i].guild_id==sd->status.guild_id && + tg->alliance[i].opposition==1) + intif_guild_alliance( tsd->status.guild_id,sd->status.guild_id, + tsd->status.account_id,sd->status.account_id,9 ); + } + + // inter鯖へ同盟要請 + intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, + sd->status.account_id,tsd->status.account_id,0 ); + return 0; + }else{ // 拒否 + sd->guild_alliance=0; + sd->guild_alliance_account=0; + if(tsd!=NULL) + clif_guild_allianceack(tsd,3); + } + return 0; +} +// ギルド関係解消 +int guild_delalliance(struct map_session_data *sd,int guild_id,int flag) +{ + if(agit_flag) { // Disable alliance breaking during woe [Valaris] + clif_displaymessage(sd->fd,"Alliances cannot be broken during Guild Wars!"); + return 0; + } // end addition [Valaris] + + nullpo_retr(0, sd); + + intif_guild_alliance( sd->status.guild_id,guild_id, + sd->status.account_id,0,flag|8 ); + return 0; +} +// ギルド敵対 +int guild_opposition(struct map_session_data *sd,int char_id) +{ + struct map_session_data *tsd=map_id2sd(char_id); + struct guild *g; + int i; + + nullpo_retr(0, sd); + + g=guild_search(sd->status.guild_id); + if(g==NULL || tsd==NULL) + return 0; + + if( guild_get_alliance_count(g,1)>=3 ) // 敵対数確認 + clif_guild_oppositionack(sd,1); + + for(i=0;ialliance[i].guild_id==tsd->status.guild_id){ + if(g->alliance[i].opposition==1){ // すでに敵対 + clif_guild_oppositionack(sd,2); + return 0; + }else // 同盟破棄 + intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, + sd->status.account_id,tsd->status.account_id,8 ); + } + } + + // inter鯖に敵対要請 + intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, + sd->status.account_id,tsd->status.account_id,1 ); + return 0; +} +// ギルド同盟/敵対通知 +int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id2, + int flag,const char *name1,const char *name2) +{ + struct guild *g[2]; + int guild_id[2]; + const char *guild_name[2]; + struct map_session_data *sd[2]; + int j,i; + + guild_id[0] = guild_id1; + guild_id[1] = guild_id2; + guild_name[0] = name1; + guild_name[1] = name2; + sd[0] = map_id2sd(account_id1); + sd[1] = map_id2sd(account_id2); + + g[0]=guild_search(guild_id1); + g[1]=guild_search(guild_id2); + + if(sd[0]!=NULL && (flag&0x0f)==0){ + sd[0]->guild_alliance=0; + sd[0]->guild_alliance_account=0; + } + + if(flag&0x70){ // 失敗 + for(i=0;i<2-(flag&1);i++) + if( sd[i]!=NULL ) + clif_guild_allianceack(sd[i],((flag>>4)==i+1)?3:4); + return 0; + } +// if(battle_config.etc_log) +// printf("guild alliance_ack %d %d %d %d %d %s %s\n",guild_id1,guild_id2,account_id1,account_id2,flag,name1,name2); + + if(!(flag&0x08)){ // 関係追加 + for(i=0;i<2-(flag&1);i++) + if(g[i]!=NULL) + for(j=0;jalliance[j].guild_id==0){ + g[i]->alliance[j].guild_id=guild_id[1-i]; + memcpy(g[i]->alliance[j].name,guild_name[1-i],NAME_LENGTH-1); + g[i]->alliance[j].opposition=flag&1; + break; + } + }else{ // 関係解消 + for(i=0;i<2-(flag&1);i++){ + if(g[i]!=NULL) + for(j=0;jalliance[j].guild_id==guild_id[1-i] && + g[i]->alliance[j].opposition==(flag&1)){ + g[i]->alliance[j].guild_id=0; + break; + } + if( sd[i]!=NULL ) // 解消通知 + clif_guild_delalliance(sd[i],guild_id[1-i],(flag&1)); + } + } + + if((flag&0x0f)==0){ // 同盟通知 + if( sd[1]!=NULL ) + clif_guild_allianceack(sd[1],2); + }else if((flag&0x0f)==1){ // 敵対通知 + if( sd[0]!=NULL ) + clif_guild_oppositionack(sd[0],0); + } + + + for(i=0;i<2-(flag&1);i++){ // 同盟/敵対リストの再送信 + struct map_session_data *sd; + if(g[i]!=NULL) + for(j=0;jmax_member;j++) + if((sd=g[i]->member[j].sd)!=NULL) + clif_guild_allianceinfo(sd); + } + return 0; +} +// ギルド解散通知用 +int guild_broken_sub(DBKey key,void *data,va_list ap) +{ + struct guild *g=(struct guild *)data; + int guild_id=va_arg(ap,int); + int i,j; + struct map_session_data *sd=NULL; + + nullpo_retr(0, g); + + for(i=0;ialliance[i].guild_id==guild_id){ + for(j=0;jmax_member;j++) + if( (sd=g->member[j].sd)!=NULL ) + clif_guild_delalliance(sd,guild_id,g->alliance[i].opposition); + intif_guild_alliance(g->guild_id, guild_id,0,0,g->alliance[i].opposition|8); + g->alliance[i].guild_id=0; + } + } + return 0; +} + +//Invoked on Castles when a guild is broken. [Skotlex] +int castle_guild_broken_sub(DBKey key,void *data,va_list ap) +{ + struct guild_castle *gc=(struct guild_castle *)data; + int guild_id=va_arg(ap,int); + + nullpo_retr(0, gc); + + if (gc->guild_id == guild_id) + { //Save the new 'owner', this should invoke guardian clean up and other such things. + gc->guild_id = 0; + guild_castledatasave(gc->castle_id, 1, 0); + } + return 0; +} + +//Innvoked on /breakguild "Guild name" +int guild_broken(int guild_id,int flag) +{ + struct guild *g=guild_search(guild_id); +// struct guild_castle *gc=NULL; + struct map_session_data *sd; + int i; +// char *name;; + + if(flag!=0 || g==NULL) + return 0; + + //we call castle_event::OnGuildBreak of all castlesof the guild + //you can set all castle_events in the castle_db.txt +/* name=(char *)aCalloc(50,sizeof(char)); //24 char = event name, + space for "::OnGuildBreak" + for(i=0;iguild_id == guild_id){ + memcpy(name,gc->castle_event,50); + npc_event_do(strcat(name,"::OnGuildBreak")); + } + } + } + free(name); +*/ + for(i=0;imax_member;i++){ // ギルド解散を通知 + if((sd=g->member[i].sd)!=NULL){ + if(sd->state.storage_flag == 2) + storage_guild_storage_quit(sd,1); + sd->status.guild_id=0; + sd->state.guild_sent=0; + clif_guild_broken(g->member[i].sd,0); + clif_charnameupdate(sd); // [LuzZza] + } + } + + guild_db->foreach(guild_db,guild_broken_sub,guild_id); + castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id); + if (guild_cache && guild_cache->guild_id == guild_id) + guild_cache = NULL; + guild_storage_delete(guild_id); + idb_remove(guild_db,guild_id); + return 0; +} + +//Changes the Guild Master to the specified player. [Skotlex] +int guild_gm_change(int guild_id, struct map_session_data *sd) +{ + struct guild *g; + nullpo_retr(0, sd); + + if (sd->status.guild_id != guild_id) + return 0; + + g=guild_search(guild_id); + + nullpo_retr(0, g); + + if (strcmp(g->master, sd->status.name) == 0) //Nothing to change. + return 0; + + //Notify servers that master has changed. + intif_guild_change_gm(guild_id, sd->status.name, strlen(sd->status.name)); + return 1; +} + +//Notification from Char server that a guild's master has changed. [Skotlex] +int guild_gm_changed(int guild_id, int pos) +{ + struct guild *g; + struct guild_member gm; + + g=guild_search(guild_id); + + if (!g || pos < 0 || pos > g->max_member) + return 0; + + memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); + memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); + memcpy(&g->member[0], &gm, sizeof(struct guild_member)); + + g->member[pos].position = g->member[0].position; + g->member[0].position = 0; //Position 0: guild Master. + strcpy(g->master, g->member[0].name); + + if (g->member[pos].sd && g->member[pos].sd->fd) + { + clif_displaymessage(g->member[pos].sd->fd, "You no longer are the Guild Master."); + g->member[pos].sd->state.gmaster_flag = 0; + } + + if (g->member[0].sd && g->member[0].sd->fd) + { + clif_displaymessage(g->member[0].sd->fd, "You have become the Guild Master!"); + g->member[0].sd->state.gmaster_flag = g; + } + return 1; +} + +// ギルド解散 +int guild_break(struct map_session_data *sd,char *name) +{ + struct guild *g; + int i; + + nullpo_retr(0, sd); + + if( (g=guild_search(sd->status.guild_id))==NULL ) + return 0; + if(strcmp(g->name,name)!=0) + return 0; + if(strcmp(sd->status.name,g->master)!=0) + return 0; + for(i=0;imax_member;i++){ + if( g->member[i].account_id>0 && ( + g->member[i].account_id!=sd->status.account_id || + g->member[i].char_id!=sd->status.char_id )) + break; + } + if(imax_member){ + clif_guild_broken(sd,2); + return 0; + } + + intif_guild_break(g->guild_id); + return 0; +} + +// ギルド城データ要求 +int guild_castledataload(int castle_id,int index) +{ + return intif_guild_castle_dataload(castle_id,index); +} +// ギルド城情報所得時イベント追加 +int guild_addcastleinfoevent(int castle_id,int index,const char *name) +{ + struct eventlist *ev; + int code=castle_id|(index<<16); + + if( name==NULL || *name==0 ) + return 0; + + ev=(struct eventlist *)aCalloc(1,sizeof(struct eventlist)); + memcpy(ev->name,name,sizeof(ev->name)); + //The next event becomes whatever was currently stored. + ev->next= idb_put(guild_castleinfoevent_db,code,ev); + return 0; +} + +// ギルド城データ要求返信 +int guild_castledataloadack(int castle_id,int index,int value) +{ + struct guild_castle *gc=guild_castle_search(castle_id); + int code=castle_id|(index<<16); + struct eventlist *ev,*ev2; + + if(gc==NULL){ + return 0; + } + switch(index){ + case 1: + gc->guild_id = value; + if (value && guild_search(value)==NULL) //Request guild data which will be required for spawned guardians. [Skotlex] + guild_request_info(value); + break; + case 2: gc->economy = value; break; + case 3: gc->defense = value; break; + case 4: gc->triggerE = value; break; + case 5: gc->triggerD = value; break; + case 6: gc->nextTime = value; break; + case 7: gc->payTime = value; break; + case 8: gc->createTime = value; break; + case 9: gc->visibleC = value; break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + gc->guardian[index-10].visible = value; break; + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + gc->guardian[index-18].hp = value; break; + default: + ShowError("guild_castledataloadack ERROR!! (Not found index=%d)\n", index); + return 0; + } + if( (ev=idb_remove(guild_castleinfoevent_db,code))!=NULL ){ + while(ev){ + npc_event_do(ev->name); + ev2=ev->next; + aFree(ev); + ev=ev2; + } + } + return 1; +} +// ギルド城データ変更要求 +int guild_castledatasave(int castle_id,int index,int value) +{ + if (index == 1) + { //The castle's owner has changed? Update Guardian ownership, too. [Skotlex] + struct guild_castle *gc = guild_castle_search(castle_id); + int m = -1; + if (gc) m = map_mapname2mapid(gc->map_name); + if (m != -1) + map_foreachinmap(mob_guardian_guildchange, m, BL_MOB); + } + return intif_guild_castle_datasave(castle_id,index,value); +} + +// ギルド城データ変更通知 +int guild_castledatasaveack(int castle_id,int index,int value) +{ + struct guild_castle *gc=guild_castle_search(castle_id); + if(gc==NULL){ + return 0; + } + switch(index){ + case 1: gc->guild_id = value; break; + case 2: gc->economy = value; break; + case 3: gc->defense = value; break; + case 4: gc->triggerE = value; break; + case 5: gc->triggerD = value; break; + case 6: gc->nextTime = value; break; + case 7: gc->payTime = value; break; + case 8: gc->createTime = value; break; + case 9: gc->visibleC = value; break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + gc->guardian[index-10].visible = value; break; + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + gc->guardian[index-18].hp = value; break; + default: + ShowError("guild_castledatasaveack ERROR!! (Not found index=%d)\n", index); + return 0; + } + return 1; +} + +// ギルドデータ一括受信(初期化時) +int guild_castlealldataload(int len,struct guild_castle *gc) +{ + int i; + int n = (len-4) / sizeof(struct guild_castle), ev = -1; + + nullpo_retr(0, gc); + + //Last owned castle in the list invokes ::OnAgitinit + for(i = 0; i < n; i++) { + if ((gc + i)->guild_id) + ev = i; + } + + // 城データ格納とギルド情報要求 + for(i = 0; i < n; i++, gc++) { + struct guild_castle *c = guild_castle_search(gc->castle_id); + if (!c) { + ShowError("guild_castlealldataload Castle id=%d not found.\n", gc->castle_id); + continue; + } + memcpy(&c->guild_id,&gc->guild_id, + sizeof(struct guild_castle) - ((int)&c->guild_id - (int)c) ); + if( c->guild_id ){ + if(i!=ev) + guild_request_info(c->guild_id); + else + guild_npc_request_info(c->guild_id, "::OnAgitInit"); + } + } + if (ev == -1) //No castles owned, invoke OnAgitInit as it is. + npc_event_doall("OnAgitInit"); + return 0; +} + +int guild_agit_start(void) +{ // Run All NPC_Event[OnAgitStart] + int c = npc_event_doall("OnAgitStart"); + ShowStatus("NPC_Event:[OnAgitStart] Run (%d) Events by @AgitStart.\n",c); + // Start auto saving + guild_save_timer = add_timer_interval (gettick() + GUILD_SAVE_INTERVAL, guild_save_sub, 0, 0, GUILD_SAVE_INTERVAL); + return 0; +} + +int guild_agit_end(void) +{ // Run All NPC_Event[OnAgitEnd] + int c = npc_event_doall("OnAgitEnd"); + ShowStatus("NPC_Event:[OnAgitEnd] Run (%d) Events by @AgitEnd.\n",c); + // Stop auto saving + delete_timer (guild_save_timer, guild_save_sub); + return 0; +} + +int guild_gvg_eliminate_timer(int tid,unsigned int tick,int id,int data) +{ // Run One NPC_Event[OnAgitEliminate] + char *name = (char*)data; + size_t len = (name) ? strlen(name) : 0; + // the rest is dangerous, but let it crash, + // if this happens, it's ruined anyway + int c=0; + + if(agit_flag) // Agit not already End + { + char *evname=(char*)aMalloc( (len + 10) * sizeof(char)); + memcpy(evname,name,len - 5); + strcpy(evname + len - 5,"Eliminate"); + c = npc_event_do(evname); + ShowStatus("NPC_Event:[%s] Run (%d) Events.\n",evname,c); + aFree(evname); // [Lance] Should fix this + } + if(name) aFree(name); + return 0; +} + +static int Ghp[MAX_GUILDCASTLE][MAX_GUARDIANS]; // so save only if HP are changed // experimental code [Yor] +static int Gid[MAX_GUILDCASTLE]; +int guild_save_sub(int tid,unsigned int tick,int id,int data) +{ + struct guild_castle *gc; + int i,j; + + for(i = 0; i < MAX_GUILDCASTLE; i++) { // [Yor] + gc = guild_castle_search(i); + if (!gc) continue; + if (gc->guild_id != Gid[i]) { + // Re-save guild id if its owner guild has changed + guild_castledatasave(gc->castle_id, 1, gc->guild_id); + Gid[i] = gc->guild_id; + } + for (j = 0; j < MAX_GUARDIANS; j++) + { + if (gc->guardian[j].visible && Ghp[i][j] != gc->guardian[j].hp) + guild_castledatasave(gc->castle_id, 18+j, gc->guardian[j].hp); + } + } + + return 0; +} + +int guild_agit_break(struct mob_data *md) +{ // Run One NPC_Event[OnAgitBreak] + char *evname; + + nullpo_retr(0, md); + + evname=(char *)aCallocA(strlen(md->npc_event) + 1, sizeof(char)); + + strcpy(evname,md->npc_event); +// Now By User to Run [OnAgitBreak] NPC Event... +// It's a little impossible to null point with player disconnect in this! +// But Script will be stop, so nothing... +// Maybe will be changed in the futher.. +// int c = npc_event_do(evname); + if(!agit_flag) return 0; // Agit already End + add_timer(gettick()+battle_config.gvg_eliminate_time,guild_gvg_eliminate_timer,md->bl.m,(int)evname); + return 0; +} + +// [MouseJstr] +// How many castles does this guild have? +int guild_checkcastles(struct guild *g) { + int i,nb_cas=0, id,cas_id=0; + struct guild_castle *gc; + id=g->guild_id; + for(i=0;iguild_id; + if(g->guild_id==cas_id) + nb_cas=nb_cas+1; + } //end for + return nb_cas; +} + +// [MouseJstr] +// is this guild allied with this castle? +int guild_isallied(struct guild *g, struct guild_castle *gc) +{ + int i; + + nullpo_retr(0, g); + + if(g->guild_id == gc->guild_id) + return 1; + + if (gc->guild_id == 0) + return 0; + + + for(i=0;ialliance[i].guild_id == gc->guild_id) { + if(g->alliance[i].opposition == 0) + return 1; + else + return 0; + } + + return 0; +} + +int guild_idisallied(int guild_id, int guild_id2) +{ + int i; + struct guild *g; + + if (guild_id <= 0 || guild_id2 <= 0) + return 0; + + if(guild_id == guild_id2) + return 1; + + g = guild_search(guild_id); + + nullpo_retr(0, g); + + + for(i=0;ialliance[i].guild_id == guild_id2) { + if(g->alliance[i].opposition == 0) + return 1; + else + return 0; + } + + return 0; +} + +static int guild_infoevent_db_final(DBKey key,void *data,va_list ap) +{ + aFree(data); + return 0; +} +void do_final_guild(void) +{ + guild_db->destroy(guild_db,NULL); + castle_db->destroy(castle_db,NULL); + guild_expcache_db->destroy(guild_expcache_db,NULL); + guild_infoevent_db->destroy(guild_infoevent_db,guild_infoevent_db_final); + guild_castleinfoevent_db->destroy(guild_castleinfoevent_db,guild_infoevent_db_final); +} -- cgit v1.2.3-60-g2f50