📄 mob.c
字号:
// $Id: mob.c,v 1.14 2003/06/30 14:45:10 lemit Exp $
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "timer.h"
#include "socket.h"
#include "db.h"
#include "map.h"
#include "clif.h"
#include "intif.h"
#include "pc.h"
#include "mob.h"
#include "guild.h"
#include "itemdb.h"
#include "skill.h"
#include "battle.h"
#include "party.h"
#include "npc.h"
#ifdef MEMWATCH
#include "memwatch.h"
#endif
#define MIN_MOBTHINKTIME 100
#define MOB_LAZYMOVEPERC 50 // 庤敳偒儌乕僪MOB偺堏摦妋棪乮愮暘棪乯
#define MOB_LAZYWARPPERC 20 // 庤敳偒儌乕僪MOB偺儚乕僾妋棪乮愮暘棪乯
struct mob_db mob_db[2001];
/*==========================================
* 儘乕僇儖僾儘僩僞僀僾愰尵 (昁梫側暔偺傒)
*------------------------------------------
*/
static int distance(int,int,int,int);
static int mob_makedummymobdb(int);
static int mob_timer(int,unsigned int,int,int);
int mobskill_use(struct mob_data *md,unsigned int tick,int event);
int mobskill_deltimer(struct mob_data *md );
int mob_skillid2skillidx(int class,int skillid);
int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx);
/*==========================================
* mob傪柤慜偱専嶕
*------------------------------------------
*/
int mobdb_searchname(const char *str)
{
int i;
for(i=0;i<sizeof(mob_db)/sizeof(mob_db[0]);i++){
if( strcmpi(mob_db[i].name,str)==0 || strcmp(mob_db[i].jname,str)==0 ||
memcmp(mob_db[i].name,str,24)==0 || memcmp(mob_db[i].jname,str,24)==0)
return i;
}
return 0;
}
/*==========================================
* MOB弌尰梡偺嵟掅尷偺僨乕僞僙僢僩
*------------------------------------------
*/
int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class)
{
md->bl.prev=NULL;
md->bl.next=NULL;
if(strcmp(mobname,"--en--")==0)
memcpy(md->name,mob_db[class].name,24);
else if(strcmp(mobname,"--ja--")==0)
memcpy(md->name,mob_db[class].jname,24);
else
memcpy(md->name,mobname,24);
md->n = 0;
md->base_class = md->class = class;
md->bl.id= npc_get_new_npc_id();
memset(&md->state,0,sizeof(md->state));
md->timer = -1;
md->target_id=0;
md->attacked_id=0;
md->speed=mob_db[class].speed;
return 0;
}
/*==========================================
* 堦敪MOB弌尰(僗僋儕僾僩梡)
*------------------------------------------
*/
int mob_once_spawn(struct map_session_data *sd,char *mapname,
int x,int y,const char *mobname,int class,int amount,const char *event)
{
struct mob_data *md=NULL;
int m,count,lv=255;
if( sd )
lv=sd->status.base_level;
if(strcmp(mapname,"this")==0)
m=sd->bl.m;
else
m=map_mapname2mapid(mapname);
if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>2000) // 抣偑堎忢側傜彚姭傪巭傔傞
return 0;
if(class<0){ // 儔儞僟儉偵彚姭
int i=0;
int j=-class-1;
int k;
if(j>=0 && j<MAX_RANDOMMONSTER){
do{
class=rand()%1000+1001;
k=rand()%1000000;
}while((mob_db[class].max_hp <= 0 || mob_db[class].summonper[j] <= k ||
(lv<mob_db[class].lv && battle_config.random_monster_checklv)) && (i++) < 2000);
if(i>=2000){
class=mob_db[0].summonper[j];
}
}else{
return 0;
}
// if(battle_config.etc_log)
// printf("mobclass=%d try=%d\n",class,i);
}
if(sd){
if(x<=0) x=sd->bl.x;
if(y<=0) y=sd->bl.y;
}else if(x<=0 || y<=0){
printf("mob_once_spawn: ??\n");
}
for(count=0;count<amount;count++){
md=calloc(sizeof(struct mob_data), 1);
if(md==NULL){
printf("mob_once_spawn: out of memory !\n");
exit(1);
}
memset(md, '\0', sizeof *md);
if(mob_db[class].mode&0x02) {
md->lootitem=calloc(sizeof(struct item)*LOOTITEM_SIZE, 1);
if(md->lootitem==NULL){
printf("mob_once_spawn: out of memory !\n");
exit(1);
}
}
else
md->lootitem=NULL;
mob_spawn_dataset(md,mobname,class);
md->bl.m=m;
md->bl.x=x;
md->bl.y=y;
md->m =m;
md->x0=x;
md->y0=y;
md->xs=0;
md->ys=0;
md->spawndelay1=-1; // 堦搙偺傒僼儔僌
md->spawndelay2=-1; // 堦搙偺傒僼儔僌
memcpy(md->npc_event,event,sizeof(md->npc_event));
md->bl.type=BL_MOB;
map_addiddb(&md->bl);
mob_spawn(md->bl.id);
}
return (amount>0)?md->bl.id:0;
}
/*==========================================
* 堦敪MOB弌尰(僗僋儕僾僩梡仌僄儕傾巜掕)
*------------------------------------------
*/
int mob_once_spawn_area(struct map_session_data *sd,char *mapname,
int x0,int y0,int x1,int y1,
const char *mobname,int class,int amount,const char *event)
{
int x,y,i,c,max,lx=-1,ly=-1,id=0;
int m=map_mapname2mapid(mapname);
max=(y1-y0+1)*(x1-x0+1)*3;
if(max>1000)max=1000;
if(m<0 || amount<=0 || (class>=0 && class<=1000) || class>2000) // 抣偑堎忢側傜彚姭傪巭傔傞
return 0;
for(i=0;i<amount;i++){
int j=0;
do{
x=rand()%(x1-x0+1)+x0;
y=rand()%(y1-y0+1)+y0;
}while( ( (c=map_getcell(m,x,y))==1 || c==5)&& (++j)<max );
if(j>=max){
if(lx>=0){ // 専嶕偵幐攕偟偨偺偱埲慜偵暒偄偨応強傪巊偆
x=lx;
y=ly;
}else
return 0; // 嵟弶偵暒偔応強偺専嶕傪幐攕偟偨偺偱傗傔傞
}
id=mob_once_spawn(sd,mapname,x,y,mobname,class,1,event);
lx=x;
ly=y;
}
return id;
}
/*==========================================
* mob偵僞僎柍帇ID傪晅壛
*------------------------------------------
*/
int mob_exclusion_add(struct mob_data *md,int type,int id)
{
if(md){
if(type==1)
md->exclusion_src=id;
if(type==2)
md->exclusion_party=id;
if(type==3)
md->exclusion_guild=id;
}
return 0;
}
/*==========================================
* mob偺僞僎柍帇ID傪僠僃僢僋
*------------------------------------------
*/
int mob_exclusion_check(struct mob_data *md,struct map_session_data *sd)
{
if(md && sd && sd->bl.type==BL_PC){
if(md->exclusion_src && md->exclusion_src==sd->bl.id)
return 1;
if(md->exclusion_party && md->exclusion_party==sd->status.party_id)
return 2;
if(md->exclusion_guild && md->exclusion_guild==sd->status.guild_id)
return 3;
}
return 0;
}
/*==========================================
* mob偺尒偐偗強摼
*------------------------------------------
*/
int mob_get_viewclass(int class)
{
return mob_db[class].view_class;
}
int mob_get_sex(int class)
{
return mob_db[class].sex;
}
short mob_get_hair(int class)
{
return mob_db[class].hair;
}
short mob_get_hair_color(int class)
{
return mob_db[class].hair_color;
}
short mob_get_weapon(int class)
{
return mob_db[class].weapon;
}
short mob_get_shield(int class)
{
return mob_db[class].shield;
}
short mob_get_head_top(int class)
{
return mob_db[class].head_top;
}
short mob_get_head_mid(int class)
{
return mob_db[class].head_mid;
}
short mob_get_head_buttom(int class)
{
return mob_db[class].head_buttom;
}
/*==========================================
* MOB偑尰嵼堏摦壜擻側忬懺偵偁傞偐偳偆偐
*------------------------------------------
*/
int mob_can_move(struct mob_data *md)
{
if(md->canmove_tick > gettick() || (md->opt1 > 0 && md->opt1 != 6) || md->option&2)
return 0;
if( md->sc_data[SC_ANKLE].timer != -1 || md->sc_data[SC_AUTOCOUNTER].timer != -1 || md->sc_data[SC_BLADESTOP].timer != -1) // 傾儞僋儖拞偱摦偗側偄
return 0;
return 1;
}
/*==========================================
* mob偺師偺1曕偵偐偐傞帪娫寁嶼
*------------------------------------------
*/
static int calc_next_walk_step(struct mob_data *md)
{
if(md->walkpath.path_pos>=md->walkpath.path_len)
return -1;
if(md->walkpath.path[md->walkpath.path_pos]&1)
return battle_get_speed(&md->bl)*14/10;
return battle_get_speed(&md->bl);
}
static int mob_walktoxy_sub(struct mob_data *md);
/*==========================================
* mob曕峴張棟
*------------------------------------------
*/
static int mob_walk(struct mob_data *md,unsigned int tick,int data)
{
int moveblock;
int i,ctype;
static int dirx[8]={0,-1,-1,-1,0,1,1,1};
static int diry[8]={1,1,0,-1,-1,-1,0,1};
int x,y,dx,dy;
md->state.state=MS_IDLE;
if(md->walkpath.path_pos>=md->walkpath.path_len || md->walkpath.path_pos!=data)
return 0;
md->walkpath.path_half ^= 1;
if(md->walkpath.path_half==0){
md->walkpath.path_pos++;
if(md->state.change_walk_target){
mob_walktoxy_sub(md);
return 0;
}
}
else {
if(md->walkpath.path[md->walkpath.path_pos]>=8)
return 1;
x = md->bl.x;
y = md->bl.y;
ctype = map_getcell(md->bl.m,x,y);
if(ctype == 1 || ctype == 5) {
mob_stop_walking(md,1);
return 0;
}
md->dir=md->walkpath.path[md->walkpath.path_pos];
dx = dirx[md->dir];
dy = diry[md->dir];
ctype = map_getcell(md->bl.m,x+dx,y+dy);
if(ctype == 1 || ctype == 5) {
mob_walktoxy_sub(md);
return 0;
}
moveblock = ( x/BLOCK_SIZE != (x+dx)/BLOCK_SIZE || y/BLOCK_SIZE != (y+dy)/BLOCK_SIZE);
md->state.state=MS_WALK;
map_foreachinmovearea(clif_moboutsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
x += dx;
y += dy;
if(md->min_chase>13)
md->min_chase--;
if(moveblock) map_delblock(&md->bl);
md->bl.x = x;
md->bl.y = y;
if(moveblock) map_addblock(&md->bl);
map_foreachinmovearea(clif_mobinsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,md);
md->state.state=MS_IDLE;
if(md->option&4)
skill_check_cloaking(&md->bl);
skill_unit_move(&md->bl,tick,1); // 僗僉儖儐僯僢僩偺専嵏
}
if((i=calc_next_walk_step(md))>0){
i = i>>1;
if(i < 1 && md->walkpath.path_half == 0)
i = 1;
md->timer=add_timer(tick+i,mob_timer,md->bl.id,md->walkpath.path_pos);
md->state.state=MS_WALK;
if(md->walkpath.path_pos>=md->walkpath.path_len)
clif_fixmobpos(md); // 偲傑偭偨偲偒偵埵抲偺嵞憲怣
}
return 0;
}
/*==========================================
* mob偺峌寕張棟
*------------------------------------------
*/
static int mob_attack(struct mob_data *md,unsigned int tick,int data)
{
struct map_session_data *sd;
int mode,race,range;
md->min_chase=13;
md->state.state=MS_IDLE;
md->state.skillstate=MSS_IDLE;
if( md->skilltimer!=-1 ) // 僗僉儖巊梡拞
return 0;
if(md->opt1>0 || md->option&2)
return 0;
if(md->sc_data[SC_AUTOCOUNTER].timer != -1)
return 0;
if(md->sc_data[SC_BLADESTOP].timer != -1)
return 0;
sd=map_id2sd(md->target_id);
if(sd==NULL || pc_isdead(sd) || md->bl.m != sd->bl.m || sd->bl.prev == NULL || sd->invincible_timer != -1 ||
distance(md->bl.x,md->bl.y,sd->bl.x,sd->bl.y)>=13 || pc_isinvisible(sd) || mob_exclusion_check(md,sd)){
md->target_id=0;
md->state.targettype = NONE_ATTACKABLE;
return 0;
}
mode=mob_db[md->class].mode;
race=mob_db[md->class].race;
if(!(mode&0x20) && (sd->sc_data[SC_TRICKDEAD].timer != -1 ||
((pc_ishiding(sd) || sd->state.gangsterparadise) && race!=4 && race!=6) ) ) {
md->target_id=0;
md->state.targettype = NONE_ATTACKABLE;
return 0;
}
range = mob_db[md->class].range;
if(mode&1)
range++;
if(distance(md->bl.x,md->bl.y,sd->bl.x,sd->bl.y) > range)
return 0;
if(battle_config.monster_attack_direction_change)
md->dir=map_calc_dir(&md->bl, sd->bl.x,sd->bl.y ); // 岦偒愝掕
clif_fixmobpos(md);
md->state.skillstate=MSS_ATTACK;
if( mobskill_use(md,tick,-2) ) // 僗僉儖巊梡
return 0;
battle_weapon_attack(&md->bl,&sd->bl,tick,0);
if(!(battle_config.monster_cloak_check_type&2) && md->sc_data[SC_CLOAKING].timer != -1)
skill_status_change_end(&md->bl,SC_CLOAKING,-1);
md->attackabletime = tick + battle_get_adelay(&md->bl);
md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
md->state.state=MS_ATTACK;
return 0;
}
/*==========================================
* id傪峌寕偟偰偄傞PC偺峌寕傪掆巭
* clif_foreachclient偺callback娭悢
*------------------------------------------
*/
int mob_stopattacked(struct map_session_data *sd,va_list ap)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -