/* * Abuse - dark 2D side-scrolling platform game * Copyright (c) 1995 Crack dot Com * Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net> * * This software was released into the Public Domain. As with most public * domain software, no warranty is made or implied by Crack dot Com, by * Jonathan Clark, or by Sam Hocevar. */ #if defined HAVE_CONFIG_H # include "config.h" #endif #include "common.h" #include "items.h" #include "lisp.h" #include "dev.h" extern palette *pal; boundary::boundary(bFILE *fp, char const *er_name) : point_list(fp) { int x1,y1,x2,y2,checkx,checky,i; if (tot) { if (!(data[0]==data[(tot-1)*2] && data[1]==data[tot*2-1])) { printf("%s : Endpoints of foretile do not match start points\n",er_name); exit(0); } inside=(uint8_t *)malloc(tot); } uint8_t *point_on; for (i=0,point_on=data; i<tot-1; i++) { x1=*(point_on++); y1=*(point_on++); x2=point_on[0]; y2=point_on[1]; checkx=(x1+x2)/2; checky=(y1+y2)/2; int j,xp1,yp1,xp2,yp2,maxx,maxy,minx,miny; uint8_t *point2,segs_left=0,segs_right=0,segs_down=0; int skip_next=0; int check_left=0,check_right=0,check_down=0; if (y1==y2) check_down=1; else if (x1==x2) check_left=1; else { check_down=1; if (x1<x2) if (y1<y2) check_left=1; else check_right=1; else if (y1<y2) check_right=1; else check_left=1; } maxx=Max(x1,x2); maxy=Max(y1,y2); minx=Min(x1,x2); miny=Min(y1,y2); if (skip_next) skip_next=0; else { for (j=0,point2=data; j<tot-1; j++,point2+=2) { if (skip_next) skip_next=0; else { if (j!=i) // make sure we are not looking at ourself { xp1=point2[0]; yp1=point2[1]; xp2=point2[2]; yp2=point2[3]; if ((checkx>=xp1 && checkx<=xp2) || (checkx>=xp2 && checkx<=xp1)) { if (check_down && (yp1>miny && yp2>miny)) segs_down++; if (checkx==xp2) skip_next=1; } else if ((checky>=yp1 && checky<=yp2) || (checky>=yp2 && checky<=yp1)) { if (check_left && xp1<maxx && xp2<maxx) segs_left++; if (check_right && xp1>minx && xp2>minx) segs_right++; if (checky==yp2) skip_next=1; } } } } } if (!check_down) segs_down=1; if (!check_right) segs_right=1; if (!check_left) segs_left=1; inside[i]=!(((segs_left&1)&&(segs_right&1)&&(segs_down&1))); } } boundary::boundary(boundary *p) : point_list(p->tot,p->data) { int x1,y1,x2,y2,checkx,checky,i; uint8_t *point_on; if (tot) { inside=(uint8_t *)malloc(tot); } else inside=NULL; for (i=0,point_on=data; i<tot-1; i++) { x1=*(point_on++); y1=*(point_on++); x2=point_on[0]; y2=point_on[1]; checkx=(x1+x2)/2; checky=(y1+y2)/2; int j,xp1,yp1,xp2,yp2,maxx,maxy,minx,miny; uint8_t *point2,segs_left=0,segs_right=0,segs_down=0; int skip_next=0; int check_left=0,check_right=0,check_down=0; if (y1==y2) check_down=1; else if (x1==x2) check_right=1; else { check_down=1; if (x1<x2) if (y1<y2) check_left=1; else check_right=1; else if (y1<y2) check_right=1; else check_left=1; } maxx=Max(x1,x2); maxy=Max(y1,y2); minx=Min(x1,x2); miny=Min(y1,y2); if (skip_next) skip_next=0; else { for (j=0,point2=data; j<tot-1; j++,point2+=2) { if (skip_next) skip_next=0; else { if (j!=i) // make sure we are not looking at ourself { xp1=point2[0]; yp1=point2[1]; xp2=point2[2]; yp2=point2[3]; if ((checkx>=xp1 && checkx<=xp2) || (checkx>=xp2 && checkx<=xp1)) { if (check_down && (yp1>miny && yp2>miny)) segs_down++; if (checkx==xp2) skip_next=1; } else if ((checky>=yp1 && checky<=yp2) || (checky>=yp2 && checky<=yp1)) { if (check_left && xp1<maxx && xp2<maxx) segs_left++; if (check_right && xp1>minx && xp2>minx) segs_right++; if (checky==yp2) skip_next=1; } } } } } if (!check_down) segs_down=1; if (!check_right) segs_right=1; if (!check_left) segs_left=1; inside[i]=!(((segs_left&1)&&(segs_right&1)&&(segs_down&1))); } } backtile::backtile(bFILE *fp) { im=load_image(fp); next=fp->read_uint16(); } backtile::backtile(spec_entry *e, bFILE *fp) { im=load_image(e,fp); next=fp->read_uint16(); } foretile::foretile(bFILE *fp) { uint8_t *sl; image *img = load_image(fp); // create the micro image of the fore tile by averaging the color values // in 2×2 space and storing the closest match //uint8_t *buffer=(uint8_t *)µ_image; int x, y, w = img->Size().x, h = img->Size().y, l; int r[AUTOTILE_WIDTH * AUTOTILE_HEIGHT], g[AUTOTILE_WIDTH * AUTOTILE_HEIGHT], b[AUTOTILE_WIDTH * AUTOTILE_HEIGHT], t[AUTOTILE_WIDTH * AUTOTILE_HEIGHT]; memset(t, 0, AUTOTILE_WIDTH * AUTOTILE_HEIGHT * sizeof(int)); memset(r, 0, AUTOTILE_WIDTH * AUTOTILE_HEIGHT * sizeof(int)); memset(g, 0, AUTOTILE_WIDTH * AUTOTILE_HEIGHT * sizeof(int)); memset(b, 0, AUTOTILE_WIDTH * AUTOTILE_HEIGHT * sizeof(int)); if (!pal) { lbreak("Palette has no been defined\nuse load_palette before load_tiles"); exit(0); } if (!color_table) { lbreak("color filter has no been defined\nuse load_color_filter before load_tiles"); exit(0); } for (y=0; y<h; y++) { sl=img->scan_line(y); for (x=0; x<w; x++,sl++) { l=(y*AUTOTILE_HEIGHT/h)*AUTOTILE_WIDTH + x*AUTOTILE_WIDTH/w; r[l]+=pal->red(*sl); g[l]+=pal->green(*sl); b[l]+=pal->blue(*sl); t[l]++; } } micro_image = new image(vec2i(AUTOTILE_WIDTH, AUTOTILE_HEIGHT)); for (l=0; l<AUTOTILE_WIDTH*AUTOTILE_HEIGHT; l++) micro_image->PutPixel(vec2i(l % AUTOTILE_WIDTH, l / AUTOTILE_WIDTH), color_table->Lookup((r[l]/(t[l]*4/5))>>3, (g[l]/(t[l]*4/5))>>3, (b[l]/(t[l]*4/5))>>3)); im=new TransImage(img,"foretile"); delete img; next=fp->read_uint16(); fp->read(&damage,1); points=new boundary(fp,"foretile boundry"); } size_t figure::MemUsage() { return forward->DiskUsage() + backward->DiskUsage() + hit->size() + f_damage->size() + b_damage->size() + sizeof(figure); } figure::figure(bFILE *fp, int type) { image *im=load_image(fp); forward=new TransImage(im,"figure data"); im->FlipX(); backward=new TransImage(im,"figure backward data"); delete im; fp->read(&hit_damage,1); fp->read(&xcfg,1); xcfg=xcfg*scale_mult/scale_div; if (type==SPEC_CHARACTER) { point_list p(fp); advance=0; } else advance=fp->read_uint8(); f_damage=new boundary(fp,"fig bound"); b_damage=new boundary(f_damage); hit=new point_list(fp); } char_tint::char_tint(bFILE *fp) // se should be a palette entry { palette *p=new palette(fp); uint8_t *t=data,*p_addr=(uint8_t *)p->addr(); for (int i=0; i<256; i++,t++,p_addr+=3) *t=pal->find_closest(*p_addr,p_addr[1],p_addr[2]); delete p; }