Added support for homunculus autofeeding (#3007)

* Added support for homunculus autofeeding
This feature is available in 2017-09-20bRagexeRE or later

Credits to @Asheraf in HerculesWS/Hercules#1898
This commit is contained in:
Lemongrass3110 2018-04-04 08:55:51 +02:00 committed by Jittapan Pluemsumran
parent 1390930ca5
commit aff70f6482
13 changed files with 92 additions and 32 deletions

View File

@ -67,3 +67,11 @@ feature.roulette: off
// Achievement (Note 1)
// Requires: 2015-05-13aRagexe or later
feature.achievement: on
// Homunculues Autofeeding (Note 1)
// Requires: 2017-09-20bRagexeRE or later
feature.homunculus_autofeed: off
// At which rate should homunculus autofeeding trigger?
// Default: 30
feature.homunculus_autofeed_rate: 30

View File

@ -608,6 +608,7 @@ CREATE TABLE IF NOT EXISTS `homunculus` (
`alive` tinyint(2) NOT NULL default '1',
`rename_flag` tinyint(2) NOT NULL default '0',
`vaporize` tinyint(2) NOT NULL default '0',
`autofeed` tinyint(2) NOT NULL default '0',
PRIMARY KEY (`homun_id`)
) ENGINE=MyISAM;

View File

@ -0,0 +1,2 @@
ALTER TABLE `homunculus`
ADD COLUMN `autofeed` tinyint(2) NOT NULL default '0' AFTER `vaporize`;

View File

@ -2453,7 +2453,7 @@ bool char_checkdb(void){
}
//checking homunculus_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`,"
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`alive`,`rename_flag`,`vaporize` "
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`alive`,`rename_flag`,`vaporize`,`autofeed` "
" FROM `%s` LIMIT 1;", schema_config.homunculus_db) ){
Sql_ShowDebug(sql_handle);
return false;

View File

@ -93,10 +93,10 @@ bool mapif_homunculus_save(struct s_homunculus* hd)
if( hd->hom_id == 0 )
{// new homunculus
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` "
"(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) "
"VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%d')",
"(`char_id`, `class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`, `autofeed`) "
"VALUES ('%d', '%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%d', '%d')",
schema_config.homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) )
hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->autofeed) )
{
Sql_ShowDebug(sql_handle);
flag = false;
@ -108,9 +108,9 @@ bool mapif_homunculus_save(struct s_homunculus* hd)
}
else
{
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%u',`max_hp`='%u',`sp`='%u',`max_sp`='%u',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'",
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_id`='%d', `class`='%d',`prev_class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%u',`max_hp`='%u',`sp`='%u',`max_sp`='%u',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d', `autofeed`='%d' WHERE `homun_id`='%d'",
schema_config.homunculus_db, hd->char_id, hd->class_, hd->prev_class, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) )
hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->autofeed, hd->hom_id) )
{
Sql_ShowDebug(sql_handle);
flag = false;
@ -155,7 +155,7 @@ bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd)
memset(hd, 0, sizeof(*hd));
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `%s` WHERE `homun_id`='%u'",
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize`, `autofeed` FROM `%s` WHERE `homun_id`='%u'",
schema_config.homunculus_db, homun_id) )
{
Sql_ShowDebug(sql_handle);
@ -196,6 +196,7 @@ bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd)
Sql_GetData(sql_handle, 19, &data, NULL); hd->skillpts = atoi(data);
Sql_GetData(sql_handle, 20, &data, NULL); hd->rename_flag = atoi(data);
Sql_GetData(sql_handle, 21, &data, NULL); hd->vaporize = atoi(data);
Sql_GetData(sql_handle, 22, &data, NULL); hd->autofeed = atoi(data);
Sql_FreeResult(sql_handle);
hd->intimacy = umin(hd->intimacy,100000);

View File

