root/src/map/mercenary.c @ 5

Revision 1, 30.4 kB (checked in by jinshiro, 17 years ago)
Line 
1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include "../common/cbasetypes.h"
5#include "../common/malloc.h"
6#include "../common/socket.h"
7#include "../common/timer.h"
8#include "../common/nullpo.h"
9#include "../common/mmo.h"
10#include "../common/showmsg.h"
11#include "../common/utils.h"
12
13#include "log.h"
14#include "clif.h"
15#include "chrif.h"
16#include "intif.h"
17#include "itemdb.h"
18#include "map.h"
19#include "pc.h"
20#include "status.h"
21#include "skill.h"
22#include "mob.h"
23#include "pet.h"
24#include "battle.h"
25#include "party.h"
26#include "guild.h"
27#include "atcommand.h"
28#include "script.h"
29#include "npc.h"
30#include "trade.h"
31#include "unit.h"
32
33#include "mercenary.h"
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <math.h>
39
40
41//Better equiprobability than rand()% [orn]
42#define rand(a, b) (a+(int) ((float)(b-a+1)*rand()/(RAND_MAX+1.0)))
43
44struct s_homunculus_db homunculus_db[MAX_HOMUNCULUS_CLASS];     //[orn]
45struct skill_tree_entry hskill_tree[MAX_HOMUNCULUS_CLASS][MAX_SKILL_TREE];
46
47static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr data);
48
49static unsigned int hexptbl[MAX_LEVEL];
50
51//For holding the view data of npc classes. [Skotlex]
52static struct view_data hom_viewdb[MAX_HOMUNCULUS_CLASS];
53
54struct view_data* merc_get_hom_viewdata(int class_)
55{       //Returns the viewdata for homunculus
56        if (homdb_checkid(class_))
57                return &hom_viewdb[class_-HM_CLASS_BASE];
58        return NULL;
59}
60
61void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp)
62{
63        clif_hominfo(hd->master,hd,0);
64}
65
66int merc_hom_dead(struct homun_data *hd, struct block_list *src)
67{
68        //There's no intimacy penalties on death (from Tharis)
69        struct map_session_data *sd = hd->master;
70
71        clif_emotion(&hd->bl, 16) ;     //wah
72
73        //Delete timers when dead.
74        merc_hom_hungry_timer_delete(hd);
75        hd->homunculus.hp = 0;
76
77        if (!sd) //unit remove map will invoke unit free
78                return 3;
79
80        clif_emotion(&sd->bl, 28) ; //sob
81        //Remove from map (if it has no intimacy, it is auto-removed from memory)
82        return 3;
83}
84
85//Vaporize a character's homun. If flag, HP needs to be 80% or above.
86int merc_hom_vaporize(struct map_session_data *sd, int flag)
87{
88        struct homun_data *hd;
89
90        nullpo_retr(0, sd);
91
92        hd = sd->hd;
93        if (!hd || hd->homunculus.vaporize)
94                return 0;
95       
96        if (status_isdead(&hd->bl))
97                return 0; //Can't vaporize a dead homun.
98
99        if (flag && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80)
100                return 0;
101
102        hd->regen.state.block = 3; //Block regen while vaporized.
103        //Delete timers when vaporized.
104        merc_hom_hungry_timer_delete(hd);
105        hd->homunculus.vaporize = 1;
106        if(battle_config.hom_setting&0x40)
107                memset(hd->blockskill, 0, sizeof(hd->blockskill));
108        clif_hominfo(sd, sd->hd, 0);
109        merc_save(hd);
110        return unit_remove_map(&hd->bl, 0);
111}
112
113//delete a homunculus, completely "killing it".
114//Emote is the emotion the master should use, send negative to disable.
115int merc_hom_delete(struct homun_data *hd, int emote)
116{
117        struct map_session_data *sd;
118        nullpo_retr(0, hd);
119        sd = hd->master;
120
121        if (!sd)
122                return unit_free(&hd->bl,1);
123
124        if (emote >= 0)
125                clif_emotion(&sd->bl, emote);
126
127        //This makes it be deleted right away.
128        hd->homunculus.intimacy = 0;
129        // Send homunculus_dead to client
130        hd->homunculus.hp = 0;
131        clif_hominfo(sd, hd, 0);
132        return unit_remove_map(&hd->bl,0);
133}
134
135int merc_hom_calc_skilltree(struct homun_data *hd)
136{
137        int i,id=0 ;
138        int j,f=1;
139        int c=0;
140
141        nullpo_retr(0, hd);
142        c = hd->homunculus.class_ - HM_CLASS_BASE;
143       
144        for(i=0;i < MAX_SKILL_TREE && (id = hskill_tree[c][i].id) > 0;i++)
145        {
146                if(hd->homunculus.hskill[id-HM_SKILLBASE].id)
147                        continue; //Skill already known.
148                if(!battle_config.skillfree)
149                {
150                        for(j=0;j<5;j++)
151                        {
152                                if( hskill_tree[c][i].need[j].id &&
153                                        merc_hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) 
154                                {
155                                        f=0;
156                                        break;
157                                }
158                        }
159                }
160                if (f)
161                        hd->homunculus.hskill[id-HM_SKILLBASE].id = id ;
162        }
163        return 0;
164}
165
166int merc_hom_checkskill(struct homun_data *hd,int skill_id)
167{
168        int i = skill_id - HM_SKILLBASE;
169        if(!hd)
170                return 0;
171
172        if(hd->homunculus.hskill[i].id == skill_id)
173                return (hd->homunculus.hskill[i].lv);
174
175        return 0;
176}
177
178int merc_skill_tree_get_max(int id, int b_class){
179        int i, skillid;
180        b_class -= HM_CLASS_BASE;
181        for(i=0;(skillid=hskill_tree[b_class][i].id)>0;i++)
182                if (id == skillid)
183                        return hskill_tree[b_class][i].max;
184        return skill_get_max(id);
185}
186
187void merc_hom_skillup(struct homun_data *hd,int skillnum)
188{
189        int i = 0 ;
190        nullpo_retv(hd);
191
192        if(hd->homunculus.vaporize)
193                return;
194       
195        i = skillnum - HM_SKILLBASE;
196        if(hd->homunculus.skillpts > 0 &&
197                hd->homunculus.hskill[i].id &&
198                hd->homunculus.hskill[i].flag == 0 && //Don't allow raising while you have granted skills. [Skotlex]
199                hd->homunculus.hskill[i].lv < merc_skill_tree_get_max(skillnum, hd->homunculus.class_)
200                )
201        {
202                hd->homunculus.hskill[i].lv++;
203                hd->homunculus.skillpts-- ;
204                status_calc_homunculus(hd,0);
205                if (hd->master) {
206                        clif_homskillup(hd->master, skillnum);
207                        clif_hominfo(hd->master,hd,0);
208                        clif_homskillinfoblock(hd->master);
209                }
210        }
211}
212
213int merc_hom_levelup(struct homun_data *hd)
214{
215        struct s_homunculus *hom;
216        struct h_stats *min, *max;
217        int growth_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ;
218        int growth_max_hp, growth_max_sp ;
219        char output[256] ;
220
221        if (hd->homunculus.level == MAX_LEVEL || !hd->exp_next || hd->homunculus.exp < hd->exp_next)
222                return 0 ;
223       
224        hom = &hd->homunculus;
225        hom->level++ ;
226        if (!(hom->level % 3)) 
227                hom->skillpts++ ;       //1 skillpoint each 3 base level
228
229        hom->exp -= hd->exp_next ;
230        hd->exp_next = hexptbl[hom->level - 1] ;
231       
232        max  = &hd->homunculusDB->gmax;
233        min  = &hd->homunculusDB->gmin;
234
235        growth_max_hp = rand(min->HP, max->HP);
236        growth_max_sp = rand(min->SP, max->SP);
237        growth_str = rand(min->str, max->str);
238        growth_agi = rand(min->agi, max->agi);
239        growth_vit = rand(min->vit, max->vit);
240        growth_dex = rand(min->dex, max->dex);
241        growth_int = rand(min->int_,max->int_);
242        growth_luk = rand(min->luk, max->luk);
243
244        //Aegis discards the decimals in the stat growth values!
245        growth_str-=growth_str%10;
246        growth_agi-=growth_agi%10;
247        growth_vit-=growth_vit%10;
248        growth_dex-=growth_dex%10;
249        growth_int-=growth_int%10;
250        growth_luk-=growth_luk%10;
251
252        hom->max_hp += growth_max_hp;
253        hom->max_sp += growth_max_sp;
254        hom->str += growth_str;
255        hom->agi += growth_agi;
256        hom->vit += growth_vit;
257        hom->dex += growth_dex;
258        hom->int_+= growth_int;
259        hom->luk += growth_luk;
260       
261        if ( battle_config.homunculus_show_growth ) {
262                sprintf(output,
263                        "Growth: hp:%d sp:%d str(%.2f) agi(%.2f) vit(%.2f) int(%.2f) dex(%.2f) luk(%.2f) ",
264                        growth_max_hp, growth_max_sp,
265                        growth_str/10.0, growth_agi/10.0, growth_vit/10.0,
266                        growth_int/10.0, growth_dex/10.0, growth_luk/10.0);
267                clif_disp_onlyself(hd->master,output,strlen(output));
268        }
269        return 1 ;
270}
271
272int merc_hom_change_class(struct homun_data *hd, short class_)
273{
274        int i;
275        i = search_homunculusDB_index(class_,HOMUNCULUS_CLASS);
276        if(i < 0)
277                return 0;
278        hd->homunculusDB = &homunculus_db[i];
279        hd->homunculus.class_ = class_;
280        status_set_viewdata(&hd->bl, class_);
281        merc_hom_calc_skilltree(hd);
282        return 1;
283}
284
285int merc_hom_evolution(struct homun_data *hd)
286{
287        struct s_homunculus *hom;
288        struct h_stats *max, *min;
289        struct map_session_data *sd;
290        nullpo_retr(0, hd);
291
292        if(!hd->homunculusDB->evo_class || hd->homunculus.class_ == hd->homunculusDB->evo_class)
293        {
294                clif_emotion(&hd->bl, 4) ;      //swt
295                return 0 ;
296        }
297        sd = hd->master;
298        if (!sd)
299                return 0;
300       
301        if (!merc_hom_change_class(hd, hd->homunculusDB->evo_class)) {
302                ShowError("merc_hom_evolution: Can't evolve homunc from %d to %d", hd->homunculus.class_, hd->homunculusDB->evo_class);
303                return 0;
304        }
305
306        //Apply evolution bonuses
307        hom = &hd->homunculus;
308        max = &hd->homunculusDB->emax;
309        min = &hd->homunculusDB->emin;
310        hom->max_hp += rand(min->HP, max->HP);
311        hom->max_sp += rand(min->SP, max->SP);
312        hom->str += 10*rand(min->str, max->str);
313        hom->agi += 10*rand(min->agi, max->agi);
314        hom->vit += 10*rand(min->vit, max->vit);
315        hom->int_+= 10*rand(min->int_,max->int_);
316        hom->dex += 10*rand(min->dex, max->dex);
317        hom->luk += 10*rand(min->luk, max->luk);
318        hom->intimacy = 500;
319
320        unit_remove_map(&hd->bl, 0);
321        map_addblock(&hd->bl);
322
323        clif_spawn(&hd->bl);
324        clif_emotion(&sd->bl, 21);      //no1
325        clif_misceffect2(&hd->bl,568);
326
327        //status_Calc flag&1 will make current HP/SP be reloaded from hom structure
328        hom->hp = hd->battle_status.hp;
329        hom->sp = hd->battle_status.sp;
330        status_calc_homunculus(hd,1);
331
332        if (!(battle_config.hom_setting&0x2))
333                skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately
334                               
335        return 1 ;
336}
337
338int merc_hom_gainexp(struct homun_data *hd,int exp)
339{
340        if(hd->homunculus.vaporize)
341                return 1;
342
343        if( hd->exp_next == 0 ) {
344                hd->homunculus.exp = 0 ;
345                return 0;
346        }
347
348        hd->homunculus.exp += exp;
349
350        if(hd->homunculus.exp < hd->exp_next) {
351                clif_hominfo(hd->master,hd,0);
352                return 0;
353        }
354
355        //levelup
356        do
357        {
358                merc_hom_levelup(hd) ;
359        }
360        while(hd->homunculus.exp > hd->exp_next && hd->exp_next != 0 );
361               
362        if( hd->exp_next == 0 )
363                hd->homunculus.exp = 0 ;
364
365        clif_misceffect2(&hd->bl,568);
366        status_calc_homunculus(hd,0);
367        status_percent_heal(&hd->bl, 100, 100);
368        return 0;
369}
370
371// Return the new value
372int merc_hom_increase_intimacy(struct homun_data * hd, unsigned int value)
373{
374        if (battle_config.homunculus_friendly_rate != 100)
375                value = (value * battle_config.homunculus_friendly_rate) / 100;
376
377        if (hd->homunculus.intimacy + value <= 100000)
378                hd->homunculus.intimacy += value;
379        else
380                hd->homunculus.intimacy = 100000;
381        return hd->homunculus.intimacy;
382}
383
384// Return 0 if decrease fails or intimacy became 0 else the new value
385int merc_hom_decrease_intimacy(struct homun_data * hd, unsigned int value)
386{
387        if (hd->homunculus.intimacy >= value)
388                hd->homunculus.intimacy -= value;
389        else
390                hd->homunculus.intimacy = 0;
391
392        return hd->homunculus.intimacy;
393}
394
395void merc_hom_heal(struct homun_data *hd,int hp,int sp)
396{
397        clif_hominfo(hd->master,hd,0);
398}
399
400void merc_save(struct homun_data *hd)
401{
402        // copy data that must be saved in homunculus struct ( hp / sp )
403        TBL_PC * sd = hd->master;
404        //Do not check for max_hp/max_sp caps as current could be higher to max due
405        //to status changes/skills (they will be capped as needed upon stat
406        //calculation on login)
407        hd->homunculus.hp = hd->battle_status.hp;
408        hd->homunculus.sp = hd->battle_status.sp;
409        intif_homunculus_requestsave(sd->status.account_id, &hd->homunculus);
410}
411
412int merc_menu(struct map_session_data *sd,int menunum)
413{
414        nullpo_retr(0, sd);
415        if (sd->hd == NULL)
416                return 1;
417       
418        switch(menunum) {
419                case 0:
420                        break;
421                case 1:
422                        merc_hom_food(sd, sd->hd);
423                        break;
424                case 2:
425                        merc_hom_delete(sd->hd, -1);
426                        break;
427                default:
428                        ShowError("merc_menu : unknown menu choice : %d\n", menunum) ;
429                        break;
430        }
431        return 0;
432}
433
434int merc_hom_food(struct map_session_data *sd, struct homun_data *hd)
435{
436        int i, foodID, emotion;
437
438        if(hd->homunculus.vaporize)
439                return 1 ;
440
441        foodID = hd->homunculusDB->foodID;
442        i = pc_search_inventory(sd,foodID);
443        if(i < 0) {
444                clif_hom_food(sd,foodID,0);
445                return 1;
446        }
447        pc_delitem(sd,i,1,0);
448
449        if ( hd->homunculus.hunger >= 91 ) {
450                merc_hom_decrease_intimacy(hd, 50);
451                emotion = 16;
452        } else if ( hd->homunculus.hunger >= 76 ) {
453                merc_hom_decrease_intimacy(hd, 5);
454                emotion = 19;
455        } else if ( hd->homunculus.hunger >= 26 ) {
456                merc_hom_increase_intimacy(hd, 75);
457                emotion = 2;
458        } else if ( hd->homunculus.hunger >= 11 ) {
459                merc_hom_increase_intimacy(hd, 100);
460                emotion = 2;
461        } else {
462                merc_hom_increase_intimacy(hd, 50);
463                emotion = 2;
464        }
465
466        hd->homunculus.hunger += 10;    //dunno increase value for each food
467        if(hd->homunculus.hunger > 100)
468                hd->homunculus.hunger = 100;
469
470        clif_emotion(&hd->bl,emotion) ;
471        clif_send_homdata(sd,SP_HUNGRY,hd->homunculus.hunger);
472        clif_send_homdata(sd,SP_INTIMATE,hd->homunculus.intimacy / 100);
473        clif_hom_food(sd,foodID,1);
474       
475        // Too much food :/
476        if(hd->homunculus.intimacy == 0)
477                return merc_hom_delete(sd->hd, 23); //omg 
478
479        return 0;
480}
481
482static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr data)
483{
484        struct map_session_data *sd;
485        struct homun_data *hd;
486
487        sd=map_id2sd(id);
488        if(!sd)
489                return 1;
490
491        if(!sd->status.hom_id || !(hd=sd->hd))
492                return 1;
493
494        if(hd->hungry_timer != tid){
495                ShowError("merc_hom_hungry_timer %d != %d\n",hd->hungry_timer,tid);
496                return 0;
497        }
498
499        hd->hungry_timer = -1;
500       
501        hd->homunculus.hunger-- ;
502        if(hd->homunculus.hunger <= 10) {
503                clif_emotion(&hd->bl, 6) ;      //an
504        } else if(hd->homunculus.hunger == 25) {
505                clif_emotion(&hd->bl, 20) ;     //hmm
506        } else if(hd->homunculus.hunger == 75) {
507                clif_emotion(&hd->bl, 33) ;     //ok
508        } 
509       
510        if(hd->homunculus.hunger < 0) {
511                hd->homunculus.hunger = 0;
512                // Delete the homunculus if intimacy <= 100
513                if ( !merc_hom_decrease_intimacy(hd, 100) )
514                        return merc_hom_delete(hd, 23); //omg 
515                clif_send_homdata(sd,SP_INTIMATE,hd->homunculus.intimacy / 100);
516        }
517
518        clif_send_homdata(sd,SP_HUNGRY,hd->homunculus.hunger);
519        hd->hungry_timer = add_timer(tick+hd->homunculusDB->hungryDelay,merc_hom_hungry,sd->bl.id,0); //simple Fix albator
520        return 0;
521}
522
523int merc_hom_hungry_timer_delete(struct homun_data *hd)
524{
525        nullpo_retr(0, hd);
526        if(hd->hungry_timer != -1) {
527                delete_timer(hd->hungry_timer,merc_hom_hungry);
528                hd->hungry_timer = -1;
529        }
530        return 1;
531}
532
533int merc_hom_change_name(struct map_session_data *sd,char *name)
534{
535        int i;
536        struct homun_data *hd;
537        nullpo_retr(1, sd);
538
539        hd = sd->hd;
540        if (!merc_is_hom_active(hd))
541                return 1;
542        if(hd->homunculus.rename_flag && !battle_config.hom_rename)
543                return 1;
544
545        for(i=0;i<NAME_LENGTH && name[i];i++){
546                if( !(name[i]&0xe0) || name[i]==0x7f)
547                        return 1;
548        }
549
550        return intif_rename_hom(sd, name);
551}
552
553int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag)
554{
555        struct homun_data *hd = sd->hd;
556        if (!merc_is_hom_active(hd)) return 0;
557        if (!flag) {
558                clif_displaymessage(sd->fd, msg_txt(280)); // You cannot use this name
559                return 0;
560        }
561        strncpy(hd->homunculus.name,name,NAME_LENGTH);
562        clif_charnameack (0,&hd->bl);
563        hd->homunculus.rename_flag = 1;
564        clif_hominfo(sd,hd,0);
565        return 1;
566}
567
568int search_homunculusDB_index(int key,int type)
569{
570        int i;
571
572        for(i=0;i<MAX_HOMUNCULUS_CLASS;i++) {
573                if(homunculus_db[i].base_class <= 0)
574                        continue;
575                switch(type) {
576                        case HOMUNCULUS_CLASS:
577                                if(homunculus_db[i].base_class == key ||
578                                        homunculus_db[i].evo_class == key)
579                                        return i;
580                                break;
581                        case HOMUNCULUS_FOOD:
582                                if(homunculus_db[i].foodID == key)
583                                        return i;
584                                break;
585                        default:
586                                return -1;
587                }
588        }
589        return -1;
590}
591
592// Create homunc structure
593int merc_hom_alloc(struct map_session_data *sd, struct s_homunculus *hom)
594{
595        struct homun_data *hd;
596        int i = 0;
597        short x,y;
598
599        nullpo_retr(1, sd);
600
601        Assert((sd->status.hom_id == 0 || sd->hd == 0) || sd->hd->master == sd); 
602
603        i = search_homunculusDB_index(hom->class_,HOMUNCULUS_CLASS);
604        if(i < 0) {
605                ShowError("merc_hom_alloc: unknown class [%d] for homunculus '%s', requesting deletion.\n", hom->class_, hom->name);
606                sd->status.hom_id = 0;
607                intif_homunculus_requestdelete(hom->hom_id);
608                return 1;
609        }
610        sd->hd = hd = (struct homun_data*)aCalloc(1,sizeof(struct homun_data));
611        hd->bl.type = BL_HOM;
612        hd->bl.id = npc_get_new_npc_id();
613
614        hd->master = sd;
615        hd->homunculusDB = &homunculus_db[i];
616        memcpy(&hd->homunculus, hom, sizeof(struct s_homunculus));
617        hd->exp_next = hexptbl[hd->homunculus.level - 1];
618
619        status_set_viewdata(&hd->bl, hd->homunculus.class_);
620        status_change_init(&hd->bl);
621        unit_dataset(&hd->bl);
622        hd->ud.dir = sd->ud.dir;
623
624        // Find a random valid pos around the player
625        hd->bl.m = sd->bl.m;
626        hd->bl.x = sd->bl.x;
627        hd->bl.y = sd->bl.y;
628        x = sd->bl.x + 1;
629        y = sd->bl.y + 1;
630        map_random_dir(&hd->bl, &x, &y);
631        hd->bl.x = x;
632        hd->bl.y = y;
633       
634        map_addiddb(&hd->bl);
635        status_calc_homunculus(hd,1);
636
637        hd->hungry_timer = -1;
638        return 0;
639}
640
641void merc_hom_init_timers(struct homun_data * hd)
642{
643        if (hd->hungry_timer == -1)
644                hd->hungry_timer = add_timer(gettick()+hd->homunculusDB->hungryDelay,merc_hom_hungry,hd->master->bl.id,0);
645        hd->regen.state.block = 0; //Restore HP/SP block.
646}
647
648int merc_call_homunculus(struct map_session_data *sd)
649{
650        struct homun_data *hd;
651
652        if (!sd->status.hom_id) //Create a new homun.
653                return merc_create_homunculus_request(sd, HM_CLASS_BASE + rand(0, 7)) ;
654
655        // If homunc not yet loaded, load it
656        if (!sd->hd)
657                return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id);
658
659        hd = sd->hd;
660
661        if (!hd->homunculus.vaporize)
662                return 0; //Can't use this if homun wasn't vaporized.
663
664        merc_hom_init_timers(hd);
665        hd->homunculus.vaporize = 0;
666        if (hd->bl.prev == NULL)
667        {       //Spawn him
668                hd->bl.x = sd->bl.x;
669                hd->bl.y = sd->bl.y;
670                hd->bl.m = sd->bl.m;
671                map_addblock(&hd->bl);
672                clif_spawn(&hd->bl);
673                clif_send_homdata(sd,SP_ACK,0);
674                clif_hominfo(sd,hd,1);
675                clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89]
676                clif_homskillinfoblock(sd);
677                if (battle_config.slaves_inherit_speed&1)
678                        status_calc_bl(&hd->bl, SCB_SPEED);
679                merc_save(hd); 
680        } else
681                //Warp him to master.
682                unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,0);
683        return 1;
684}
685
686// Recv homunculus data from char server
687int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag)
688{
689        struct map_session_data *sd;
690        struct homun_data *hd;
691
692        sd = map_id2sd(account_id);
693        if(!sd)
694                return 0;
695        if (sd->status.char_id != sh->char_id)
696        {
697                if (sd->status.hom_id == sh->hom_id)
698                        sh->char_id = sd->status.char_id; //Correct char id.
699                else
700                        return 0;
701        }
702        if(!flag) { // Failed to load
703                sd->status.hom_id = 0;
704                return 0;
705        }
706
707        if (!sd->status.hom_id) //Hom just created.
708                sd->status.hom_id = sh->hom_id;
709        if (sd->hd) //uh? Overwrite the data.
710                memcpy(&sd->hd->homunculus, sh, sizeof(struct s_homunculus));
711        else
712                merc_hom_alloc(sd, sh);
713       
714        hd = sd->hd;
715        if(hd && hd->homunculus.hp && !hd->homunculus.vaporize && hd->bl.prev == NULL && sd->bl.prev != NULL)
716        {
717                map_addblock(&hd->bl);
718                clif_spawn(&hd->bl);
719                clif_send_homdata(sd,SP_ACK,0);
720                clif_hominfo(sd,hd,1);
721                clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89]
722                clif_homskillinfoblock(sd);
723                merc_hom_init_timers(hd);
724        }
725        return 1;
726}
727
728// Ask homunculus creation to char server
729int merc_create_homunculus_request(struct map_session_data *sd, int class_)
730{
731        struct s_homunculus homun;
732        struct h_stats *base;
733        int i;
734
735        nullpo_retr(1, sd);
736
737        i = search_homunculusDB_index(class_,HOMUNCULUS_CLASS);
738        if(i < 0) return 0;
739       
740        memset(&homun, 0, sizeof(struct s_homunculus));
741        //Initial data
742        strncpy(homun.name, homunculus_db[i].name, NAME_LENGTH-1);
743        homun.class_ = class_;
744        homun.level = 1;
745        homun.hunger = 32; //32%
746        homun.intimacy = 2100; //21/1000
747        homun.char_id = sd->status.char_id;
748       
749        homun.hp = 10 ;
750        base = &homunculus_db[i].base;
751        homun.max_hp = base->HP;
752        homun.max_sp = base->SP;
753        homun.str = base->str *10;
754        homun.agi = base->agi *10;
755        homun.vit = base->vit *10;
756        homun.int_= base->int_*10;
757        homun.dex = base->dex *10;
758        homun.luk = base->luk *10;
759
760        // Request homunculus creation
761        intif_homunculus_create(sd->status.account_id, &homun); 
762        return 1;
763}
764
765int merc_resurrect_homunculus(struct map_session_data* sd, unsigned char per, short x, short y)
766{
767        struct homun_data* hd;
768        nullpo_retr(0, sd);
769
770        if (!sd->status.hom_id)
771                return 0; // no homunculus
772
773        if (!sd->hd) //Load homun data;
774                return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id);
775       
776        hd = sd->hd;
777
778        if (hd->homunculus.vaporize)
779                return 0; // vaporized homunculi need to be 'called'
780
781        if (!status_isdead(&hd->bl))
782                return 0; // already alive
783
784        merc_hom_init_timers(hd);
785
786        if (!hd->bl.prev)
787        {       //Add it back to the map.
788                hd->bl.m = sd->bl.m;
789                hd->bl.x = x;
790                hd->bl.y = y;
791                map_addblock(&hd->bl);
792                clif_spawn(&hd->bl);
793        }
794        status_revive(&hd->bl, per, 0);
795        return 1;
796}
797
798void merc_hom_revive(struct homun_data *hd, unsigned int hp, unsigned int sp)
799{
800        struct map_session_data *sd = hd->master;
801        hd->homunculus.hp = hd->battle_status.hp;
802        if (!sd)
803                return;
804        clif_send_homdata(sd,SP_ACK,0);
805        clif_hominfo(sd,hd,1);
806        clif_hominfo(sd,hd,0);
807        clif_homskillinfoblock(sd);
808}
809
810void merc_reset_stats(struct homun_data *hd)
811{       //Resets a homunc stats back to zero (but doesn't touches hunger or intimacy)
812        struct s_homunculus_db *db;
813        struct s_homunculus *hom;
814        struct h_stats *base;
815        hom = &hd->homunculus;
816        db = hd->homunculusDB;
817        base = &db->base;
818        hom->level = 1;
819        hom->hp = 10;
820        hom->max_hp = base->HP;
821        hom->max_sp = base->SP;
822        hom->str = base->str *10;
823        hom->agi = base->agi *10;
824        hom->vit = base->vit *10;
825        hom->int_= base->int_*10;
826        hom->dex = base->dex *10;
827        hom->luk = base->luk *10;
828        hom->exp = 0;
829        hd->exp_next = hexptbl[0];
830        memset(&hd->homunculus.hskill, 0, sizeof hd->homunculus.hskill);
831        hd->homunculus.skillpts = 0;
832}
833
834int merc_hom_shuffle(struct homun_data *hd)
835{
836        struct map_session_data *sd;
837        int lv, i, skillpts;
838        unsigned int exp;
839        struct skill b_skill[MAX_HOMUNSKILL];
840
841        if (!merc_is_hom_active(hd))
842                return 0;
843
844        sd = hd->master;
845        lv = hd->homunculus.level;
846        exp = hd->homunculus.exp;
847        memcpy(&b_skill, &hd->homunculus.hskill, sizeof(b_skill));
848        skillpts = hd->homunculus.skillpts;
849        //Reset values to level 1.
850        merc_reset_stats(hd);
851        //Level it back up
852        for (i = 1; i < lv && hd->exp_next; i++){
853                hd->homunculus.exp += hd->exp_next;
854                merc_hom_levelup(hd);
855        }
856
857        if(hd->homunculus.class_ == hd->homunculusDB->evo_class) {
858                //Evolved bonuses
859                struct s_homunculus *hom = &hd->homunculus;
860                struct h_stats *max = &hd->homunculusDB->emax, *min = &hd->homunculusDB->emin;
861                hom->max_hp += rand(min->HP, max->HP);
862                hom->max_sp += rand(min->SP, max->SP);
863                hom->str += 10*rand(min->str, max->str);
864                hom->agi += 10*rand(min->agi, max->agi);
865                hom->vit += 10*rand(min->vit, max->vit);
866                hom->int_+= 10*rand(min->int_,max->int_);
867                hom->dex += 10*rand(min->dex, max->dex);
868                hom->luk += 10*rand(min->luk, max->luk);
869        }
870
871        hd->homunculus.exp = exp;
872        memcpy(&hd->homunculus.hskill, &b_skill, sizeof(b_skill));
873        hd->homunculus.skillpts = skillpts;
874        clif_homskillinfoblock(sd);
875        status_calc_homunculus(hd,0);
876        status_percent_heal(&hd->bl, 100, 100);
877        clif_misceffect2(&hd->bl,568);
878
879        return 1;
880}
881
882int read_homunculusdb(void)
883{
884        FILE *fp;
885        char line[1024], *p;
886        int i, k, classid; 
887        int j = 0;
888        const char *filename[]={"homunculus_db.txt","homunculus_db2.txt"};
889        char *str[50];
890        struct s_homunculus_db *db;
891
892        memset(homunculus_db,0,sizeof(homunculus_db));
893        for(i = 0; i<2; i++)
894        {
895                sprintf(line, "%s/%s", db_path, filename[i]);
896                fp = fopen(line,"r");
897                if(!fp){
898                        if(i != 0)
899                                continue;
900                        ShowError("read_homunculusdb : can't read %s\n", line);
901                        return -1;
902                }
903
904                while(fgets(line, sizeof(line), fp) && j < MAX_HOMUNCULUS_CLASS)
905                {
906                        if(line[0] == '/' && line[1] == '/')
907                                continue;
908
909                        k = 0;
910                        p = strtok (line,",");
911                        while (p != NULL && k < 50)
912                        {
913                                str[k++] = p;
914                                p = strtok (NULL, ",");
915                        }
916                        if (k < 50 )
917                        {
918                                ShowError("read_homunculusdb : Incorrect number of columns at %s, homunculus %d. Read %d columns, 50 are needed.\n", filename[i], j+1, k);
919                                continue;
920                        }
921                       
922                        //Base Class,Evo Class
923                        classid = atoi(str[0]);
924                        if (classid < HM_CLASS_BASE || classid > HM_CLASS_MAX)
925                        {
926                                ShowError("read_homunculusdb : Invalid class %d (%s)\n", classid, filename[i]);
927                                continue;
928                        }
929                        db = &homunculus_db[j];
930                        db->base_class = classid;
931                        classid = atoi(str[1]);
932                        if (classid < HM_CLASS_BASE || classid > HM_CLASS_MAX)
933                        {
934                                db->base_class = 0;
935                                ShowError("read_homunculusdb : Invalid class %d (%s)\n", classid, filename[i]);
936                                continue;
937                        }
938                        db->evo_class = classid;
939                        //Name, Food, Hungry Delay, Base Size, Evo Size, Race, Element, ASPD
940                        strncpy(db->name,str[2],NAME_LENGTH-1);
941                        db->foodID = atoi(str[3]);
942                        db->hungryDelay = atoi(str[4]);
943                        db->base_size = atoi(str[5]);
944                        db->evo_size = atoi(str[6]);
945                        db->race = atoi(str[7]);
946                        db->element = atoi(str[8]);
947                        db->baseASPD = atoi(str[9]);
948                        //base HP, SP, str, agi, vit, int, dex, luk
949                        db->base.HP = atoi(str[10]);
950                        db->base.SP = atoi(str[11]);
951                        db->base.str = atoi(str[12]);
952                        db->base.agi = atoi(str[13]);
953                        db->base.vit = atoi(str[14]);
954                        db->base.int_= atoi(str[15]);
955                        db->base.dex = atoi(str[16]);
956                        db->base.luk = atoi(str[17]);
957                        //Growth Min/Max HP, SP, str, agi, vit, int, dex, luk
958                        db->gmin.HP = atoi(str[18]);
959                        db->gmax.HP = atoi(str[19]);
960                        db->gmin.SP = atoi(str[20]);
961                        db->gmax.SP = atoi(str[21]);
962                        db->gmin.str = atoi(str[22]);
963                        db->gmax.str = atoi(str[23]);
964                        db->gmin.agi = atoi(str[24]);
965                        db->gmax.agi = atoi(str[25]);
966                        db->gmin.vit = atoi(str[26]);
967                        db->gmax.vit = atoi(str[27]);
968                        db->gmin.int_= atoi(str[28]);
969                        db->gmax.int_= atoi(str[29]);
970                        db->gmin.dex = atoi(str[30]);
971                        db->gmax.dex = atoi(str[31]);
972                        db->gmin.luk = atoi(str[32]);
973                        db->gmax.luk = atoi(str[33]);
974                        //Evolution Min/Max HP, SP, str, agi, vit, int, dex, luk
975                        db->emin.HP = atoi(str[34]);
976                        db->emax.HP = atoi(str[35]);
977                        db->emin.SP = atoi(str[36]);
978                        db->emax.SP = atoi(str[37]);
979                        db->emin.str = atoi(str[38]);
980                        db->emax.str = atoi(str[39]);
981                        db->emin.agi = atoi(str[40]);
982                        db->emax.agi = atoi(str[41]);
983                        db->emin.vit = atoi(str[42]);
984                        db->emax.vit = atoi(str[43]);
985                        db->emin.int_= atoi(str[44]);
986                        db->emax.int_= atoi(str[45]);
987                        db->emin.dex = atoi(str[46]);
988                        db->emax.dex = atoi(str[47]);
989                        db->emin.luk = atoi(str[48]);
990                        db->emax.luk = atoi(str[49]);
991
992                        //Check that the min/max values really are below the other one.
993                        if(db->gmin.HP > db->gmax.HP)
994                                db->gmin.HP = db->gmax.HP;
995                        if(db->gmin.SP > db->gmax.SP)
996                                db->gmin.SP = db->gmax.SP;
997                        if(db->gmin.str > db->gmax.str)
998                                db->gmin.str = db->gmax.str;
999                        if(db->gmin.agi > db->gmax.agi)
1000                                db->gmin.agi = db->gmax.agi;
1001                        if(db->gmin.vit > db->gmax.vit)
1002                                db->gmin.vit = db->gmax.vit;
1003                        if(db->gmin.int_> db->gmax.int_)
1004                                db->gmin.int_= db->gmax.int_;
1005                        if(db->gmin.dex > db->gmax.dex)
1006                                db->gmin.dex = db->gmax.dex;
1007                        if(db->gmin.luk > db->gmax.luk)
1008                                db->gmin.luk = db->gmax.luk;
1009
1010                        if(db->emin.HP > db->emax.HP)
1011                                db->emin.HP = db->emax.HP;
1012                        if(db->emin.SP > db->emax.SP)
1013                                db->emin.SP = db->emax.SP;
1014                        if(db->emin.str > db->emax.str)
1015                                db->emin.str = db->emax.str;
1016                        if(db->emin.agi > db->emax.agi)
1017                                db->emin.agi = db->emax.agi;
1018                        if(db->emin.vit > db->emax.vit)
1019                                db->emin.vit = db->emax.vit;
1020                        if(db->emin.int_> db->emax.int_)
1021                                db->emin.int_= db->emax.int_;
1022                        if(db->emin.dex > db->emax.dex)
1023                                db->emin.dex = db->emax.dex;
1024                        if(db->emin.luk > db->emax.luk)
1025                                db->emin.luk = db->emax.luk;
1026
1027                        j++;
1028                }
1029                if (j > MAX_HOMUNCULUS_CLASS)
1030                        ShowWarning("read_homunculusdb: Reached max number of homunculus [%d]. Remaining homunculus were not read.\n ", MAX_HOMUNCULUS_CLASS);
1031                fclose(fp);
1032                ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' homunculus in '"CL_WHITE"db/%s"CL_RESET"'.\n",j,filename[i]);
1033        }
1034        return 0;
1035}
1036
1037int read_homunculus_skilldb(void)
1038{
1039        FILE *fp;
1040        char line[1024], *p;
1041        int k, classid; 
1042        int j = 0;
1043        char *split[15];
1044
1045        memset(hskill_tree,0,sizeof(hskill_tree));
1046        sprintf(line, "%s/homun_skill_tree.txt", db_path);
1047        fp=fopen(line,"r");
1048        if(fp==NULL){
1049                ShowError("can't read %s\n", line);
1050                return 1;
1051        }
1052
1053        while(fgets(line, sizeof(line), fp))
1054        {
1055                int minJobLevelPresent = 0;
1056
1057                if(line[0]=='/' && line[1]=='/')
1058                        continue;
1059
1060                k = 0;
1061                p = strtok(line,",");
1062                while (p != NULL && k < 15)
1063                {
1064                        split[k++] = p;
1065                        p = strtok(NULL, ",");
1066                }
1067
1068                if(k < 13)
1069                        continue;
1070
1071                if (k == 14)
1072                        minJobLevelPresent = 1; // MinJobLvl has been added
1073
1074                // check for bounds [celest]
1075                classid = atoi(split[0]) - HM_CLASS_BASE;
1076                if ( classid >= MAX_HOMUNCULUS_CLASS )
1077                        continue;
1078
1079                k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
1080                // Search an empty line or a line with the same skill_id (stored in j)
1081                for(j = 0; j < MAX_SKILL_TREE && hskill_tree[classid][j].id && hskill_tree[classid][j].id != k; j++);
1082
1083                if (j == MAX_SKILL_TREE)
1084                {
1085                        ShowWarning("Unable to load skill %d into homunculus %d's tree. Maximum number of skills per class has been reached.\n", k, classid);
1086                        continue;
1087                }
1088
1089                hskill_tree[classid][j].id=k;
1090                hskill_tree[classid][j].max=atoi(split[2]);
1091                if (minJobLevelPresent)
1092                        hskill_tree[classid][j].joblv=atoi(split[3]);
1093
1094                for(k=0;k<5;k++){
1095                        hskill_tree[classid][j].need[k].id=atoi(split[3+k*2+minJobLevelPresent]);
1096                        hskill_tree[classid][j].need[k].lv=atoi(split[3+k*2+minJobLevelPresent+1]);
1097                }
1098        }
1099
1100        fclose(fp);
1101        ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","homun_skill_tree.txt");
1102        return 0;
1103}
1104
1105void read_homunculus_expdb(void)
1106{
1107        FILE *fp;
1108        char line[1024];
1109        int i, j=0;
1110        char *filename[]={"exp_homun.txt","exp_homun2.txt"};
1111
1112        memset(hexptbl,0,sizeof(hexptbl));
1113        for(i=0; i<2; i++){
1114                sprintf(line, "%s/%s", db_path, filename[i]);
1115                fp=fopen(line,"r");
1116                if(fp == NULL){
1117                        if(i != 0)
1118                                continue;
1119                        ShowError("can't read %s\n",line);
1120                        return;
1121                }
1122                while(fgets(line, sizeof(line), fp) && j < MAX_LEVEL)
1123                {
1124                        if(line[0] == '/' && line[1] == '/')
1125                                continue;
1126
1127                        hexptbl[j] = strtoul(line, NULL, 10);
1128                        if (!hexptbl[j++])
1129                                break;
1130                }
1131                if (hexptbl[MAX_LEVEL - 1]) // Last permitted level have to be 0!
1132                {
1133                        ShowWarning("read_hexptbl: Reached max level in exp_homun [%d]. Remaining lines were not read.\n ", MAX_LEVEL);
1134                        hexptbl[MAX_LEVEL - 1] = 0;
1135                }
1136                fclose(fp);
1137                ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' levels in '"CL_WHITE"%s"CL_RESET"'.\n", j, filename[i]);
1138        }
1139}
1140
1141void merc_reload(void)
1142{
1143        read_homunculusdb();
1144        read_homunculus_expdb();
1145}
1146
1147void merc_skill_reload(void)
1148{
1149        read_homunculus_skilldb();
1150}
1151
1152int do_init_merc(void)
1153{
1154        int class_;
1155        read_homunculusdb();
1156        read_homunculus_expdb();
1157        read_homunculus_skilldb();
1158        // Add homunc timer function to timer func list [Toms]
1159        add_timer_func_list(merc_hom_hungry, "merc_hom_hungry");
1160
1161        //Stock view data for homuncs
1162        memset(&hom_viewdb, 0, sizeof(hom_viewdb));
1163        for (class_ = 0; class_ < ARRAYLENGTH(hom_viewdb); class_++) 
1164                hom_viewdb[class_].class_ = HM_CLASS_BASE+class_;
1165        return 0;
1166}
1167
1168int do_final_merc(void);
Note: See TracBrowser for help on using the browser.