summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/char_sql/int_homun.c10
-rw-r--r--src/map/battle.c88
-rw-r--r--src/map/clif.c39
-rw-r--r--src/map/clif.h1
-rw-r--r--src/map/mercenary.c67
-rw-r--r--src/map/mercenary.h5
-rw-r--r--src/map/script.c24
-rw-r--r--src/map/unit.c7
8 files changed, 180 insertions, 61 deletions
diff --git a/src/char_sql/int_homun.c b/src/char_sql/int_homun.c
index 9fedfe978..17633ef4a 100644
--- a/src/char_sql/int_homun.c
+++ b/src/char_sql/int_homun.c
@@ -342,11 +342,11 @@ bool mapif_mercenary_load(int merc_id, int char_id, struct s_mercenary *merc)
return false;
}
- Sql_GetData(sql_handle, 1, &data, NULL); merc->class_ = atoi(data);
- Sql_GetData(sql_handle, 2, &data, NULL); merc->hp = atoi(data);
- Sql_GetData(sql_handle, 3, &data, NULL); merc->sp = atoi(data);
- Sql_GetData(sql_handle, 4, &data, NULL); merc->kill_count = atoi(data);
- Sql_GetData(sql_handle, 5, &data, NULL); merc->remain_life_time = atoi(data);
+ Sql_GetData(sql_handle, 0, &data, NULL); merc->class_ = atoi(data);
+ Sql_GetData(sql_handle, 1, &data, NULL); merc->hp = atoi(data);
+ Sql_GetData(sql_handle, 2, &data, NULL); merc->sp = atoi(data);
+ Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data);
+ Sql_GetData(sql_handle, 4, &data, NULL); merc->remain_life_time = atoi(data);
Sql_FreeResult(sql_handle);
if( save_log )
ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id);
diff --git a/src/map/battle.c b/src/map/battle.c
index ee2f5a2a3..2ea509299 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -16,6 +16,7 @@
#include "status.h"
#include "skill.h"
#include "homunculus.h"
+#include "mercenary.h"
#include "mob.h"
#include "itemdb.h"
#include "clif.h"
@@ -3027,6 +3028,10 @@ struct block_list* battle_get_master(struct block_list *src)
if (((TBL_HOM*)src)->master)
src = (struct block_list*)((TBL_HOM*)src)->master;
break;
+ case BL_MER:
+ if (((TBL_MER*)src)->master)
+ src = (struct block_list*)((TBL_MER*)src)->master;
+ break;
case BL_SKILL:
if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id)
src = map_id2bl(((TBL_SKILL*)src)->group->src_id);
@@ -3050,7 +3055,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
{
int m,state = 0; //Initial state none
int strip_enemy = 1; //Flag which marks whether to remove the BCT_ENEMY status if it's also friend/ally.
- struct block_list *s_bl= src, *t_bl= target;
+ struct block_list *s_bl = src, *t_bl = target;
nullpo_retr(0, src);
nullpo_retr(0, target);
@@ -3059,13 +3064,13 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
//t_bl/s_bl hold the 'master' of the attack, while src/target are the actual
//objects involved.
- if ((t_bl = battle_get_master(target)) == NULL)
+ if( (t_bl = battle_get_master(target)) == NULL )
t_bl = target;
- if ((s_bl = battle_get_master(src)) == NULL)
+ if( (s_bl = battle_get_master(src)) == NULL )
s_bl = src;
- switch (target->type)
+ switch( target->type )
{ //Checks on actual target
case BL_PC:
if (((TBL_PC*)target)->invincible_timer != -1 || pc_isinvisible((TBL_PC*)target))
@@ -3109,6 +3114,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
}
break;
//Valid targets with no special checks here.
+ case BL_MER:
case BL_HOM:
break;
//All else not specified is an invalid target.
@@ -3116,34 +3122,35 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
return 0;
}
- switch (t_bl->type)
+ switch( t_bl->type )
{ //Checks on target master
case BL_PC:
{
- TBL_PC *sd = (TBL_PC*)t_bl;
- if (sd->status.karma && t_bl != s_bl && s_bl->type == BL_PC &&
- ((TBL_PC*)s_bl)->status.karma)
- state |= BCT_ENEMY; //Characters with bad karma may fight amongst them.
- if (sd->state.monster_ignore && t_bl != s_bl && flag&BCT_ENEMY)
- return 0; //Global inmunity to attacks.
- if (sd->state.killable && t_bl != s_bl)
- {
- state |= BCT_ENEMY; //Universal Victim
+ struct map_session_data *sd;
+ if( t_bl == s_bl ) break;
+ sd = BL_CAST(BL_PC, t_bl);
+
+ if( sd->state.monster_ignore && flag&BCT_ENEMY )
+ return 0; // Global inminuty only to Attacks
+ if( sd->status.karma && s_bl->type == BL_PC && ((TBL_PC*)s_bl)->status.karma )
+ state |= BCT_ENEMY; // Characters with bad karma may fight amongst them
+ if( sd->state.killable ) {
+ state |= BCT_ENEMY; // Everything can kill it
strip_enemy = 0;
}
break;
}
case BL_MOB:
{
- TBL_MOB *md = (TBL_MOB*)t_bl;
+ struct mob_data *md = BL_CAST(BL_MOB, t_bl);
- if (!(agit_flag && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id)
- return 0; //Disable guardians/emperiums owned by Guilds on non-woe times.
+ if( !(agit_flag && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id )
+ return 0; // Disable guardians/emperiums owned by Guilds on non-woe times.
break;
}
}
- switch(src->type)
+ switch( src->type )
{ //Checks on actual src type
case BL_PET:
if (t_bl->type != BL_MOB && flag&BCT_ENEMY)
@@ -3170,26 +3177,24 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
}
}
- switch (s_bl->type)
+ switch( s_bl->type )
{ //Checks on source master
case BL_PC:
{
- TBL_PC *sd = (TBL_PC*) s_bl;
+ struct map_session_data *sd = BL_CAST(BL_PC, s_bl);
if( s_bl != t_bl )
{
if( sd->state.killer )
{
- state |= BCT_ENEMY; //Is on a killing rampage :O
+ state |= BCT_ENEMY; // Can kill anything
strip_enemy = 0;
}
else if( sd->duel_group && !((!battle_config.duel_allow_pvp && map[m].flag.pvp) || (!battle_config.duel_allow_gvg && map_flag_gvg(m))) )
{
- if (t_bl->type == BL_PC &&
- (sd->duel_group == ((TBL_PC*)t_bl)->duel_group))
- //Duel targets can ONLY be your enemy, nothing else.
- return (BCT_ENEMY&flag)?1:-1;
- else // You can't target anything out of your duel
- return 0;
+ if( t_bl->type == BL_PC && (sd->duel_group == ((TBL_PC*)t_bl)->duel_group) )
+ return (BCT_ENEMY&flag)?1:-1; // Duel targets can ONLY be your enemy, nothing else.
+ else
+ return 0; // You can't target anything out of your duel
}
}
if (map_flag_gvg(m) && !sd->status.guild_id &&
@@ -3201,20 +3206,21 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
}
case BL_MOB:
{
- TBL_MOB*md = (TBL_MOB*)s_bl;
- if (!(agit_flag && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id)
- return 0; //Disable guardians/emperium owned by Guilds on non-woe times.
-
- { //Smart enemy criteria.
- if (!md->special_state.ai) { //Normal mobs.
- if (t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai)
- state |= BCT_PARTY; //Normal mobs with no ai are friends.
- else
- state |= BCT_ENEMY; //However, all else are enemies.
- } else {
- if (t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai)
- state |= BCT_ENEMY; //Natural enemy for AI mobs are normal mobs.
- }
+ struct mob_data *md = BL_CAST(BL_MOB, s_bl);
+ if( !(agit_flag && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id )
+ return 0; // Disable guardians/emperium owned by Guilds on non-woe times.
+
+ if( !md->special_state.ai )
+ { //Normal mobs.
+ if( t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai )
+ state |= BCT_PARTY; //Normal mobs with no ai are friends.
+ else
+ state |= BCT_ENEMY; //However, all else are enemies.
+ }
+ else
+ {
+ if( t_bl->type == BL_MOB && !((TBL_MOB*)t_bl)->special_state.ai )
+ state |= BCT_ENEMY; //Natural enemy for AI mobs are normal mobs.
}
break;
}
diff --git a/src/map/clif.c b/src/map/clif.c
index a66f2b393..69534c9ed 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -11306,11 +11306,21 @@ void clif_parse_HomMoveTo(int fd, struct map_session_data *sd)
}
void clif_parse_HomAttack(int fd,struct map_session_data *sd)
-{ //[orn]
- if(!merc_is_hom_active(sd->hd))
- return;
-
- unit_attack(&sd->hd->bl,RFIFOL(fd,6),0) ;
+{
+ struct block_list *bl = NULL;
+ int id = RFIFOL(fd,2),
+ target_id = RFIFOL(fd,6),
+ action_type = RFIFOB(fd,10);
+
+ if( merc_is_hom_active(sd->hd) && sd->hd->bl.id == id )
+ bl = &sd->hd->bl;
+ else if( sd->md && sd->md->bl.id == id )
+ bl = &sd->md->bl;
+ else return;
+
+ unit_stop_walking(bl, 1);
+ unit_stop_attack(bl);
+ unit_attack(bl, target_id, action_type != 0);
}
void clif_parse_HomMenu(int fd, struct map_session_data *sd)
@@ -12386,10 +12396,10 @@ void clif_mercenary_info(struct map_session_data *sd)
WFIFOL(fd,52) = status->max_hp;
WFIFOL(fd,56) = status->sp;
WFIFOL(fd,60) = status->max_sp;
- WFIFOL(fd,64) = 0; // Contract End
+ WFIFOL(fd,64) = (int)time(NULL) + (md->mercenary.remain_life_time / 1000);
WFIFOW(fd,68) = 0; // Loyalty
WFIFOL(fd,70) = 0; // Summon Count
- WFIFOL(fd,74) = 0; // Kill Counter
+ WFIFOL(fd,74) = md->mercenary.kill_count;
WFIFOW(fd,78) = 0;
WFIFOSET(fd,80);
}
@@ -12461,6 +12471,21 @@ void clif_parse_mercenary_action(int fd, struct map_session_data* sd)
return;
}
+/*------------------------------------------
+ * Mercenary Message
+ * 0 = Mercenary soldier's duty hour is over.
+ * 1 = Your mercenary soldier has been killed.
+ * 2 = Your mercenary soldier has been fired.
+ * 3 = Your mercenary soldier has ran away.
+ *------------------------------------------*/
+void clif_mercenary_message(int fd, int message)
+{
+ WFIFOHEAD(fd,4);
+ WFIFOW(fd,0) = 0x0291;
+ WFIFOW(fd,2) = 1266 + message;
+ WFIFOSET(fd,4);
+}
+
/*==========================================
* パケットデバッグ
*------------------------------------------*/
diff --git a/src/map/clif.h b/src/map/clif.h
index f136d4424..5bd7ca67a 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -442,5 +442,6 @@ void clif_Adopt_reply(struct map_session_data *sd, int type);
// MERCENARIES
void clif_mercenary_info(struct map_session_data *sd);
void clif_mercenary_skillblock(struct map_session_data *sd);
+void clif_mercenary_message(int fd, int message);
#endif /* _CLIF_H_ */
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 1435a89da..e324ec7ab 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.c
@@ -86,13 +86,75 @@ int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime)
int mercenary_save(struct mercenary_data *md)
{
+ const struct TimerData * td = get_timer(md->contract_timer);
+
md->mercenary.hp = md->battle_status.hp;
md->mercenary.sp = md->battle_status.sp;
- intif_mercenary_save(&md->mercenary);
+ if( td != NULL )
+ md->mercenary.remain_life_time = DIFF_TICK(td->tick, gettick());
+ else
+ {
+ md->mercenary.remain_life_time = 0;
+ ShowWarning("mercenary_save : mercenary without timer (tid %d)\n", md->contract_timer);
+ }
+ intif_mercenary_save(&md->mercenary);
return 1;
}
+static int merc_contract_end(int tid, unsigned int tick, int id, intptr data)
+{
+ struct map_session_data *sd;
+ struct mercenary_data *md;
+
+ if( (sd = map_id2sd(id)) == NULL )
+ return 1;
+ if( (md = sd->md) == NULL )
+ return 1;
+
+ if( md->contract_timer != tid )
+ {
+ ShowError("merc_contract_end %d != %d.\n", md->contract_timer, tid);
+ return 0;
+ }
+
+ md->contract_timer = INVALID_TIMER;
+ merc_delete(md, 0); // Mercenary soldier's duty hour is over.
+
+ return 0;
+}
+
+int merc_delete(struct mercenary_data *md, int reply)
+{
+ struct map_session_data *sd = md->master;
+ md->mercenary.remain_life_time = 0;
+
+ if( md->contract_timer != INVALID_TIMER )
+ delete_timer(md->contract_timer, merc_contract_end);
+
+ if( !sd )
+ return unit_free(&md->bl, 1);
+ clif_mercenary_message(sd->fd, reply);
+
+ return unit_remove_map(&md->bl, 1);
+}
+
+void merc_contract_stop(struct mercenary_data *md)
+{
+ nullpo_retv(md);
+ if( md->contract_timer != INVALID_TIMER )
+ delete_timer(md->contract_timer, merc_contract_end);
+ md->contract_timer = INVALID_TIMER;
+}
+
+void merc_contract_init(struct mercenary_data *md)
+{
+ if( md->contract_timer == INVALID_TIMER )
+ md->contract_timer = add_timer(gettick() + md->mercenary.remain_life_time, merc_contract_end, md->master->bl.id, 0);
+
+ md->regen.state.block = 0;
+}
+
int merc_data_received(struct s_mercenary *merc, bool flag)
{
struct map_session_data *sd;
@@ -134,6 +196,7 @@ int merc_data_received(struct s_mercenary *merc, bool flag)
map_addiddb(&md->bl);
status_calc_mercenary(md,1);
+ md->contract_timer = INVALID_TIMER;
}
else
memcpy(&sd->md->mercenary, merc, sizeof(struct s_mercenary));
@@ -145,7 +208,7 @@ int merc_data_received(struct s_mercenary *merc, bool flag)
clif_spawn(&md->bl);
clif_mercenary_info(sd);
clif_mercenary_skillblock(sd);
- // init timers
+ merc_contract_init(md);
}
return 1;
diff --git a/src/map/mercenary.h b/src/map/mercenary.h
index 3bca79485..bc2046dc7 100644
--- a/src/map/mercenary.h
+++ b/src/map/mercenary.h
@@ -32,7 +32,8 @@ struct mercenary_data {
struct s_mercenary_db *db;
struct s_mercenary mercenary;
- struct map_session_data *master; // Master of mercenary
+ struct map_session_data *master;
+ int contract_timer;
};
bool merc_class(int class_);
@@ -41,5 +42,7 @@ int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime);
int merc_data_received(struct s_mercenary *merc, bool flag);
int mercenary_save(struct mercenary_data *md);
int do_init_mercenary(void);
+int merc_delete(struct mercenary_data *md, int reply);
+void merc_contract_stop(struct mercenary_data *md);
#endif /* _MERCENARY_H_ */
diff --git a/src/map/script.c b/src/map/script.c
index ab75f0771..05d7a0736 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -28,6 +28,7 @@
#include "pet.h"
#include "mapreg.h"
#include "homunculus.h"
+#include "mercenary.h"
#include "intif.h"
#include "skill.h"
#include "status.h"
@@ -12792,6 +12793,28 @@ BUILDIN_FUNC(setcell)
return 0;
}
+/*==========================================
+ * Mercenary Commands
+ *------------------------------------------*/
+BUILDIN_FUNC(createmercenary)
+{
+ struct map_session_data *sd;
+ int class_, contract_time;
+
+ if( (sd = script_rid2sd(st)) == NULL || sd->md || sd->status.mer_id != 0 )
+ return 0;
+
+ class_ = script_getnum(st,2);
+
+ if( !merc_class(class_) )
+ return 0;
+
+ contract_time = script_getnum(st,3);
+ merc_create(sd, class_, contract_time);
+
+ return 0;
+}
+
/******************
Questlog script commands
*******************/
@@ -13222,5 +13245,6 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(hasquest, "i"),
BUILDIN_DEF(setwall,"siiiiis"),
BUILDIN_DEF(delwall,"s"),
+ BUILDIN_DEF(createmercenary,"ii"),
{NULL,NULL,NULL},
};
diff --git a/src/map/unit.c b/src/map/unit.c
index d5c452148..6299175d6 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -1258,9 +1258,8 @@ int unit_attack(struct block_list *src,int target_id,int continuous)
}
}
- if(battle_check_target(src,target,BCT_ENEMY)<=0 ||
- !status_check_skilluse(src, target, 0, 0)
- ) {
+ if( battle_check_target(src,target,BCT_ENEMY) <= 0 || !status_check_skilluse(src, target, 0, 0) )
+ {
unit_unattackable(src);
return 1;
}
@@ -2065,7 +2064,6 @@ int unit_free(struct block_list *bl, int clrtype)
{
struct homun_data *hd = (TBL_HOM*)bl;
struct map_session_data *sd = hd->master;
- // Desactive timers
merc_hom_hungry_timer_delete(hd);
if( clrtype >= 0 )
{
@@ -2086,7 +2084,6 @@ int unit_free(struct block_list *bl, int clrtype)
{
struct mercenary_data *md = (TBL_MER*)bl;
struct map_session_data *sd = md->master;
- /* Stop Mercenary Timer */
if( clrtype >= 0 )
{
if( md->mercenary.remain_life_time > 0 )