#include #include #include #include #include #include #include #include #include #include "engine1.h" #include "globals.h" #include "specproc.h" #include #define MOB_ZNAKY "FLBLCH" #define MOB_START 1 #define MOB_DIST 24 #define MBS_WALK 0 #define MBS_ATTACK 1 #define MBS_HIT 2 #define MBA_ATTACK 3 //potvora utoci #define MBA_SPELL 1 //potvora caruje #define MBA_FLEE 2 //potvora utika #define MBA_NONE 0 #define PK_QUERY 0 //dotaz zda je v mrtvole predmet #define PK_PICK 1 //prvni predmet v mrtvole #define mob_walk_sound(p) if (p->locx!=p->headx || p->locy!=p->heady) mob_sound_event(p,MBS_WALK) TMOB mobs[MAX_MOBS]; char *mob_map; char hex_chars[]="0123456789ABCDEF"; int mob_dostal=0; int mob_dostal_pocet; char folow_mode=0; char folow_mob; char show_mob_info = 0; char mob_go_x[]={128,255,128,0}; char mob_go_y[]={0,128,255,128}; char mob_batt_x[]={128,128+MOB_DIST,128,128-MOB_DIST}; char mob_batt_y[]={128-MOB_DIST,128,128+MOB_DIST,128}; short konv_x[]={1,1,-1,-1}; short konv_y[]={-1,1,1,-1}; char going[]={0,0,1,0,1,1}; static word *mob_paths[MAX_MOBS]; static word *mob_path_ptr[MAX_MOBS]; static int monster_block = 0; void *sound_template=NULL; short att_sect; char battle=0; char neco_v_pohybu=1; char nohassle=0; typedef struct tmobsavedata { short anim_counter; //citac animaci char anim_phase; //cinnost kterou mob dela char dir; }TMOBSAVEDATA; static TMOBSAVEDATA **mobsavedata=0; static void register_mob_path(int mob,word *path) //registruje cestu pro potvoru { mob_paths[mob]=path; mob_path_ptr[mob]=path; } static void free_path(int mob) //vymaze cestu potvore { free(mob_paths[mob]); mob_paths[mob]=NULL; mob_path_ptr[mob]=NULL; } void send_mob_to(int m,word *path) { if (mob_paths[m]!=NULL) { free_path(m); } register_mob_path(m,path); mobs[m].stay_strategy |= MOB_WALK; } void smeruj_moba(TMOB *m,int smer) { int val=128+MOB_DIST*smer; switch (m->dir) { case 0:m->headx=val;break; case 1:m->heady=val;break; case 2:m->headx=-val;break; case 3:m->heady=-val;break; } } void save_enemy_paths(TMPFILE_WR *f) { short i; int s; word *w; for(i=0;imsg == E_KOUZLO_KOLO) { { if (insleep) return; if (counter++==10) { TMOB *m; int32_t vl; static int last; counter=0; while (lasthome_pos].flags & MC_PLAYER || mob_map[m->home_pos]) return; m->vlajky|=MOB_LIVE; m->vlajky&=~MOB_IN_BATTLE; m->lives=m->vlastnosti[VLS_MAXHIT]; m->sector=m->home_pos; m->locx=m->headx=m->locy=m->heady=128; memset(m->inv,0,sizeof(m->inv)); play_sample_at_sector(H_SND_TELEPOUT,viewsector,m->home_pos,0,0); add_spectxtr(m->home_pos,H_TELEP_PCX,14,1,0); refresh_mob_map(); SEND_LOG("(RELOAD) Mob reloaded: '%s' at sector %d",m->name,m->home_pos); free_path(m-mobs); } } } } void init_mobs() { memset(mobs,0,sizeof(mobs)); mob_map=getmem(mapsize); memset(mob_map,0,mapsize); memset(mob_paths,0,sizeof(mob_paths)); memset(mob_path_ptr,0,sizeof(mob_path_ptr)); send_message(E_DONE,E_KOUZLO_KOLO,mob_reload); send_message(E_ADD,E_KOUZLO_KOLO,mob_reload); } static void register_mob_graphics(int num,char *name_part,const char *anims,const char *seq) { char fulname[14]; char znaky[]=MOB_ZNAKY; int i,j,a; strcpy(fulname,name_part); strcat(fulname,"??.PCX"); a=num; for(i=0;i<6;i++) { for(j=0;j<16;j++) { if (anims[i]) { fulname[6]=znaky[i]; if (j<=anims[i]) { fulname[7]=*seq++; def_handle(a,fulname,pcx_8bit_nopal,SR_ENEMIES); } a++; } else { fulname[6]=znaky[0]; if (j<=anims[0]) { fulname[7]=*seq++; def_handle(a,fulname,pcx_8bit_nopal,SR_ENEMIES); } a++; } if (*seq=='\r') { char buff[256]; closemode(); sprintf(buff,"Soubor sekvence %s obsahuje chybne udaje nebo je sekvence je moc kratka\n", fulname); display_error(buff); exit(0); } } seq=strchr(seq,'\n')+1; } } static void register_mob_sounds(int hlptr,word *sounds) { int i,z; for(i=0;i<4;i++) { z=sounds[i]; if (z) { def_handle(hlptr,sound_table[z-1],wav_load,SR_ZVUKY); } hlptr++; } } static char miri_middle(TMOB *p) //procedura zjisti zda li potvora miri do dveri { int ss; ss=(p->sector<<2)+p->dir; return (map_sides[ss].lclip!=0); } static char pick_item_corpse(TMOB *m,char query) { short *p=NULL; int sector=m->sector; //sektor kde se bude mrtvola prohledavat if (map_coord[sector].flags & MC_DEAD_PLR) //lezi tam vubec nejaka mrtvola? { int i; THUMAN *h; //najdi mezi hraci mrtvolu ktera tam lezi for(i=0,h=postavy;ilives && h->used && h->inmaphash == current_map_hash &&h->sektor==sector) { int i; //podivej se ji do inventare.... for(i=0;iprsteny[i]) p=&h->prsteny[i]; //nejprve ber prsteny for(i=0;iwearing[i]) p=&h->wearing[i]; //pak seber zbrane a brneni for(i=0;iinv_size && p==NULL;i++) if (h->inv[i]) p=&h->inv[i]; //teprve potom se podivej co ma v inv. } } if (p!=NULL) //nasel jsi neco? if (query==PK_QUERY) return 1; //pokud se jednalo o dotaz, tak pouze vrat 1 else { int i; for(i=0;iinv[i]==0) break; //zjisti jestli mas misto if (i==MOBS_INV) return 0; //nemas, mas smulu.... m->inv[i]=*p; //prenes predmet od postavy do sveho inventare. *p=0; //ale na puvodnim miste tento predmet znic. } else return 0; return 1; } static char seber_predmet(TMOB *m) { short *p=NULL,*q; int i,j,c,z = 0; for(j=0,c=0;jinv[j]==0),++j); i=0; do { for(;i<4 && p==NULL;i+=(p==NULL)) pop_item(m->sector,i,0,&p); if (i==4) return 1; z=count_items_total(p); if (z>c) { push_item(m->sector,i,p); free(p); p=NULL; } i++; } while (z>c); if (z<=c) for(q=p,j=0;jinv[j]==0) m->inv[j]=(abs(*q++)); free(p); return 0; } static void mob_sound_event(TMOB *m, int event) { if (m->sounds[event] && m->vlajky & MOB_LIVE && ~m->vlastnosti[VLS_KOUZLA] & SPL_STONED) { if (event == MBS_WALK) { play_sample_at_sector( m->cislo_vzoru + 16 * 6 + event + monster_block, viewsector, m->sector, m - mobs + 256, (m->vlajky & MOB_SAMPLE_LOOP) != 0); } else { play_sample_at_sector( m->cislo_vzoru + 16 * 6 + event + monster_block, viewsector, m->sector, 0, 0); } } } void load_enemies(short *data,int size,int *grptr,TMOB *template,int32_t tsize) { int i; short cisla[256]; monster_block=*grptr; memset(cisla,0xff,sizeof(cisla)); size>>=2; for(i=0;iMAX_MOBS-MOB_START) size=MAX_MOBS-MOB_START; for(i=0;i0)mobs[i].palette=rnd(mobs[i].palette);else mobs[i].palette=abs(mobs[i].palette); mobs[i].sector=data[0]; mobs[i].dir=(data[1]>>14)&0x3; mobs[i].home_pos=data[0]; mobs[i].vlajky|=MOB_LIVE; if (mobs[i].speed<1) { char buff[256]; closemode(); sprintf(buff,"Nestvura cislo #%d (%s) je spatne definovana (rychlost)",i,mobs[i].name); display_error(buff); exit(1); } cisla[i]=mobs[i].cislo_vzoru; for(j=0;j0 && cnt<5;cnt++,dir=(dir+1)&3) if (!(i=mob_check_next_sector(sector,dir,alone,mobile))) { r--; if (!r) break; } if (cnt==5) dir=-1; return dir; } char je_mozne_videt(int sector1, int sector2, int flag) { int x1, y1; int x2, y2; int xs, ys; int x, y, ly, s; if (map_coord[sector1].layer != map_coord[sector2].layer) return 0; x1 = map_coord[sector1].x; x2 = map_coord[sector2].x; y1 = map_coord[sector1].y; y2 = map_coord[sector2].y; xs = x1 - x2; ys = y1 - y2; if (xs == 0 && ys == 0) return 1; s = sector1; ly = 0; if (xs >= 0) { for (x = 0; x <= xs; x++) { y = (x + 1) * ys / (xs + 1); while (y > ly) { if ((map_sides[(s << 2)].flags & flag) != (unsigned) flag) { s = map_sectors[s].step_next[0]; ly++; } else return 0; } while (y < ly) { if ((map_sides[(s << 2) + 2].flags & flag) != (unsigned) flag) { s = map_sectors[s].step_next[2]; ly--; } else return 0; } if (x != xs) { if ((map_sides[(s << 2) + 3].flags & flag) != (unsigned) flag) { s = map_sectors[s].step_next[3]; } else { return 0; } } } } else if (xs < 0) { for (x = 0; x >= xs; x--) { y = (x - 1) * ys / (xs - 1); while (y > ly) if ((map_sides[(s << 2)].flags & flag) != (unsigned) flag) { s = map_sectors[s].step_next[0]; ly++; } else return 0; while (y < ly) if ((map_sides[( s << 2) + 2].flags & flag) != (unsigned) flag) { s = map_sectors[s].step_next[2]; ly--; } else return 0; if (x != xs) { if ((map_sides[(s << 2) + 1].flags & flag) != (unsigned) flag) { s = map_sectors[s].step_next[1]; } else { return 0; } } } } return s == sector2; } int q_vidis_postavu(int sector,int dir,TMOB *p,int *otocit_se,char ret) { int i,z=-1; int xs,ys,nd=0,d,dis=255; if (p->vlastnosti[VLS_KOUZLA] & SPL_BLIND) return -1; if (p->vlastnosti[VLS_KOUZLA] & SPL_FEAR) return -1; if (p->flee_num==100 && !insleep) return -1; for(i=0;iused && ps->inmaphash == current_map_hash) { xs=map_coord[sector].x-map_coord[postavy[i].sektor].x; ys=map_coord[sector].y-map_coord[postavy[i].sektor].y; d=MAX(abs(xs),abs(ys)); if (d<=p->dohled && (!(ps->vlastnosti[VLS_KOUZLA] & SPL_INVIS)||p->vlajky & MOB_SENSE) && ps->used && ps->lives && ps->inmaphash == current_map_hash) switch(dir) { case 0:ok=ys>=0;break; case 1:ok=xs<=0;break; case 2:ok=ys<=0;break; case 3:ok=xs>=0;break; } if (ok) if (je_mozne_videt(sector,postavy[i].sektor,SD_MONST_IMPS | SD_PLAY_IMPS)) { int alt = 0; if (ys>=abs(xs)) {nd=0;alt=xs>0?3:1;} else if (xs>=abs(ys)) {nd=3;alt=ys>0?0:2;} else if (ys<=(-abs(xs))) {nd=2;alt=xs>0?1:3;} else if (xs<=(-abs(ys))) {nd=1;alt=ys>0?2:0;} if (mob_check_next_sector(p->sector,nd,p->stay_strategy & MOB_BIG,p->vlajky & MOB_PASSABLE)==1) { nd=alt; if (mob_check_next_sector(p->sector,nd,p->stay_strategy & MOB_BIG,p->vlajky & MOB_PASSABLE)==1) { nd=(alt+2)&3; if (mob_check_next_sector(p->sector,nd,p->stay_strategy & MOB_BIG,p->vlajky & MOB_PASSABLE)==1) { nd=(alt+3)&3; } } } } else d=255; else d=255; if (d!=255) { d*=2; if (xs!=0 && ys!=0) d+=3;//dej prednost tem co jsou na tve souradnici. if (dheadx!=255 && p->headx!=0 && p->headx!=128) return 128-p->headx; if (p->heady!=255 && p->heady!=0 && p->heady!=128) return 128-p->heady; } if (p->headx!=255 && p->headx!=0) p->headx=128+kolik; if (p->heady!=255 && p->heady!=0) p->heady=128+kolik; return -kolik; } void stop_mob(TMOB *p) { int num1; TMOB *q; p->mode=MBA_NONE; num1=mob_map[p->sector]; if (num1) q=&mobs[num1-MOB_START];else q=p; if (p==q) { if (p->next) { q=mobs+p->next-MOB_START; } else { q=NULL; } } if (p->stay_strategy & MOB_BIG) { p->headx=128; p->heady=128; goto end; } if (q!=NULL && p->dir!=q->dir) { p->headx=mob_batt_x[p->dir]; p->heady=mob_batt_y[p->dir]; q->headx=mob_batt_x[q->dir]; q->heady=mob_batt_y[q->dir]; mob_walk_sound(p); mob_walk_sound(q); return; } if (q!=NULL && p->dir==q->dir) { if (miri_middle(q)) { p->dir=(p->dir+1) & 3; stop_mob(q); } } else { if (p->dir & 1) { p->headx=mob_batt_x[p->dir]; if (p->heady==255 || p->heady==0) p->heady=128; } else { p->heady=mob_batt_y[p->dir]; if (p->headx==255 || p->headx==0) p->headx=128; } goto end; } { switch (p->dir) { case 0: case 2:if (q->headx==128) { if (p->headx<128) q->headx=128+MOB_DIST;else q->headx=128-MOB_DIST; } p->headx=-q->headx; p->heady=mob_batt_y[p->dir]; break; case 1: case 3:if (q->heady==128) { if (p->heady<128) q->heady=128+MOB_DIST;else q->heady=128-MOB_DIST; } p->heady=-q->heady; p->headx=mob_batt_x[p->dir];break; } } end: mob_walk_sound(p); } void stop_all_mobs() { int i; for(i=0;inext; } } char mob_test_na_bitvu(TMOB *p) { int x,d; char c=0; char pt; if (nohassle) return 0; if (p->stay_strategy & MOB_WATCH) if ((d=q_vidis_postavu(p->sector,p->dir,p,&x,0))>-1) { p->stay_strategy|=MOB_WALK; if (mob_check_next_sector(p->sector,x,p->stay_strategy & MOB_BIG,p->vlajky & MOB_PASSABLE)!=1) { pt=(p->headx==p->locx && p->heady==p->locy); if (p->dir!=x || pt) { p->dir=x; if (!(p->stay_strategy & MOB_BIG) || pt) { p->headx=mob_go_x[x]; p->heady=mob_go_y[x]; } else { p->headx=128; p->heady=128; } } if (q_zacit_souboj(p,d,att_sect)) { stop_mob(p); p->vlajky|=MOB_IN_BATTLE; if (!battle) zacni_souboj(p,d,att_sect); } c=1; } if (c) mob_sound_event(p,MBS_WALK); return c; } return 0; } char return_home(TMOB *p,int *smer) { word *path; int i; i=p->dir; if (!mob_check_next_sector(p->sector,(i+1)&3,p->stay_strategy & MOB_BIG,0) || !mob_check_next_sector(p->sector,(i+3)&3,p->stay_strategy & MOB_BIG,0)) return 1; if (p->sector==p->home_pos) return 1; najdi_cestu(p->sector,p->home_pos,SD_MONST_IMPS,&path,(p->stay_strategy & MOB_BIG)?1:2); if (path==NULL) { return 1; } for(i=0;i<4 && map_sectors[p->sector].step_next[i]!=path[0];i++); free(path); if (i==4) return 1; if (mob_check_next_sector(p->sector,i,p->stay_strategy & MOB_BIG,0)) return 1; *smer=i; return 0; } static int jdi_po_ceste(int old,TMOB *p) { int i,s; word *c; if (p->mode==MBA_FLEE && !p->actions--) //v pride uteku pocitej kroky { p->mode=0; p->vlajky&=~MOB_IN_BATTLE; return old; } c=mob_path_ptr[p-mobs]; //vem cestu if (c==NULL) return old; //neni -> konec if (*c==0) //na konci -> dealokace a konec { free_path(p-mobs); p->mode=0; p->vlajky&=~MOB_IN_BATTLE; return old; } s=p->sector; for(i=0;i<4;i++) if (map_sectors[s].step_next[i]==*c) break; if (i==4) return old; old=i; c++; mob_path_ptr[p-mobs]=c; //uloz_ukazatel return old; } void rozhodni_o_smeru(TMOB *p) { int sect,dir,r,v,c,alone,oldwalk,passable; int vdir=-1; alone=p->stay_strategy & MOB_BIG; passable=p->vlajky & MOB_PASSABLE; sect=p->sector; dir=p->dir; if (mob_paths[p-mobs]!=NULL) c=jdi_po_ceste(-1,p);else c=-1; if (c!=-1) { if (!mob_check_next_sector(sect,c,alone,passable)) { p->headx=mob_go_x[c]; p->heady=mob_go_y[c]; p->dir=c; goto end1; } else { if (mob_path_ptr[p-mobs]-mob_paths[p-mobs]>1) mob_path_ptr[p-mobs]-=2; } } if (p->vlajky & MOB_IN_BATTLE) { stop_mob(p); goto end1; } if (call_mob_event(p->specproc,SMPR_WALK,p)) goto end1; oldwalk=p->walk_data; if (mob_test_na_bitvu(p)) return; p->vlajky&=~MOB_IN_BATTLE; c=map_sectors[sect].sector_type; c-=S_SMER; if (c>=0 && c<4 && !mob_check_next_sector(sect,c,alone,passable)) { if (p->headx==p->locx && p->heady==p->locy) dir=c+4;else dir=c; } else { v=mob_pocet_vychodu(sect,dir); if (v==p->walk_data && !mob_check_next_sector(sect,dir,alone,passable)) if (p->headx==p->locx && p->heady==p->locy) dir=p->dir+4;else dir=p->dir; else { r=1; if (v==0) v=1; p->walk_data=v; if (v==1 && p->stay_strategy & MOB_GUARD) r=return_home(p,&dir); if (r) { if (v<2) r=1;else r=rnd(v)+1; vdir=dir=mob_vyber_vychod(r,sect,dir,alone,passable); //if ( p->stay_strategy & MOB_WATCH && rnd(100)<20 && lv<128 && dir!=p->dir) dir=-1; } } } if (dir==-1) { dir=p->dir;p->dir=(p->dir+2)&3; stop_mob(p); p->walk_data=rnd(32)+223; if (vdir!=-1)p->dir=vdir; } else if (p->dir!=dir || miri_middle(p)) { if (p->stay_strategy & MOB_BIG && (p->locx!=p->headx || p->locy!=p->heady)) { stop_mob(p); p->walk_data=oldwalk; } else if (((p->dir-dir) &0x3)==2 && (p->headx!=p->locx || p->heady!=p->locy)) { stop_mob(p); p->walk_data=0; } else { dir&=3; p->headx=mob_go_x[dir]; p->heady=mob_go_y[dir]; p->dir=dir; } } end1: if (p->headx!=p->locx || p->heady!=p->locy) mob_sound_event(p,MBS_WALK); } void krok_moba(TMOB *p) { if (!mob_check_next_sector(p->sector,p->dir,p->stay_strategy,p->vlajky)) { p->headx=mob_go_x[p->dir]; p->heady=mob_go_y[p->dir]; } } typedef struct enemy_face_tag { int pos; int face; int mirror; } TENEMY_FACE; TENEMY_FACE get_enemy_face(TMOB *p,int dirmob,int action,int curdir) { TENEMY_FACE ret; int view;int pos; int xs,ys; ret.mirror = 0; if (action==MOB_ATTACK) pos=4; else if (action==MOB_TO_HIT) pos=5; else if (action==MOB_DEATH) { ret.pos = 0; ret.face = 0; return ret; } else { xs=p->headx-p->locx; ys=p->heady-p->locy; if (!(game_extras & EX_WALKDIAGONAL) || p->stay_strategy & MOB_BIG) if (ys!=0 && xs!=0) { if (p->dir==1 || p->dir==3) xs=0;else ys=0; } if (xs) dirmob=(xs<0)?3:1; if (ys) dirmob=(ys<0)?0:2; pos=(2+dirmob-curdir)&0x3; if (game_extras & EX_WALKDIAGONAL && !( p->stay_strategy & MOB_BIG)) { switch (curdir & 0x3) { case 0: if (p->locx>p->headx) pos=1;else if (p->locxheadx) pos=3;break; case 1: if (p->locy>p->heady) pos=1;else if (p->locyheady) pos=3;break; case 2: if (p->locx>p->headx) pos=3;else if (p->locxheadx) pos=1;break; case 3: if (p->locy>p->heady) pos=3;else if (p->locyheady) pos=1;break; } } } if (pos==3) ret.mirror=pos=1; if (p->anim_counter==-1) view=pos*16; else view=pos*16+(p->anim_counter % p->anim_counts[pos])+1; ret.face = view; ret.pos = pos; return ret; } void get_pos(int x,int y,int *xpos,int *ypos,int dir) { switch(dir) { case 0:*xpos=x;*ypos=-y;break; case 1:*xpos=y;*ypos=x;break; case 2:*xpos=-x;*ypos=y;break; case 3:*xpos=-y;*ypos=-x;break; } } /* void draw_blood(int zasah,int celx,int cely,int posx,int posy) { draw_placed_texture(ablock(H_MZASAH1+zasah-1),celx,cely,posx+64,posy+64,75,0); } */ static const void *mob_select_palette(TMOB *p) { const char *palet; palet=ablock(p->cislo_vzoru+6*16+4+monster_block); return palet+(p->palette)*PIC_FADE_PAL_SIZE; } static void CheckMobStoned(int num) { if (mobs[num].vlastnosti[VLS_KOUZLA] & SPL_STONED) { TMOB *p=mobs+num; TMOBSAVEDATA *save; if (!mobsavedata) { mobsavedata=(TMOBSAVEDATA **)getmem(sizeof(TMOBSAVEDATA *)*MAX_MOBS); memset(mobsavedata,0,sizeof(TMOBSAVEDATA)*MAX_MOBS); } save=mobsavedata[num]; if (save==NULL) { save=mobsavedata[num]=(TMOBSAVEDATA *)getmem(sizeof(TMOBSAVEDATA)); save->anim_counter=p->anim_counter; save->anim_phase=p->anim_phase; save->dir=p->dir; } else { p->anim_counter=save->anim_counter; p->anim_phase=save->anim_phase; p->dir=save->dir; p->headx=p->locx; p->heady=p->locy; } } else { if (mobsavedata && mobsavedata[num]) { free(mobsavedata[num]); mobsavedata[num]=0; } } } static void fill_drw_enemy_struct(TMOB *m, DRW_ENEMY *enm, char *buff, int curdir) { if (!show_mob_info) { enm->more_info = NULL; return; } char flag_buff[100] = ""; char strategy_buff[100] = ""; const char *strategies[] = { "WALK","WATCH","LISTEN","BIG","GUARD","PICK","PICKING","ROGUE" }; const char *flags[] = { "BATTLE","PASSABLE","SENS","MOB","RESPWN","CAST","SNDLP","LIVE" }; const char *modes[] = {"NONE","CAST","FLEE","ATTACK"}; const char *actions[] = { "STANDFWD","STANDLEFT","STANDBACK","STANDRIGHT","STANDLEFTMIRR", "WALKFWD","WALKLEFT","WALKBACK","WALKRIGHT","WALKLEFTMIRR", "ATTACK","ATTACKMIRR","INPAIN","INPAINMIRR","ERR"}; TENEMY_FACE fc = get_enemy_face(m,m->dir,m->anim_phase,curdir); int action = countof(actions)-1; int stand = (fc.face & 0xF) == 0; if (fc.pos < 4) { action = (fc.mirror?4:fc.pos) + (stand?0:5); } else { action = ((fc.pos - 4)*2+(fc.mirror?1:0))+10; } for (int i = 0; i < 8; i++) { if (m->stay_strategy & (1<vlajky & (1<name, actions[action], m->walk_data, m->dohled, m->dosah, m->dostal, modes[(uint8_t)m->mode], strategy_buff, flag_buff, mob_paths[m - mobs]!=NULL?"YES":"NO" ); enm->more_info = buff; } void draw_mob_call(int num,int curdir,int celx,int cely,char shiftup) { TMOB *p,*q; TENEMY_FACE view; int vw; TENEMY_FACE view2; int vw2; DRW_ENEMY drw1,drw2; char buff[256], buff2[256]; set_font(H_FLITT5,RGB555(31,31,0)); CheckMobStoned(num-MOB_START); p=&mobs[num-MOB_START]; shiftup|=(p->stay_strategy & MOB_BIG); get_pos(p->locx-128,p->locy-128,&drw1.posx,&drw1.posy,curdir); view=get_enemy_face(p,p->dir,p->anim_phase,curdir); vw=p->cislo_vzoru+view.face+monster_block; if ((p->vlastnosti[VLS_KOUZLA] & SPL_INVIS) && !true_seeing) { drw1.txtr = NULL; vw = 0; } else { drw1.txtr = ablock(vw); } drw1.celx=celx; drw1.cely=cely; drw1.mirror=view.mirror; drw1.adjust=p->adjusting[view.face]; drw1.shiftup=shiftup; drw1.num=p->lives; drw1.palette=mob_select_palette(p); drw1.stoned= (p->vlastnosti[VLS_KOUZLA] & SPL_STONED)!=0; see_monster|=(~p->vlajky & MOB_PASSABLE); fill_drw_enemy_struct(p, &drw1, buff, curdir); if (p->next) { CheckMobStoned(p->next-MOB_START); q=&mobs[p->next-MOB_START]; get_pos(q->locx-128,q->locy-128,&drw2.posx,&drw2.posy,curdir); view2=get_enemy_face(q,q->dir,q->anim_phase,curdir); vw2=view2.face+q->cislo_vzoru+monster_block; drw2.shiftup=shiftup; drw2.celx=celx; drw2.cely=cely; alock(vw); alock(vw+6*16+5); if ((q->vlastnosti[VLS_KOUZLA] & SPL_INVIS) && !true_seeing) { drw2.txtr = NULL; vw2 = 0; } else { drw2.txtr = ablock(vw2); } drw2.mirror=view2.mirror; alock(vw2); alock(vw2+6*16+5); drw2.adjust=q->adjusting[view2.face]; drw2.num=q->lives; drw2.palette=mob_select_palette(q); drw2.stoned=(q->vlastnosti[VLS_KOUZLA] & SPL_STONED)!=0; see_monster|=(~q->vlajky & MOB_PASSABLE); fill_drw_enemy_struct(q, &drw2, buff2, curdir); } else { draw_enemy(&drw1); return; } if (drw1.posy>drw2.posy) { draw_enemy(&drw1); draw_enemy(&drw2); } else { draw_enemy(&drw2); draw_enemy(&drw1); } aunlock(vw); aunlock(vw2); aunlock(vw+6*16+5); aunlock(vw2+6*16+5); } void draw_mob(int num,int curdir,int celx,int cely,char shiftup) { int ss=(num<<2); num=mob_map[num]; if (!num) return; set_lclip_rclip(celx,cely,map_sides[ss+((curdir+3)&3)].lclip,map_sides[ss+((curdir+1)&3)].lclip); draw_mob_call(num,curdir,celx,cely,shiftup); } void otoc_moba(TMOB *p) { p->walk_data=255; rozhodni_o_smeru(p); } static int mob_check_teleport(int sect,int num) { int i; if (!ISTELEPORTSECT(sect)) return sect; play_sample_at_sector(H_SND_TELEPOUT,viewsector,sect,0,0); add_spectxtr(sect,H_TELEP_PCX,14,1,0); sect=map_sectors[sect].sector_tag; play_sample_at_sector(H_SND_TELEPOUT,viewsector,sect,0,0); add_spectxtr(sect,H_TELEP_PCX,14,1,0); if (map_coord[sect].flags & MC_PLAYER) { THUMAN *h=postavy; for(i=0;isektor==sect) player_hit(h,h->lives,0); } mobs[num].locx=128; mobs[num].locy=128; return sect; } void mob_step_next(int num,int sect,int dir,char *change) { int c,numm,d = 0; TMOB *p; *change+=128; numm=num+MOB_START; if (~mobs[num].vlajky & MOB_MOBILE) { c=mob_map[sect]; if (c!=numm) mobs[c-MOB_START].next=0; else mob_map[sect]=mobs[num].next; mobs[num].next=0; recheck_button(sect,1); } sect=map_sectors[sect].step_next[dir]; if (~mobs[num].vlajky & MOB_MOBILE) { sect=mob_check_teleport(sect,num); c=mob_map[sect]; if (c) { mobs[num].next=c; d=uhni_mobe(1,num,0); if (d) d=uhni_mobe(1,c-MOB_START,d); else d=uhni_mobe(1,c-MOB_START,-MOB_DIST); } mob_map[sect]=numm; recheck_button(sect,1); } mobs[num].sector=sect; p=&mobs[num]; p->dir=dir; rozhodni_o_smeru(p); if (p->next) uhni_mobe(0,num,d); if (p->stay_strategy & MOB_PICKING) { for(c=0;c<4;c++) if (map_items[(p->sector<<2)+c]!=NULL) break; if (c==4 && pick_item_corpse(p,PK_QUERY)) c=0; if (c!=4) { stop_mob(p); p->stay_strategy|=MOB_PICK; } } } void mob_check(int num,TMOB *p) { int sect,q,z; sect=p->sector; q=p->stay_strategy & MOB_BIG; z=p->vlajky & MOB_PASSABLE; if (p->locy<64) { if (mob_check_next_sector(sect,0,q,z)) otoc_moba(p); else mob_step_next(num,sect,0,&p->locy); } else if (p->locx>191) { if (mob_check_next_sector(sect,1,q,z)) otoc_moba(p); else mob_step_next(num,sect,1,&p->locx); } else if (p->locy>191) { if (mob_check_next_sector(sect,2,q,z)) otoc_moba(p); else mob_step_next(num,sect,2,&p->locy); } else if (p->locx<64) { if (mob_check_next_sector(sect,3,q,z)) otoc_moba(p); else mob_step_next(num,sect,3,&p->locx); } if (battle && p->mode!=MBA_FLEE) { mob_sound_event(p,MBS_WALK); stop_mob(p); } } /*void mobs_attack(TMOB *p) { int sect,dir,asect; if (p->actions<=0) return; neco_v_pohybu=1; sect=p->sector; dir=p->dir; asect=map_sectors[sect].step_next[dir]; if (!asect || map_sides[sect*4+dir].flags & SD_MONST_IMPS) { rozhodni_o_smeru(p); p->headx=mob_go_x[p->dir]; p->heady=mob_go_y[p->dir]; p->anim_phase=0; return; } if (!(map_coord[asect].flags & MC_PLAYER)) { rozhodni_o_smeru(p); p->headx=mob_go_x[p->dir]; p->heady=mob_go_y[p->dir]; p->anim_phase=0; return; } p->anim_phase=MOB_ATTACK; p->csektor=asect; viewsector=asect; viewdir=(dir+2)&3; }*/ void vymaz_zasahy(THE_TIMER *q) { if (q->userdata[1]!=postavy[q->userdata[0]].dostal) return; postavy[q->userdata[0]].dostal=0; bott_draw(0); } static int drop_inventory(TMOB *p) { int i,x,y,pl; short c[]={0,0}; for(i=-1;iinv[i] || (i<0 && p->money)) { if (p->locx>128) x=1;else if (p->locx<128) x=-1;else x=rnd(2)*2-1; if (p->locy>128) y=1;else if (p->locy<128) y=-1;else y=rnd(2)*2-1; pl=0;if (x>0) pl++; if (y>0) pl=3-pl; if (i<0) { int z=(int)p->money+(int)(rnd(40)-20)*(int)p->money/(int)100; c[0]=create_item_money(z); } else { c[0]=p->inv[i]; p->inv[i]=0; } push_item(p->sector,pl,c); } return 0; } void mob_check_death(int num,TMOB *p) { int sect; mob_dostal=0; bott_draw(0); if (p->lives>0) return; SEND_LOG("(GAME) Monster killed ... '%s'",p->name); sect=p->sector; p->vlajky&=~MOB_IN_BATTLE & ~MOB_LIVE; free_path(num); drop_inventory(p); if (mob_map[sect]==num+MOB_START) mob_map[sect]=p->next; else { p=&mobs[mob_map[sect]-MOB_START]; p->next=0; } pozdrz_akci(); } extern char att_player; void mob_hit(TMOB *mm, int dostal) { int ch; int mob_dostal = 0, mob_dostal_pocet = 0; if (mm->vlajky & MOB_PASSABLE) return; if (dostal > mm->vlastnosti[VLS_MAXHIT]) dostal = mm->vlastnosti[VLS_MAXHIT]; mm->headx = mm->locx; mm->heady = mm->locy; mm->lives -= dostal; mob_dostal_pocet = dostal; mm->dostal += dostal; if (dostal > 0) mm->vlajky |= MOB_IN_BATTLE; //mm->stay_strategy|=MOB_WALK | MOB_WATCH; mm->dialog_flags |= 0x2; if (mm->lives > mm->vlastnosti[VLS_MAXHIT]) mm->lives = mm->vlastnosti[VLS_MAXHIT]; if (log_combat) wzprintf("%s was hit: %d, lives: %d\n", mm->name, dostal, mm->lives); if (dostal > 0) { send_experience(mm, dostal); att_player = select_player; if (dostal < mm->lives) ch = dostal * 3 / mm->lives; else ch = 2; mob_dostal = ch + 1; bott_draw(0); if (mm->lives < 1) { int xpos = 0; switch (viewdir) { case 0: xpos = -(mm->locx - 128); break; case 1: xpos = -(mm->locy - 128); break; case 2: xpos = (mm->locx - 128); break; case 3: xpos = (mm->locy - 128); break; } add_spectxtr(mm->sector, H_KILL, 10, 1, xpos * 23 / 10); mm->anim_phase = MOB_DEATH; } else mm->anim_phase = MOB_TO_HIT; mm->anim_counter = 0; mm->mode = MBA_NONE; mob_sound_event(mm, MBS_HIT); battle |= dostal > 0; if (vybrana_zbran > -1) //utok zbrani? { int druh; if (vybrana_zbran != 0) //neni to utok holyma rukama { TITEM *it; it = &glob_items[vybrana_zbran - 1]; druh = it->typ_zbrane; } else druh = TPW_OST; send_weapon_skill(druh); vybrana_zbran = -1; } } if (mob_dostal_pocet > 0) draw_blood(1, mob_dostal, mob_dostal_pocet); } void mob_strelba(TMOB *p) { int i; TITEM *t; for(i=0;izmeny[VLS_MGSIL_H]=p->vlastnosti[VLS_MGSIL_H]; //adjust zmen v magickem utoku t->zmeny[VLS_MGSIL_L]=p->vlastnosti[VLS_MGSIL_L]; t->zmeny[VLS_MGZIVEL]=p->vlastnosti[VLS_MGZIVEL]; spell_throw(-((p-mobs)+1),i); letici_veci->flags &=~FLY_DESTROY; int att = p->vlastnosti[VLS_OBRAT]/5; int attack_roll = p->vlastnosti[VLS_UTOK_L]+rnd(p->vlastnosti[VLS_UTOK_H]-p->vlastnosti[VLS_UTOK_L]+1); letici_veci->hit_bonus= attack_roll + att; if (log_combat) { wzprintf("%s shoots: %d (roll %d-%d) + %d (%s/5) = %d\n", p->name, attack_roll, p->vlastnosti[VLS_UTOK_L],p->vlastnosti[VLS_UTOK_H],att,texty[13],letici_veci->hit_bonus); } letici_veci->damage=p->vlastnosti[VLS_DAMAGE]; p->dostal=0; } static void knock_player_back(THUMAN *p,int dir) { int sect,sid,nsect; sect=p->sektor;sid=sect*4+dir; nsect=map_sectors[sect].step_next[dir]; if (mob_map[nsect]) return; destroy_player_map(); call_macro(sid,MC_EXIT); if (map_sides[sid].flags & SD_PLAY_IMPS) { call_macro(sid,MC_PASSFAIL); build_player_map(); return; } else call_macro(sid,MC_PASSSUC); p->sektor=nsect; viewsector=nsect; check_postavy_teleport(); build_player_map(); recheck_button(nsect,1); recheck_button(sect,1); redraw_scene(); hold_timer(TM_BACK_MUSIC,1); zooming_backward(ablock(H_BGR_BUFF)); hold_timer(TM_BACK_MUSIC,0); showview(0,0,0,0); } void PodporaStitu(THUMAN *h, short *vlastnosti) { int pos[]={PO_RUKA_L,PO_RUKA_R}; int i; int factor=h->kondice*100/h->vlastnosti[VLS_KONDIC]; for (i=0;i<2;i++) { if (h->wearing[pos[i]]!=0) { TITEM *it=glob_items+h->wearing[pos[i]]-1; if (it->zmeny[VLS_OBRAN_L] || it->zmeny[VLS_OBRAN_H]) { vlastnosti[VLS_OBRAN_L]-=it->zmeny[VLS_OBRAN_L]; vlastnosti[VLS_OBRAN_H]-=it->zmeny[VLS_OBRAN_H]; vlastnosti[VLS_OBRAN_L]+=(2*it->zmeny[VLS_OBRAN_L])*factor/100; vlastnosti[VLS_OBRAN_H]+=(2*it->zmeny[VLS_OBRAN_H])*factor/100; } } } if (factor<20) { vlastnosti[VLS_OBRAT]=vlastnosti[VLS_OBRAT]*factor/20; } if (h->kondice) h->kondice--; } void mobs_hit(TMOB *p) { int asect; int obet; int i,pocet; THE_TIMER *tt; int spec;char rr=1;char dead; THUMAN *h; short vlastnosti[VLS_MAX]; if (p->mode==MBA_SPELL) { mob_cast(p->casting,p,p-mobs); p->dostal=0; } else if (p->stay_strategy & MOB_ROGUE) mob_strelba(p); else { asect=p->csektor; if (!(map_coord[asect].flags & MC_PLAYER)) return; pocet=0; for(i=0;iused && p->sektor==asect && p->lives && p->inmaphash == current_map_hash) pocet++; } if (!pocet) abort(); obet=1+rnd(pocet); for(i=0;obet>0;) { THUMAN *p; i++; if (i>=POCET_POSTAV) i=0; p=&postavy[i]; if (p->used && p->sektor==asect && p->lives && p->inmaphash == current_map_hash) obet--; } h=&postavy[i]; if (h->utek) { pocet=10; h->utek--; } memcpy(vlastnosti,h->vlastnosti,sizeof(vlastnosti)); spec=vlastnosti[VLS_KOUZLA]; if (game_extras & EX_SHIELD_BLOCKING) PodporaStitu(h,vlastnosti); else uprav_podle_kondice(h,&pocet); h->dostal=vypocet_zasahu(p->vlastnosti,vlastnosti,pocet,0,0,1); //vypocet zasahu if (h->dostal) p->dostal=0; if (spec & SPL_OKO) //oko za oko pro hrace { vybrana_zbran=-1; mob_hit(p,h->dostal); if (log_combat) wzprintf("%s was hit (eye for an eye): %d\n", p->name, h->dostal); mob_check_death(p-mobs,p); } if (h->dostal && p->vlastnosti[VLS_KOUZLA] & SPL_KNOCK) knock_player_back(h,p->dir); if (p->vlastnosti[VLS_KOUZLA] & SPL_DRAIN) //energy drain pro potvoru { p->lives+=h->dostal; if (p->lives>p->vlastnosti[VLS_MAXHIT])p->lives=p->vlastnosti[VLS_MAXHIT]; if (log_combat) wzprintf("%s drained HP : %d, lives %d\n", p->name, h->dostal, p->lives); } dead=player_hit(h,h->dostal,1); if (h->lives>h->vlastnosti[VLS_MAXHIT]) h->lives=h->vlastnosti[VLS_MAXHIT]; if ((spec & SPL_TVAR) && (spec & SPL_OKO)) //nedovolena kombinace { char s[200]; h->lives=0; sprintf(s,texty[73+(postavy[i].female==1)],postavy[i].jmeno); bott_disp_text(s); rr=0; dead=player_check_death(&postavy[i],0); } tt=add_to_timer(TM_CLEAR_ZASAHY,100,1,vymaz_zasahy);tt->userdata[0]=i;tt->userdata[1]=postavy[i].dostal; if (dead && hlubina_level>0) { select_player=i; vybrana_zbran=-1; mob_hit(p,p->lives); //hlubina (potvora je mrtva); } bott_draw(rr); } } void mobs_live(int num) { TMOB *p; int xs,ys; p=&mobs[num]; if (p->vlastnosti[VLS_KOUZLA] & SPL_STONED && p->lives>0) { p->vlajky &= ~MOB_IN_BATTLE; return; } if (p->sector>=mapsize) { char buff[256]; closemode(); sprintf(buff,"Potvora v neexistujicim sektoru (%d, %d) ",num,p->sector); display_error(buff); exit(1); } if (p->headx==p->locx && p->heady==p->locy && !p->anim_phase) { //zde se bude rozhodovat co dal; p->anim_counter=-1; stop_track_free(num+256); if (battle) { if (p->mode!=MBA_NONE && p->mode!=MBA_FLEE) { neco_v_pohybu=1; p->anim_phase=MOB_ATTACK; p->anim_counter=0; mob_sound_event(p,MBS_ATTACK); mobs_live(num); return; } if (p->mode==MBA_NONE) return; rozhodni_o_smeru(p); return; } if (p->stay_strategy & MOB_PICK) { if (!seber_predmet(p)) return; if (pick_item_corpse(p,PK_PICK)) return; p->stay_strategy&=~MOB_PICK; } if (p->stay_strategy & MOB_WALK) { if (p->walk_data>=224) if (++p->walk_data<255) { p->anim_counter=-1; return; } p->anim_counter=0; rozhodni_o_smeru(p); } else if (mob_map[p->sector]==num+MOB_START && (!p->next) ) { p->headx=128;p->heady=128; } } else { if (p->anim_phasemode==MBA_FLEE) { int xr=abs(map_coord[p->sector].x-map_coord[viewsector].x); int yr=abs(map_coord[p->sector].y-map_coord[viewsector].y); if (xr>3 || yr>3) spd=100;else spd=2*p->speed; } else spd=p->speed; xs=p->headx-p->locx; ys=p->heady-p->locy; if (!(game_extras & EX_WALKDIAGONAL) || p->stay_strategy & MOB_BIG) { if (ys!=0 && xs!=0) { if (p->dir==1 || p->dir==3) xs=0;else ys=0; }} if (xs>spd) xs=spd; else if (xs<-spd) xs=-spd; if (ys>spd) ys=spd; else if (ys<-spd) ys=-spd; p->locx+=xs; p->locy+=ys; if (xs!=0 || ys!=0) neco_v_pohybu=1; if (p->locx>192 || p->locx<64 || p->locy>192 || p->locy<64) mob_check(num,p); } p->anim_counter++; if (p->anim_phase==MOB_ATTACK) { neco_v_pohybu=1; if (p->anim_counter==p->hit_pos) mobs_hit(p); if (p->anim_counter>=p->anim_counts[4]) { if (p->lives<1) p->anim_phase=MOB_TO_HIT;else p->anim_phase=0; p->anim_counter=-1; p->mode=MBA_NONE; } } else if (p->anim_phase==MOB_TO_HIT && p->anim_counter>=p->anim_counts[5]) { neco_v_pohybu=1; p->anim_phase=0; p->anim_counter=-1; mob_check_death(num,p); } else if (p->anim_phase==MOB_DEATH) { neco_v_pohybu=1; if (p->anim_counter==2) mob_check_death(num,p); else if (p->anim_counter>12) { p->anim_phase=0; p->anim_counter=-1; } } } } void calc_mobs() { int i; neco_v_pohybu=0; for(i=0;ivlajky & MOB_LIVE) { mob_test_na_bitvu(p); if (p->vlajky & MOB_IN_BATTLE) b=1; } } battle=b; } void check_all_mobs_battle() //kontroluje zda je nekdo v battle { int i; TMOB *p; char b=0; for(i=0;ivlajky & MOB_LIVE) if (p->vlajky & MOB_IN_BATTLE) b=1; } battle=b; } #define Hi(x) ((x)>>16) #define Lo(x) ((x)& 0xffff) int q_kolik_je_potvor(int sector) { if (mob_map[sector]) { if (mobs[mob_map[sector] - MOB_START].next) { return 2; } else if (mobs[mob_map[sector] - MOB_START].stay_strategy & MOB_BIG) { return 2; } else { return 1; } } return 0; } void najdi_cestu(word start,word konec,int flag,word **cesta, int iamcnt) { longint *stack; longint *stk_free; longint *stk_cur; char *ok_flags; *cesta=NULL; stk_free=stk_cur=stack=getmem(4*(mapsize+2)); memset(ok_flags=getmem((mapsize+8)/8),0,(mapsize+8)/8); ok_flags[start>>3]|=1<<(start & 0x7); for(*stk_free++=start;stk_free!=stk_cur;stk_cur++) { uint8_t i;word s,d=0xFFFF,ss; s=(ss=Lo(*stk_cur))<<2; for(i=0;i<4;i++) if (!(map_sides[s+i].flags & flag)) { char c; word w; d=map_sectors[ss].step_next[i]; c=1<<(d & 0x7); w=d>>3; if (!(ok_flags[w] & c) && q_kolik_je_potvor(d)>3]|=1<<(start & 0x7); for(*stk_free++=start;stk_free!=stk_cur;stk_cur++) { uint8_t i;word s,d,ss; s=(ss=Lo(*stk_cur))<<2; for(i=0;i<4;i++) if (!(map_sides[s+i].flags & SD_SOUND_IMPS)) { char c; word w; d=map_sectors[ss].step_next[i]; c=1<<(d & 0x7); w=d>>3; if (!(ok_flags[w] & c)) { int mob; ok_flags[w]|=c; *stk_free++=d | ((stk_cur-stack)<<16); mob=mob_map[d]-MOB_START; if (mob>=0) { reakce_na_hluk(mob,(i+2)&3); if ((mob=mobs[mob].next-MOB_START)>=0) reakce_na_hluk(mob,(i+2)&3); } } } } free(stack); free(ok_flags); } void refresh_mob_map() { int i,s; memset(mob_map,0,mapsize); for(i=0;istay_strategy & MOB_BIG) return 0; if (mm->dir!=i && i!=-1) return 0; stop_mob(mm); if (!mm->next && i==-1) if (mm->headx==128 || mm->heady==128) smeruj_moba(mm,1); i=mm->dir;m=mm->next; } if (!(map_sides[(sect<<2)+dir].flags & SD_THING_IMPS)) sect=map_sectors[sect].step_next[dir]; else return 1; } while (1); } //--------------------------------------------------------------------- /* Nasledujici procedury a funkce se volaji pro chovani potvory v bitve */ typedef struct flee_monster_context { word last_sector; TMOB *fleeing_mob; } TFLEE_MONSTER_CONTEXT; static char valid_sectors(word sector, void *ctx) { int pp; TFLEE_MONSTER_CONTEXT *fmc = (TFLEE_MONSTER_CONTEXT *)ctx; fmc->last_sector=sector; if (map_coord[sector].flags & MC_MARKED) return 0; //nevyhovujici pp=q_kolik_je_potvor(sector); if (pp==2) return 0; //moc potvor - nevyhovujici if (fmc->fleeing_mob->stay_strategy & MOB_BIG && pp) return 0; pp=map_sectors[sector].sector_type; if (pp==S_DIRA || ISTELEPORT(pp)) return 0; return 1; } char flee_monster_zac(TMOB *m) { int ss,s; int i,j; word *cesta,*c,cntr; for(j=0;jsector,65535,SD_MONST_IMPS,valid_sectors,NULL,&fmc); i=labyrinth_find_path(m->sector,fmc.last_sector,SD_MONST_IMPS,valid_sectors,&cesta,&fmc); for(j=0;jmode=MBA_FLEE; m->headx=m->locx+1; m->actions=6; m->dostal=0; return 1; } char akce_moba_zac(TMOB *m) { int sect,flg,i,j; THUMAN *h; char flee; int perlives,dper,corlives; if (~m->vlajky & MOB_LIVE) return 1; dper=m->dostal*100/(m->lives+m->dostal); corlives=m->vlastnosti[VLS_MAXHIT]-m->flee_num*(m->vlastnosti[VLS_MAXHIT]-m->lives)/100; perlives=(100-m->flee_num)*corlives*q_kolik_je_potvor(m->sector)/(m->vlastnosti[VLS_MAXHIT]); perlives+=rnd(m->flee_num); dper+=rnd(m->flee_num); flee=dper>perlives || m->vlastnosti[VLS_KOUZLA] & SPL_FEAR; if (flee) { if (flee_monster_zac(m)) return 1; m->dostal=0; } if (call_mob_event(m->specproc,SMPR_ATTACK,m)) { mob_walk_sound(m); return 0; } sect=map_sectors[m->sector].step_next[m->dir]; flg=map_sides[(m->sector<<2)+m->dir].flags; if (!(flg & SD_PLAY_IMPS)) if (map_coord[sect].flags & MC_PLAYER) for(i=0;iused && p->lives && p->sektor==sect && p->inmaphash == current_map_hash) { if (((m->vlajky & MOB_CASTING) && get_spell_track(m->casting))|| m->stay_strategy & MOB_ROGUE) {stop_all_mobs_on_sector(m->sector);smeruj_moba(m,0);} else stop_mob(m); viewsector=sect; viewdir=(m->dir+2) &3; m->csektor=sect; if ((m->vlajky & MOB_CASTING)&& rnd(100)<=(unsigned int)m->vlastnosti[VLS_SMAGIE]) m->mode=MBA_SPELL;else m->mode=MBA_ATTACK; bott_draw(1); return 0; } } for(i=0;i<4;i++) { sect=map_sectors[m->sector].step_next[i]; flg=map_sides[(m->sector<<2)+i].flags; if (!(flg & SD_MONST_IMPS)) if (map_coord[sect].flags & MC_PLAYER) for(j=0;jused && p->lives && p->inmaphash == current_map_hash &&p->sektor==sect && !(p->vlastnosti[VLS_KOUZLA] & SPL_INVIS)) { m->dir=i; stop_mob(m); return 1; } } } sect=m->sector; i=q_vidis_postavu(m->sector,m->dir,m,&j,1); h=postavy+i; if (i>-1) { if (((m->vlajky & MOB_CASTING && get_spell_track(m->casting))|| m->stay_strategy & MOB_ROGUE) && (map_coord[m->sector].x==map_coord[h->sektor].x || map_coord[m->sector].y==map_coord[h->sektor].y) && track_mob(m->sector,m->dir)) { m->dir=j; stop_all_mobs_on_sector(m->sector); if (~m->stay_strategy & MOB_ROGUE) m->mode=MBA_SPELL; else m->mode=MBA_ATTACK; smeruj_moba(m,0); viewsector=h->sektor; viewdir=(m->dir+2) & 3; return 0; } else { word *cesta; najdi_cestu(m->sector,postavy[i].sektor,SD_MONST_IMPS,&cesta,(m->stay_strategy & MOB_BIG)?1:2); if (cesta!=NULL) { for(j=0;j<4 && map_sectors[sect].step_next[j]!=cesta[0];j++); m->dir=j & 3; free(cesta); if (m->dir & 1)m->headx=mob_go_x[m->dir];else m->heady=mob_go_y[m->dir]; mob_sound_event(m,MBS_WALK); return 1; } else return 1; } } rozhodni_o_smeru(m); if (m->dir & 1)m->headx=mob_go_x[m->dir];else m->heady=mob_go_y[m->dir]; // m->headx=mob_go_x[m->dir]; // m->heady=mob_go_y[m->dir]; m->vlajky&=~MOB_IN_BATTLE; return 1; } void mob_animuj() { int mob; for(mob=0;moblocylocy) return m;else if (m1->locy>m2->locy) return ch;break; case 1: if (m1->locxlocx) return m;else if (m1->locx>m2->locx) return ch;break; case 0: if (m1->locy>m2->locy) return m;else if (m1->locylocy) return ch;break; case 3: if (m1->locx>m2->locx) return m;else if (m1->locxlocx) return ch;break; } x=rnd(2); if (x) return ch; return m; } static void knock_mob_back(TMOB *mm,int dir) { char chk; int i,sek,mnum,mms; if (call_mob_event(mm->specproc,SMPR_KNOCK,mm)) return; mms=mm->sector;mnum=mm-mobs+MOB_START; chk=mob_check_next_sector(mms,dir,mm->stay_strategy,mm->vlajky); if (chk) return; sek=map_sectors[mms].step_next[dir]; i=mob_map[sek]; if (mob_map[mms]!=mnum) mobs[mob_map[mms]-MOB_START].next=0;else mob_map[mms]=mm->next; if (i) { mm->next=i; uhni_mobe(1,i-1,0); } else mm->next=0; mob_map[sek]=mm-mobs+MOB_START;mm->sector=sek; recheck_button(mms,1); recheck_button(sek,1); } static void remove_other_weapon_from_calc(THUMAN *p, short *vlastnosti, int poz) { int otherpoz = poz == PO_RUKA_L?PO_RUKA_R:PO_RUKA_L; int itnum = p->wearing[otherpoz]; if (itnum == 0) return; const TITEM *it = glob_items + itnum-1; if (it->druh != TYP_UTOC) return; int vls[] = {VLS_UTOK_H,VLS_UTOK_L,VLS_DAMAGE}; for (size_t i = 0; i < countof(vls); ++i) { vlastnosti[vls[i]] -= it->zmeny[vls[i]]; } } int utok_na_sektor(THUMAN *p,TMOB *mm,int ch,int bonus, int ruka) { int dostal; short vlastnosti[VLS_MAX]; const short *use_vls = p->vlastnosti; if (ruka == PO_RUKA_L || ruka == PO_RUKA_R) { memcpy(vlastnosti, p->vlastnosti, sizeof(vlastnosti)); remove_other_weapon_from_calc(p, vlastnosti, ruka); use_vls = vlastnosti; } dostal=vypocet_zasahu(use_vls,mm->vlastnosti,ch,bonus,0,ruka != PL_OBOUR); mob_hit(mm,dostal); if (dostal && p->vlastnosti[VLS_KOUZLA] & SPL_KNOCK) knock_mob_back(mm,p->direction); if (mm->vlastnosti[VLS_KOUZLA] & SPL_OKO) //oko za oko pro potvoru { p->lives-=dostal; if (log_combat) wzprintf("%s was hit (eye for an eye): %d\n", p->jmeno, dostal); player_check_death(p,0); } if (dostal) { mm->dir=(p->direction+2)&3; play_sample_at_sector(H_SND_SWHIT1+rnd(2),viewsector,viewsector,0,0); if (p->vlastnosti[VLS_KOUZLA] & SPL_DRAIN) { int drain_roll = rnd(16)+16; int drain = dostal*8/drain_roll; p->lives+=drain; if (log_combat) wzprintf("%s received (live drain): %d(hit) x 8 / %d(drain_roll) = %d HP\n", p->jmeno, dostal, drain_roll, drain); if (p->lives>p->vlastnosti[VLS_MAXHIT]) p->lives=p->vlastnosti[VLS_MAXHIT]; } } else { dostal=0; play_sample_at_sector(H_SND_SWMISS1+rnd(2),viewsector,viewsector,0,0); } mm->vlajky|=MOB_IN_BATTLE; neco_v_pohybu=1; return dostal; } void sleep_enemy(char regen) { int i; for(i=0;ivlajky & MOB_LIVE && m->lives>0) { if (regen) { m->lives+=m->vlastnosti[VLS_HPREG]; if (m->lives>m->vlastnosti[VLS_MAXHIT]) m->lives=m->vlastnosti[VLS_MAXHIT]; } if (m->stay_strategy & MOB_WALK) { m->locx=m->headx; m->locy=m->heady; mob_check(i,m); if (m->locx<64 || m->locx>192) m->locx=128; if (m->locy<64 || m->locy>192) m->locy=128; if (m->locx==m->headx && m->locy==m->heady) rozhodni_o_smeru(m); } } } } static int mob_mob_alter(int num) { int i; num-=MOB_START; if (num<0) return 0xff; if (mobs[num].dialog>-1 && ~mobs[num].vlajky & MOB_PASSABLE) start_dialog(mobs[num].dialog,num); else if (mobs[num].stay_strategy & MOB_WATCH) { stop_mob(mobs+num); if (!battle) battle=1; } i=mob_mob_alter(mobs[num].next); return (mobs[num].vlajky & MOB_PASSABLE) & i; } int mob_alter(int sect) { char p; att_player=0xff; p=mob_mob_alter(mob_map[sect]); /* if (p) { int i;THUMAN *h; for (i=0;iused && h->lives && h->groupnum==cur_group) {att_player=group_sort[i];break;} } }*/ return p; } void regen_all_mobs() { int i; TMOB *m; for(i=0,m=mobs;ivlajky & MOB_LIVE && m->vlastnosti[VLS_HPREG]) m->lives=m->vlastnosti[VLS_MAXHIT]; } void load_enemy_to_map(int i, int sector, int dir, const TMOB *t) { mobs[i]=*t; if (~mobs[i].vlajky & MOB_MOBILE) mob_map[ sector]=i+MOB_START; if (mobs[i].palette>0)mobs[i].palette=rnd(mobs[i].palette);else mobs[i].palette=abs(mobs[i].palette); mobs[i].sector=sector; mobs[i].dir=dir; mobs[i].home_pos=sector; mobs[i].vlajky|=MOB_LIVE; char s[20]; sprintf(s,"%s.SEQ",mobs[i].mobs_name); int h = find_handle(s, NULL); int *grptr = &h; if (h == -1) { grptr = &end_ptr; def_handle(grptr[0]++,s,NULL,SR_ENEMIES); mobs[i].cislo_vzoru=*grptr-monster_block; register_mob_graphics(*grptr,mobs[i].mobs_name,mobs[i].anim_counts,ablock(grptr[0]-1)); grptr[0]+=6*16; register_mob_sounds(*grptr,mobs[i].sounds); grptr[0]+=4; sprintf(s,"%s.COL",mobs[i].mobs_name); def_handle(grptr[0],s,col_load,SR_ENEMIES); grptr[0]++; } else { mobs[i].cislo_vzoru=(h+1)-monster_block; } }