/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "share.h" #include "zapper.h" #include "../movie.h" ZAPPER ZD[2]; static void ZapperFrapper(int w, uint8 *bg, uint8 *spr, uint32 linets, int final) { int xs,xe; int zx,zy; if(!bg) // New line, so reset stuff. { ZD[w].zappo=0; return; } xs=ZD[w].zappo; xe=final; zx=ZD[w].mzx; zy=ZD[w].mzy; if(xe>256) xe=256; if(scanline>=(zy-4) && scanline<=(zy+4)) { while(xs=(zx-4)) { a1=bg[xs]; if(spr) { a2=spr[xs]; if(!(a2&0x80)) if(!(a2&0x40) || (a1&64)) a1=a2; } a1&=63; sum=palo[a1].r+palo[a1].g+palo[a1].b; if(sum>=100*3) { ZD[w].zaphit=((uint64)linets+(xs+16)*(PAL?15:16))/48+timestampbase; goto endo; } } xs++; } } endo: ZD[w].zappo=final; //if this was a miss, clear out the hit if(ZD[w].mzb&2) ZD[w].zaphit=0; } static INLINE int CheckColor(int w) { FCEUPPU_LineUpdate(); if(newppu) { int x = (int)ZD[w].mzx; int y = (int)ZD[w].mzy; int b = (int)ZD[w].mzb; bool block = (b&2)!=0; int mousetime = y*256+x; int nowtime = scanline*256 + g_rasterpos; if(!block && mousetime < nowtime && mousetime >= nowtime - 384) { extern uint8 *XBuf; uint8 *pix = XBuf+(ZD[w].mzy<<8); uint8 a1 = pix[ZD[w].mzx]; a1&=63; uint32 sum=palo[a1].r+palo[a1].g+palo[a1].b; //return ZD[w].zaphit = sum != 0; ZD[w].zaphit = (sum>=100*3)?1:0; } else { ZD[w].zaphit = 0; } return ZD[w].zaphit?0:1; } if((ZD[w].zaphit+100)>=(timestampbase+timestamp)) { return 0; } return 1; } static uint8 ReadZapperVS(int w) { uint8 ret=0; if(ZD[w].zap_readbit==4) ret=1; if(ZD[w].zap_readbit==7) { if(ZD[w].bogo) ret|=0x1; } if(ZD[w].zap_readbit==6) { if(!CheckColor(w)) ret|=0x1; } if(!fceuindbg) ZD[w].zap_readbit++; return ret; } static void StrobeZapperVS(int w) { ZD[w].zap_readbit=0; } static uint8 ReadZapper(int w) { uint8 ret=0; if(ZD[w].bogo) ret|=0x10; if(CheckColor(w)) ret|=0x8; return ret; } static void DrawZapper(int w, uint8 *buf, int arg) { FCEU_DrawGunSight(buf, ZD[w].mzx,ZD[w].mzy); } static void UpdateZapper(int w, void *data, int arg) { uint32 *ptr=(uint32 *)data; bool newclicked = (ptr[2]&3)!=0; bool oldclicked = (ZD[w].lastInput)!=0; if(ZD[w].bogo) { ZD[w].bogo--; } ZD[w].lastInput = ptr[2]&3; //woah.. this looks like broken bit logic. if(newclicked && !oldclicked) { ZD[w].bogo=5; ZD[w].mzb=ptr[2]; ZD[w].mzx=ptr[0]; ZD[w].mzy=ptr[1]; } } static void LogZapper(int w, MovieRecord* mr) { mr->zappers[w].x = ZD[w].mzx; mr->zappers[w].y = ZD[w].mzy; mr->zappers[w].b = ZD[w].mzb; mr->zappers[w].bogo = ZD[w].bogo; mr->zappers[w].zaphit = ZD[w].zaphit; } static void LoadZapper(int w, MovieRecord* mr) { ZD[w].mzx = mr->zappers[w].x; ZD[w].mzy = mr->zappers[w].y; ZD[w].mzb = mr->zappers[w].b; ZD[w].bogo = mr->zappers[w].bogo; ZD[w].zaphit = mr->zappers[w].zaphit; } static INPUTC ZAPC={ReadZapper,0,0,UpdateZapper,ZapperFrapper,DrawZapper,LogZapper,LoadZapper}; static INPUTC ZAPVSC={ReadZapperVS,0,StrobeZapperVS,UpdateZapper,ZapperFrapper,DrawZapper,LogZapper,LoadZapper}; INPUTC *FCEU_InitZapper(int w) { memset(&ZD[w],0,sizeof(ZAPPER)); if(GameInfo->type == GIT_VSUNI) return(&ZAPVSC); else return(&ZAPC); }