// 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 <stdio.h>
#include <stdlib.h>
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;
}