summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/battle/homunc.conf8
-rw-r--r--db/re/exp_homun.txt51
-rw-r--r--doc/script_commands.txt13
-rw-r--r--npc/re/quests/homu_s.txt236
-rw-r--r--npc/re/scripts_athena.conf1
-rw-r--r--src/map/battle.c2
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/clif.c10
-rw-r--r--src/map/homunculus.c85
-rw-r--r--src/map/homunculus.h35
-rw-r--r--src/map/script.c31
11 files changed, 462 insertions, 12 deletions
diff --git a/conf/battle/homunc.conf b/conf/battle/homunc.conf
index 8349aae64..6ebd43bec 100644
--- a/conf/battle/homunc.conf
+++ b/conf/battle/homunc.conf
@@ -30,10 +30,16 @@ hom_rename: no
hvan_explosion_intimate: 45000
// Show stat growth to the owner when an Homunculus levels up
-homunculus_show_growth: no
+homunculus_show_growth: yes
// Does autoloot work, when a monster is killed by homunculus only?
homunculus_autoloot: yes
// Should homunculii Vaporize when Master dies?
homunculus_auto_vapor: yes
+
+// Max level for regular Homunculus
+homunculus_max_level: 99
+
+// Max level for Homunculus S
+homunculus_S_max_level: 150
diff --git a/db/re/exp_homun.txt b/db/re/exp_homun.txt
index 814e4c6a4..3c479cfa4 100644
--- a/db/re/exp_homun.txt
+++ b/db/re/exp_homun.txt
@@ -97,4 +97,55 @@
2280000
2660000
3135000
+3800000
+4124000
+4260000
+4462000
+4527000
+4779000
+4921000
+4984000
+5118000
+5353000
+5438000
+5507000
+5610000
+5776000
+5867000
+6000000
+6116000
+6241000
+6373000
+6498000
+6639000
+6720000
+6907000
+7025000
+7105000
+7264000
+7454000
+7611000
+7688000
+7735000
+7940000
+8020000
+8198000
+8318000
+8376000
+8469000
+8528000
+8573000
+8650000
+8701000
+8769000
+8814000
+8820000
+8826000
+8838000
+8887000
+8905000
+8916000
+8922000
+8966000
+9094000
0
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 662bbbae7..d50ee5184 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -5316,6 +5316,19 @@ the homunculus must have above 91000 intimacy with it's owner.
---------------------------------------
+*hommutate {<ID>};
+
+This Command will evolve the current player's Homunculus into the new Homunculus S.
+If it doesn't work, the /swt emotion is shown.
+
+To change a Homunculus into the new Homunculus S,
+the invoking Player must have an evolved Homunculus and it must be at least Level 99.
+
+If the optional parameter <ID> is set, the invoking Players Homunculus will change into the given ID's Homunculus S,
+otherwise the Homunculus will change into an randomly chosen Homunculus S Class.
+
+---------------------------------------
+
*unitwalk <GID>,<x>,<y>;
*unitwalk <GID>,<mapid>;
diff --git a/npc/re/quests/homu_s.txt b/npc/re/quests/homu_s.txt
new file mode 100644
index 000000000..dda0ad7ee
--- /dev/null
+++ b/npc/re/quests/homu_s.txt
@@ -0,0 +1,236 @@
+//===== rAthena Script =======================================
+//= Homunculus S Quest
+//===== By: ==================================================
+//= Masao
+//===== Current Version: =====================================
+//= 1.0
+//===== Compatible With: =====================================
+//= rAthena SVN
+//===== Description: =========================================
+//= Evolves an Homunculus which is at least Level 99 to the
+//= new Homunculus S Class.
+//===== Additional Comments: =================================
+//= 1.0 First Version. The actual changing dialog is currently
+//= customized. [Masao]
+//============================================================
+
+job3_gen01,12,44,4 script Viorel#job3_gen01 542,{
+
+ if((Class != Job_Genetic) && (Class != Job_Genetic_T) && (Class != Job_Baby_Genetic)){
+ mes "[Viorel]";
+ mes "^FF4800Homunculus^000000 research requires a lot of time and funding.";
+ mes "However, I believe passion is the most important factor.";
+ next;
+ switch(select("End conversation.:What are you talking about?:Why are you always standing there?")) {
+ case 1:
+ mes "[Viorel]";
+ mes "So long~!";
+ close;
+ case 2:
+ mes "[Viorel]";
+ mes "You see, ^006400Alchemists^000000 have an inquisitive nature.";
+ mes "People like me, especially, even think of creating life itself.";
+ next;
+ mes "[Viorel]";
+ mes "You'd have to research ^FF4800Homunculus^000000 to understand.";
+ mes "Now, if you'll excuse me~!";
+ close;
+ case 3:
+ emotion 4,0;
+ mes "[Viorel]";
+ mes "What, is it so strange to see an Alchemist in their own lab?";
+ mes "How so?";
+ close;
+ }
+ }
+ mes "[Viorel]";
+ mes "Hello "+strcharinfo(0)+",";
+ mes "what can I do for an fellow Alchemist like you?";
+ next;
+ switch(select("I want to evolve my Homunculus:About Homunculus S:Cancel")){
+ case 1:
+ mes "[Viorel]";
+ if(!getskilllv("AM_BIOETHICS")){
+ mes "I'm sorry but you must know the Skill Bioethics! Otherwise I can't let your Homunculus evolve into an Homunculus S.";
+ close;
+ }
+ if(gethominfo(1) < 6009){
+ mes "I'm sorry but you must have an evolved Homunculus, otherwise you can't let it evolve to the new Homunculus S.";
+ close;
+ }
+ if(gethominfo(6) < 99){
+ mes "I'm sorry but to evolve your Homunculus to the next level it must be Level 99!";
+ mes "Come back after you've trained your Homunculus a little bit more.";
+ close;
+ }
+ if(gethominfo(1) == 6048 || gethominfo(1) == 6049 || gethominfo(1) == 6050 || gethominfo(1) == 6051 || gethominfo(1) == 6052){
+ mes "Your Homunculus S looks great!";
+ mes "I hope you wil experience many great adventures with it!";
+ close;
+ }
+ mes "Great, it seems like you're all ready to get your Homunculus to the next level!";
+ next;
+ mes "[Viorel]";
+ mes "Now if you want to you can either directly change your Homunculus to an new random Homunculus S Form or you can donate a little fee";
+ mes "of 50'000 zeny to the Alchemist Guild and for this you'll be able to change your Homunculus into your desired Homunculus S Class!";
+ mes "So, what do you think?";
+ next;
+ switch(Select("I want to Donate:I don't want to Donate:Cancel")){
+ case 1:
+ if(Zeny < 50000){
+ mes "[Viorel]";
+ mes "Haha, nice try my friend! But you don't even have the 50'000 zeny to donate!";
+ mes "Come back if you have the zeny, thanks.";
+ close;
+ }
+ mes "[Viorel]";
+ mes "Allright, now please tell me which Homunculus you'd like to have:";
+ next;
+ switch(select("Eira:Bayeri:Sera:Dieter:Elanor:Cancel")){
+ case 1:
+ mes "[Viorel]";
+ mes "Ok, it's all set! Now just give me a moment!";
+ next;
+ mes "[Viorel]";
+ mes "Abra...";
+ next;
+ mes "[Viorel]";
+ mes "Kadabra...";
+ next;
+ mes "[Viorel]";
+ mes "Simsala!";
+ mes "...";
+ mes "Oh sorry.. wrong game!";
+ next;
+ mes "[Viorel]";
+ mes "Here you go! Your new Homunculus S!";
+ hommutate 6048;
+ set Zeny,Zeny - 50000;
+ close;
+ case 2:
+ mes "[Viorel]";
+ mes "Ok, it's all set! Now just give me a moment!";
+ next;
+ mes "[Viorel]";
+ mes "Abra...";
+ next;
+ mes "[Viorel]";
+ mes "Kadabra...";
+ next;
+ mes "[Viorel]";
+ mes "Simsala!";
+ mes "...";
+ mes "Oh sorry.. wrong game!";
+ next;
+ mes "[Viorel]";
+ mes "Here you go! Your new Homunculus S!";
+ hommutate 6049;
+ set Zeny,Zeny - 50000;
+ close;
+ case 3:
+ mes "[Viorel]";
+ mes "Ok, it's all set! Now just give me a moment!";
+ next;
+ mes "[Viorel]";
+ mes "Abra...";
+ next;
+ mes "[Viorel]";
+ mes "Kadabra...";
+ next;
+ mes "[Viorel]";
+ mes "Simsala!";
+ mes "...";
+ mes "Oh sorry.. wrong game!";
+ next;
+ mes "[Viorel]";
+ mes "Here you go! Your new Homunculus S!";
+ hommutate 6050;
+ set Zeny,Zeny - 50000;
+ close;
+ case 4:
+ mes "[Viorel]";
+ mes "Ok, it's all set! Now just give me a moment!";
+ next;
+ mes "[Viorel]";
+ mes "Abra...";
+ next;
+ mes "[Viorel]";
+ mes "Kadabra...";
+ next;
+ mes "[Viorel]";
+ mes "Simsala!";
+ mes "...";
+ mes "Oh sorry.. wrong game!";
+ next;
+ mes "[Viorel]";
+ mes "Here you go! Your new Homunculus S!";
+ hommutate 6051;
+ set Zeny,Zeny - 50000;
+ close;
+ case 5:
+ mes "[Viorel]";
+ mes "Ok, it's all set! Now just give me a moment!";
+ next;
+ mes "[Viorel]";
+ mes "Abra...";
+ next;
+ mes "[Viorel]";
+ mes "Kadabra...";
+ next;
+ mes "[Viorel]";
+ mes "Simsala!";
+ mes "...";
+ mes "Oh sorry.. wrong game!";
+ next;
+ mes "[Viorel]";
+ mes "Here you go! Your new Homunculus S!";
+ hommutate 6052;
+ set Zeny,Zeny - 50000;
+ close;
+ case 6:
+ mes "[Viorel]";
+ mes "So long~!";
+ close;
+ }
+ case 2:
+ mes "[Viorel]";
+ mes "Ok, it's all set! Now just give me a moment!";
+ next;
+ mes "[Viorel]";
+ mes "Abra...";
+ next;
+ mes "[Viorel]";
+ mes "Kadabra...";
+ next;
+ mes "[Viorel]";
+ mes "Simsala!";
+ mes "...";
+ mes "Oh sorry.. wrong game!";
+ next;
+ mes "[Viorel]";
+ mes "Here you go! Your new Homunculus S!";
+ hommutate;
+ close;
+ case 3:
+ mes "[Viorel]";
+ mes "So long~!";
+ close;
+ }
+ case 2:
+ mes "[Viorel]";
+ mes "The Homunculus S are the new and improved Versions of the current Homunculus you know.";
+ mes "These new Homunculus have been made since the Monsters in our World keep getting stronger and stronger";
+ mes "and our current loyal Homunculus are just not able to keep up with them anymore so they can't";
+ mes "protect their Masters anymore!";
+ next;
+ mes "[Viorel]";
+ mes "But since we're Alchemists and we don't want to abandon our precious Homunculus we found a Way to improve their";
+ mes "skills and strength in order to keep them by our side and joining us once more in battle!";
+ mes "Isn't that great?";
+ close;
+ case 3:
+ mes "[Viorel]";
+ mes "So long~!";
+ close;
+ }
+} \ No newline at end of file
diff --git a/npc/re/scripts_athena.conf b/npc/re/scripts_athena.conf
index bdca69bcb..4e02ec6b3 100644
--- a/npc/re/scripts_athena.conf
+++ b/npc/re/scripts_athena.conf
@@ -214,6 +214,7 @@ npc: npc/re/quests/eden/56-70.txt
npc: npc/re/quests/eden/71-85.txt
npc: npc/re/quests/eden/86-90.txt
npc: npc/re/quests/eden/91-99.txt
+npc: npc/re/quests/homu_s.txt
// --------------------------------------------------------------
// --------------------------- Guides ---------------------------
npc: npc/re/guides/guides_alberta.txt
diff --git a/src/map/battle.c b/src/map/battle.c
index eab699c94..02cb4b466 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -5446,6 +5446,8 @@ static const struct _battle_data {
{ "feature.atcommand_suggestions", &battle_config.atcommand_suggestions_enabled, 0, 0, 1 },
{ "min_npc_vending_distance", &battle_config.min_npc_vending_distance, 3, 0, 100 },
{ "atcommand_mobinfo_type", &battle_config.atcommand_mobinfo_type, 0, 0, 1 },
+ { "homunculus_max_level", &battle_config.hom_max_level, 99, 0, MAX_LEVEL, },
+ { "homunculus_S_max_level", &battle_config.hom_S_max_level, 150, 0, MAX_LEVEL, },
};
diff --git a/src/map/battle.h b/src/map/battle.h
index 0e98e49ae..7048e35a8 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -455,6 +455,8 @@ extern struct Battle_Config
int cashshop_show_points;
int mail_show_status;
int client_limit_unit_lv;
+ int hom_max_level;
+ int hom_S_max_level;
// [BattleGround Settings]
int bg_update_interval;
diff --git a/src/map/clif.c b/src/map/clif.c
index a35e0fa49..7b3e9e650 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -1395,10 +1395,13 @@ void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag)
{
struct status_data *status;
unsigned char buf[128];
+ int m_class;
nullpo_retv(hd);
- status = &hd->battle_status;
+ status = &hd->battle_status;
+ m_class = hom_class2mapid(hd->homunculus.class_);
+
memset(buf,0,packet_len(0x22e));
WBUFW(buf,0)=0x22e;
memcpy(WBUFP(buf,2),hd->homunculus.name,NAME_LENGTH);
@@ -1434,7 +1437,10 @@ void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag)
WBUFW(buf,57)=status->max_sp;
}
WBUFL(buf,59)=hd->homunculus.exp;
- WBUFL(buf,63)=hd->exp_next;
+ if( ((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level) || ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level) )
+ WBUFL(buf,63)=0;
+ else
+ WBUFL(buf,63)=hd->exp_next;
WBUFW(buf,67)=hd->homunculus.skillpts;
WBUFW(buf,69)=status_get_range(&hd->bl);
clif_send(buf,packet_len(0x22e),&sd->bl,SELF);
diff --git a/src/map/homunculus.c b/src/map/homunculus.c
index e77b5d093..6787ca43d 100644
--- a/src/map/homunculus.c
+++ b/src/map/homunculus.c
@@ -56,6 +56,31 @@ struct view_data* merc_get_hom_viewdata(int class_)
return NULL;
}
+int hom_class2mapid(int hom_class)
+{
+ switch(hom_class)
+ {
+ // Normal Homunculus
+ case 6001: case 6005: return MAPID_LIF;
+ case 6002: case 6006: return MAPID_AMISTR;
+ case 6003: case 6007: return MAPID_FILIR;
+ case 6004: case 6008: return MAPID_VANILMIRTH;
+ // Evolved Homunculus
+ case 6009: case 6013: return MAPID_LIF_E;
+ case 6010: case 6014: return MAPID_AMISTR_E;
+ case 6011: case 6015: return MAPID_FILIR_E;
+ case 6012: case 6016: return MAPID_VANILMIRTH_E;
+ // Homunculus S
+ case 6048: return MAPID_EIRA;
+ case 6049: return MAPID_BAYERI;
+ case 6050: return MAPID_SERA;
+ case 6051: return MAPID_DIETER;
+ case 6052: return MAPID_ELANOR;
+
+ default: return -1;
+ }
+}
+
void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp)
{
clif_hominfo(hd->master,hd,0);
@@ -215,10 +240,13 @@ int merc_hom_levelup(struct homun_data *hd)
int growth_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ;
int growth_max_hp, growth_max_sp ;
char output[256] ;
+ int m_class;
- if (hd->homunculus.level == MAX_LEVEL || !hd->exp_next || hd->homunculus.exp < hd->exp_next)
+ m_class = hom_class2mapid(hd->homunculus.class_);
+
+ if((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level || (m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level || !hd->exp_next || hd->homunculus.exp < hd->exp_next)
return 0 ;
-
+
hom = &hd->homunculus;
hom->level++ ;
if (!(hom->level % 3))
@@ -333,13 +361,62 @@ int merc_hom_evolution(struct homun_data *hd)
return 1 ;
}
+int hom_mutate(struct homun_data *hd, int homun_id)
+{
+ struct s_homunculus *hom;
+ struct map_session_data *sd;
+ int m_class, m_id;
+ nullpo_ret(hd);
+
+ m_class = hom_class2mapid(hd->homunculus.class_);
+ m_id = hom_class2mapid(homun_id);
+
+ if( !m_class&HOM_EVO || !m_id&HOM_S ) {
+ clif_emotion(&hd->bl, E_SWT);
+ return 0;
+ }
+
+ sd = hd->master;
+ if (!sd)
+ return 0;
+
+ if (!merc_hom_change_class(hd, homun_id)) {
+ ShowError("hom_mutate: Can't evolve homunc from %d to %d", hd->homunculus.class_, homun_id);
+ return 0;
+ }
+
+ unit_remove_map(&hd->bl, CLR_OUTSIGHT);
+ map_addblock(&hd->bl);
+
+ clif_spawn(&hd->bl);
+ clif_emotion(&sd->bl, E_NO1);
+ clif_specialeffect(&hd->bl,568,AREA);
+
+ //status_Calc flag&1 will make current HP/SP be reloaded from hom structure
+ hom = &hd->homunculus;
+ hom->hp = hd->battle_status.hp;
+ hom->sp = hd->battle_status.sp;
+ status_calc_homunculus(hd,1);
+
+ if (!(battle_config.hom_setting&0x2))
+ skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately
+
+ return 1;
+}
+
int merc_hom_gainexp(struct homun_data *hd,int exp)
{
+ int m_class;
+
if(hd->homunculus.vaporize)
return 1;
- if( hd->exp_next == 0 ) {
- hd->homunculus.exp = 0 ;
+ m_class = hom_class2mapid(hd->homunculus.class_);
+
+ if( hd->exp_next == 0 ||
+ ((m_class&HOM_REG) && hd->homunculus.level >= battle_config.hom_max_level) ||
+ ((m_class&HOM_S) && hd->homunculus.level >= battle_config.hom_S_max_level) ) {
+ hd->homunculus.exp = 0;
return 0;
}
diff --git a/src/map/homunculus.h b/src/map/homunculus.h
index 47f874588..cb209144a 100644
--- a/src/map/homunculus.h
+++ b/src/map/homunculus.h
@@ -47,6 +47,29 @@ struct homun_data {
char blockskill[MAX_SKILL]; // [orn]
};
+#define HOM_EVO 0x100 //256
+#define HOM_S 0x200 //512
+
+#define HOM_REG 0x1000 //4096
+
+enum {
+// Normal Homunculus
+ MAPID_LIF = HOM_REG|0x0,
+ MAPID_AMISTR,
+ MAPID_FILIR,
+ MAPID_VANILMIRTH,
+// Evolved Homunulus
+ MAPID_LIF_E = HOM_REG|HOM_EVO|0x0,
+ MAPID_AMISTR_E,
+ MAPID_FILIR_E,
+ MAPID_VANILMIRTH_E,
+// Homunculus S
+ MAPID_EIRA = HOM_S|0x0,
+ MAPID_BAYERI,
+ MAPID_SERA,
+ MAPID_DIETER,
+ MAPID_ELANOR,
+};
#define homdb_checkid(id) (id >= HM_CLASS_BASE && id <= HM_CLASS_MAX)
@@ -55,14 +78,16 @@ struct homun_data {
int do_init_merc(void);
int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag); //albator
struct view_data* merc_get_hom_viewdata(int class_);
+int hom_class2mapid(int hom_class);
void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp);
int merc_hom_dead(struct homun_data *hd, struct block_list *src);
void merc_hom_skillup(struct homun_data *hd,int skillnum);
-int merc_hom_calc_skilltree(struct homun_data *hd) ;
-int merc_hom_checkskill(struct homun_data *hd,int skill_id) ;
-int merc_hom_gainexp(struct homun_data *hd,int exp) ;
-int merc_hom_levelup(struct homun_data *hd) ;
-int merc_hom_evolution(struct homun_data *hd) ;
+int merc_hom_calc_skilltree(struct homun_data *hd);
+int merc_hom_checkskill(struct homun_data *hd,int skill_id);
+int merc_hom_gainexp(struct homun_data *hd,int exp);
+int merc_hom_levelup(struct homun_data *hd);
+int merc_hom_evolution(struct homun_data *hd);
+int hom_mutate(struct homun_data *hd,int homun_id);
void merc_hom_heal(struct homun_data *hd,int hp,int sp);
int merc_hom_vaporize(struct map_session_data *sd, int flag);
int merc_resurrect_homunculus(struct map_session_data *sd, unsigned char per, short x, short y);
diff --git a/src/map/script.c b/src/map/script.c
index a1bc94bc4..68baecc23 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -9551,6 +9551,36 @@ BUILDIN_FUNC(homunculus_evolution)
return 0;
}
+/*==========================================
+ * [Xantara]
+ *------------------------------------------*/
+BUILDIN_FUNC(homunculus_mutate)
+{
+ int homun_id, m_class, m_id;
+ int homun_array[5] = {6048,6049,6050,6051,6052};
+ TBL_PC *sd;
+
+ sd = script_rid2sd(st);
+ if( sd == NULL )
+ return 0;
+
+ if(script_hasdata(st,2))
+ homun_id = script_getnum(st,2);
+ else
+ homun_id = homun_array[rnd() % 5];
+
+ if(merc_is_hom_active(sd->hd)) {
+ m_class = hom_class2mapid(sd->hd->homunculus.class_);
+ m_id = hom_class2mapid(homun_id);
+
+ if ( m_class&HOM_EVO && m_id&HOM_S && sd->hd->homunculus.level >= 99 )
+ hom_mutate(sd->hd, homun_id);
+ else
+ clif_emotion(&sd->hd->bl, E_SWT);
+ }
+ return 0;
+}
+
// [Zephyrus]
BUILDIN_FUNC(homunculus_shuffle)
{
@@ -16676,6 +16706,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(getvariableofnpc,"rs"),
BUILDIN_DEF(warpportal,"iisii"),
BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn]
+ BUILDIN_DEF2(homunculus_mutate,"hommutate","?"),
BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus]
BUILDIN_DEF(eaclass,"?"), //[Skotlex]
BUILDIN_DEF(roclass,"i?"), //[Skotlex]