@ -434,6 +434,7 @@ struct s_homunculus { //[orn]
int luk_value;
char spiritball; //for homun S [lighta]
bool autofeed;
};
struct s_mercenary {

View File

@ -8503,6 +8503,8 @@ static const struct _battle_data {
{ "autoloot_adjust", &battle_config.autoloot_adjust, 0, 0, 1, },
{ "broadcast_hide_name", &battle_config.broadcast_hide_name, 2, 0, NAME_LENGTH, },
{ "skill_drop_items_full", &battle_config.skill_drop_items_full, 0, 0, 1, },
{ "feature.homunculus_autofeed", &battle_config.feature_homunculus_autofeed, 1, 0, 1, },
{ "feature.homunculus_autofeed_rate", &battle_config.feature_homunculus_autofeed_rate,30, 0, 100, },
#include "../custom/battle_config_init.inc"
};
@ -8633,6 +8635,13 @@ void battle_adjust_conf()
}
#endif
#if PACKETVER < 20170920
if( battle_config.feature_homunculus_autofeed ){
ShowWarning("conf/battle/feature.conf homunculus autofeeding is enabled but it requires PACKETVER 2017-09-20 or newer, disabling...\n");
battle_config.feature_homunculus_autofeed = 0;
}
#endif
#ifndef CELL_NOSTACK
if (battle_config.custom_cell_stack_limit != 1)
ShowWarning("Battle setting 'custom_cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");

View File

@ -639,6 +639,8 @@ struct Battle_Config
int autoloot_adjust;
int broadcast_hide_name;
int skill_drop_items_full;
int feature_homunculus_autofeed;
int feature_homunculus_autofeed_rate;
#include "../custom/battle_config_struct.inc"
};

View File

@ -9765,23 +9765,21 @@ void clif_feel_hate_reset(struct map_session_data *sd)
}
/// Equip window (un)tick ack (ZC_CONFIG).
/// 02d9 <type>.L <value>.L
/// type:
/// 0 = open equip window
/// value:
/// 0 = disabled
/// 1 = enabled
void clif_equiptickack(struct map_session_data* sd, int flag)
{
/// Send out reply to configuration change
/// 02d9 <type>.L <value>.L (ZC_CONFIG)
/// type: see enum e_config_type
/// value:
/// false = disabled
/// true = enabled
void clif_configuration( struct map_session_data* sd, enum e_config_type type, bool enabled ){
int fd;
nullpo_retv(sd);
fd = sd->fd;
WFIFOHEAD(fd, packet_len(0x2d9));
WFIFOW(fd, 0) = 0x2d9;
WFIFOL(fd, 2) = 0;
WFIFOL(fd, 6) = flag;
WFIFOL(fd, 2) = type;
WFIFOL(fd, 6) = enabled;
WFIFOSET(fd, packet_len(0x2d9));
}
@ -10449,6 +10447,13 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
clif_partyinvitationstate(sd);
clif_equipcheckbox(sd);
#endif
#if PACKETVER >= 20170920
if( sd->hd ){
clif_configuration( sd, CONFIG_HOMUNCULUS_AUTOFEED, sd->hd->homunculus.autofeed );
}else{
clif_configuration( sd, CONFIG_HOMUNCULUS_AUTOFEED, false );
}
#endif
if (sd->guild && battle_config.guild_notice_changemap == 1)
clif_guild_notice(sd); // Displays after VIP
@ -16543,19 +16548,38 @@ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd)
}
/// Request to change equip window tick (CZ_CONFIG).
/// 02d8 <type>.L <flag>.L
/// type:
/// 0 = open equip window
/// Request to a configuration.
/// 02d8 <type>.L <flag>.L (CZ_CONFIG)
/// type: see enum e_config_type
/// flag:
/// 0 = disabled
/// 1 = enabled
void clif_parse_EquipTick(int fd, struct map_session_data* sd)
{
//int type = RFIFOL(fd,packet_db[cmd].pos[0]);
bool flag = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[1]) != 0;
sd->status.show_equip = flag;
clif_equiptickack(sd, flag);
/// false = disabled
/// true = enabled
void clif_parse_configuration( int fd, struct map_session_data* sd ){
int cmd = RFIFOW(fd,0);
int type = RFIFOL(fd,packet_db[cmd].pos[0]);
bool flag = RFIFOL(fd,packet_db[cmd].pos[1]) != 0;
switch( type ){
case CONFIG_OPEN_EQUIPMENT_WINDOW:
sd->status.show_equip = flag;
break;
case CONFIG_PET_AUTOFEED:
// TODO: Implement with pet evolution system
break;
case CONFIG_HOMUNCULUS_AUTOFEED:
// Player can not click this if he does not have a homunculus or it is vaporized
if( sd->hd == nullptr || sd->hd->homunculus.vaporize ){
return;
}
sd->hd->homunculus.autofeed = flag;
break;
default:
ShowWarning( "clif_parse_configuration: received unknown configuration type '%d'...\n", type );
return;
}
clif_configuration( sd, static_cast<e_config_type>(type), flag );
}
/// Request to change party invitation tick.

