diff options
author | zephyrus <zephyrus@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2008-08-24 22:45:32 +0000 |
---|---|---|
committer | zephyrus <zephyrus@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2008-08-24 22:45:32 +0000 |
commit | 9bf4c93d86a081c0c1254613d5115e8210e035ec (patch) | |
tree | 7047ed6cbdfca59eb5860e42dc9a5fbc1c9245c3 /src | |
parent | 2600d527592c3e5c6ed6ab827ce69c24f3c6b35b (diff) | |
download | hercules-9bf4c93d86a081c0c1254613d5115e8210e035ec.tar.gz hercules-9bf4c93d86a081c0c1254613d5115e8210e035ec.tar.bz2 hercules-9bf4c93d86a081c0c1254613d5115e8210e035ec.tar.xz hercules-9bf4c93d86a081c0c1254613d5115e8210e035ec.zip |
- Implemented Mercenary Scrolls (item_db)
- There are some little problems, like remaining time going to 0, but you can summon it, make it walk, follow you.
- Feel free to test it.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13126 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r-- | src/char_sql/int_homun.c | 10 | ||||
-rw-r--r-- | src/map/battle.c | 88 | ||||
-rw-r--r-- | src/map/clif.c | 39 | ||||
-rw-r--r-- | src/map/clif.h | 1 | ||||
-rw-r--r-- | src/map/mercenary.c | 67 | ||||
-rw-r--r-- | src/map/mercenary.h | 5 | ||||
-rw-r--r-- | src/map/script.c | 24 | ||||
-rw-r--r-- | src/map/unit.c | 7 |
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 ) |