// Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder #define HERCULES_CORE #include "config/core.h" #include "int_clan.h" #include "char/char.h" #include "char/inter.h" #include "char/mapif.h" #include "common/cbasetypes.h" #include "common/db.h" #include "common/memmgr.h" #include "common/mmo.h" #include "common/nullpo.h" #include "common/showmsg.h" #include "common/socket.h" #include "common/sql.h" #include "common/strlib.h" #include "common/timer.h" #include #include struct inter_clan_interface inter_clan_; struct inter_clan_interface *inter_clan; //clan cache static struct DBMap* clan_db_; // int clan_id -> struct clan* int inter_clan_removemember_tosql(uint32 account_id, uint32 char_id){ if( SQL_ERROR == SQL->Query( inter->sql_handle, "UPDATE `%s` SET `clan_id` = '0' WHERE `char_id` = '%d'", char_db, char_id ) ){ Sql_ShowDebug( inter->sql_handle ); return 1; }else{ return 0; } } struct clan* inter_clan_fromsql(int clan_id){ struct clan* clan; struct SqlStmt *stmt = NULL; char* data; size_t len; int i; stmt = SQL->StmtMalloc(inter->sql_handle); if( clan_id <= 0 ) return NULL; clan = (struct clan*)idb_get(clan_db_, clan_id); if( clan ){ return clan; } if( SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `name`, `master`, `mapname`, `max_member` FROM `%s` WHERE `clan_id`='%d'", clan_db_, clan_id) ){ Sql_ShowDebug(inter->sql_handle); return NULL; } if( SQL_SUCCESS != SQL->StmtNextRow(stmt) ){ return NULL;// Clan does not exists. } CREATE(clan, struct clan, 1); memset(clan, 0, sizeof(struct clan)); clan->id = clan_id; SQL->GetData(inter->sql_handle, 0, &data, &len); memcpy(clan->name, data, min(len, NAME_LENGTH)); SQL->GetData(inter->sql_handle, 1, &data, &len); memcpy(clan->master, data, min(len, NAME_LENGTH)); SQL->GetData(inter->sql_handle, 2, &data, &len); memcpy(clan->map, data, min(len, MAP_NAME_LENGTH_EXT)); SQL->GetData(inter->sql_handle, 3, &data, NULL); clan->max_member = atoi(data); clan->connect_member = 0; SQL->FreeResult( inter->sql_handle ); if( clan->max_member > MAX_CLAN ){ ShowWarning("Clan %d:%s specifies higher capacity (%d) than MAX_CLAN (%d)\n", clan_id, clan->name, clan->max_member, MAX_CLAN); clan->max_member = MAX_CLAN; } if( SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `clan_id`='%d'", clan_alliance_db, clan_id) ){ Sql_ShowDebug(inter->sql_handle); aFree(clan); return NULL; } for( i = 0; i < MAX_CLANALLIANCE && SQL_SUCCESS == SQL->StmtNextRow(stmt); i++ ){ struct clan_alliance* a = &clan->alliance[i]; SQL->GetData(inter->sql_handle, 0, &data, NULL); a->opposition = atoi(data); SQL->GetData(inter->sql_handle, 1, &data, NULL); a->clan_id = atoi(data); SQL->GetData(inter->sql_handle, 2, &data, &len); memcpy(a->name, data, min(len, NAME_LENGTH)); } idb_put( clan_db_, clan_id, clan); if (chr->show_save_log) ShowInfo("Clan loaded (%d - %s)\n", clan_id, clan->name); return clan; } int mapif_clan_info( int fd ){ struct DBIterator *iter; int offset; struct clan* clan; int length; length = 4 + db_size(clan_db_) * sizeof( struct clan ); WFIFOHEAD( fd, length ); WFIFOW( fd, 0 ) = 0x38A0; WFIFOW( fd, 2 ) = length; offset = 4; iter = db_iterator(clan_db_); for( clan = (struct clan*)dbi_first(iter); dbi_exists(iter); clan = (struct clan*)dbi_next(iter) ){ memcpy( WFIFOP( fd, offset ), clan, sizeof( struct clan ) ); offset += sizeof( struct clan ); } dbi_destroy(iter); WFIFOSET( fd, length ); return 0; } static int mapif_parse_clan_request( int fd ){ mapif_clan_info( fd ); return 0; } static int mapif_parse_clan_message( int fd ){ unsigned char buf[500]; uint16 len; len = RFIFOW(fd,2); WBUFW(buf,0) = 0x38A1; memcpy( WBUFP(buf,2), RFIFOP(fd,2), len-2 ); mapif->sendallwos( fd, buf, len ); return 0; } static void mapif_clan_refresh_onlinecount( int fd, struct clan* clan ){ unsigned char buf[8]; WBUFW(buf,0) = 0x38A2; WBUFL(buf,2) = clan->id; WBUFW(buf,6) = clan->connect_member; mapif->sendallwos( fd, buf, 8 ); } static void mapif_parse_clan_member_left( int fd ){ struct clan* clan = (struct clan*)idb_get(clan_db_, RFIFOL(fd,2) ); if( clan == NULL ){ // Unknown clan return; } if( clan->connect_member > 0 ){ clan->connect_member--; mapif_clan_refresh_onlinecount( fd, clan ); } } static void mapif_parse_clan_member_joined( int fd ){ struct clan* clan = (struct clan*)idb_get(clan_db_, RFIFOL(fd,2) ); if( clan == NULL ){ // Unknown clan return; } clan->connect_member++; mapif_clan_refresh_onlinecount( fd, clan ); } // Communication from the map server // - Can analyzed only one by one packet // Data packet length that you set to inter.c //- Shouldn't do checking and packet length, RFIFOSKIP is done by the caller // Must Return // 1 : ok // 0 : error int inter_clan_parse_frommap( int fd ){ RFIFOHEAD(fd); switch(RFIFOW(fd,0)) { case 0x30A0: mapif_parse_clan_request( fd ); return 1; case 0x30A1: mapif_parse_clan_message( fd ); return 1; case 0x30A2: mapif_parse_clan_member_left( fd ); return 1; case 0x30A3: mapif_parse_clan_member_joined( fd ); return 1; default: return 0; } } // Initialize clan sql int inter_clan_init(void){ char* data; struct SqlStmt *stmt = NULL; int* clan_ids; int amount; clan_db_ = idb_alloc(DB_OPT_RELEASE_DATA); if( SQL_ERROR == SQL->Query( inter->sql_handle, "SELECT `clan_id` FROM `%s`", clan_db_ ) ){ Sql_ShowDebug(inter->sql_handle); return 1; } amount = (int)SQL->NumRows( inter->sql_handle ); stmt = SQL->StmtMalloc(inter->sql_handle); if( amount > 0 ){ int i; CREATE( clan_ids, int, amount ); i = 0; while( SQL_SUCCESS == SQL->StmtNextRow(stmt) ){ SQL->GetData(inter->sql_handle, 0, &data, NULL); clan_ids[i++] = atoi(data); } SQL->FreeResult( inter->sql_handle ); // If we didnt load a row as expected amount = i; for( i = 0; i < amount; i++ ){ inter_clan->fromsql( clan_ids[i] ); } aFree(clan_ids); } return 0; } void inter_clan_sql_final(){ db_destroy(clan_db_); } void inter_clan_defaults(void) { inter_clan = &inter_clan_; inter_clan->sql_init = inter_clan_init; inter_clan->fromsql = inter_clan_fromsql; inter_clan->sql_final = inter_clan_sql_final; inter_clan->parse_frommap = inter_clan_parse_frommap; }