View File

@ -536,6 +536,13 @@ enum e_damage_type : uint8_t {
DMG_TOUCH, /// (touch skill?)
};
enum e_config_type : uint32 {
CONFIG_OPEN_EQUIPMENT_WINDOW = 0,
// Unknown
CONFIG_PET_AUTOFEED = 2,
CONFIG_HOMUNCULUS_AUTOFEED
};
int clif_setip(const char* ip);
void clif_setbindip(const char* ip);
void clif_setport(uint16 port);
@ -862,7 +869,7 @@ void clif_homskillup(struct map_session_data *sd, uint16 skill_id); //[orn]
int clif_hom_food(struct map_session_data *sd,int foodid,int fail); //[orn]
void clif_send_homdata(struct map_session_data *sd, int state, int param); //[orn]
void clif_equiptickack(struct map_session_data* sd, int flag);
void clif_configuration( struct map_session_data* sd, enum e_config_type type, bool enabled );
void clif_partytickack(struct map_session_data* sd, bool flag);
void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd);
void clif_equipcheckbox(struct map_session_data* sd);

View File

@ -1123,7 +1123,7 @@
packet(0x02d5,2);
parseable_packet(0x02d6,6,clif_parse_ViewPlayerEquip,2);
packet(0x02d7,-1);
parseable_packet(0x02d8,10,clif_parse_EquipTick,2,6);
parseable_packet(0x02d8,10,clif_parse_configuration,2,6);
packet(0x02d9,10);
packet(0x02da,3);
parseable_packet(0x02db,-1,clif_parse_BattleChat,2,4);

View File

@ -4008,6 +4008,7 @@
parseable_packet(0x0281,6,clif_parse_GetCharNameRequest,2);
// 2017-09-13bRagexeRE
#elif PACKETVER == 20170913
parseable_packet(0x0281,6,clif_parse_GetCharNameRequest,2);
parseable_packet(0x035F,26,clif_parse_FriendsListAdd,2);
parseable_packet(0x0437,-1,clif_parse_SearchStoreInfo,2,4,5,9,13,14,15);
parseable_packet(0x07E4,8,clif_parse_MoveFromKafra,2,4);

View File

@ -892,6 +892,10 @@ static int hom_hungry(int tid, unsigned int tick, int id, intptr_t data)
clif_emotion(&hd->bl, ET_OK);
}
if( battle_config.feature_homunculus_autofeed && hd->homunculus.autofeed && hd->homunculus.hunger <= battle_config.feature_homunculus_autofeed_rate ){
hom_food( sd, hd );
}
if (hd->homunculus.hunger < 0) {
hd->homunculus.hunger = 0;
// Delete the homunculus if intimacy <= 100