//------------------------------------------------------------------------- /* Copyright (C) 1997, 2005 - 3D Realms Entertainment This file is part of Shadow Warrior version 1.2 Shadow Warrior 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. Original Source: 1997 - Frank Maddin and Jim Norwood Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms */ //------------------------------------------------------------------------- // JPLAYER.C // Copyright (c) 1996 by Jim Norwood #include "ns.h" #include "build.h" #include "mytypes.h" #include "keys.h" #include "names2.h" #include "panel.h" #include "game.h" #include "tags.h" #include "player.h" #include "lists.h" #include "warp.h" #include "quake.h" #include "common_game.h" #include "gamecontrol.h" #include "control.h" #include "trigger.h" #include "savedef.h" #include "menus.h" #include "network.h" #include "pal.h" #include "bots.h" BEGIN_SW_NS SWBOOL WeaponOK(PLAYERp pp); #define MAXANGVEL 80 // From build.h #define CLIPMASK0 (((1L)<<16)+1L) #define CLIPMASK1 (((256L)<<16)+64L) // PLAYER QUOTES TO OTHER PLAYERS //////////////////////////////////////////////////////////// #define STARTALPHANUM 4608 // New SW font for typing in stuff, It's in ASCII order. #define ENDALPHANUM 4701 #define MINIFONT 2930 // Start of small font, it's blue for good palette swapping #define NUMPAGES 1 #define NUMOFFIRSTTIMEACTIVE 100 // You can save up to 100 strings in the message history queue char pus, pub; // Global text vars char fta_quotes[NUMOFFIRSTTIMEACTIVE][64]; int gametext(int x,int y,char *t,char s,short dabits) { short ac,newx; char centre, *oldt; centre = (x == (320>>1)); newx = 0; oldt = t; if (centre) { while (*t) { if (*t == 32) {newx+=5; t++; continue; } else ac = *t - '!' + STARTALPHANUM; if (ac < STARTALPHANUM || ac > ENDALPHANUM) break; if (*t >= '0' && *t <= '9') newx += 8; else newx += tilesiz[ac].x; t++; } t = oldt; x = (320>>1)-(newx>>1); } while (*t) { if (*t == 32) {x+=5; t++; continue; } else ac = *t - '!' + STARTALPHANUM; if (ac < STARTALPHANUM || ac > ENDALPHANUM) break; rotatesprite(x<<16,y<<16,65536L,0,ac,s,16,dabits,0,0,xdim-1,ydim-1); if (*t >= '0' && *t <= '9') x += 8; else x += tilesiz[ac].x; t++; } return x; } int minigametext(int x,int y,const char *t,char s,short dabits) { short ac,newx; char centre; const char *oldt; centre = (x == (320>>1)); newx = 0; oldt = t; if (centre) { while (*t) { if (*t == 32) {newx+=4; t++; continue; } else ac = *t - '!' + 2930; if ((ac < 2930 || ac > 3023) && *t != asc_Space) break; if (*t > asc_Space && *t < 127) { newx += tilesiz[ac].x; } else x += 4; t++; } t = oldt; x = (320>>1)-(newx>>1); } while (*t) { if (*t == 32) {x+=4; t++; continue; } else ac = *t - '!' + 2930; if ((ac < 2930 || ac > 3023) && *t != asc_Space) break; if (*t > asc_Space && *t < 127) { rotatesprite(x<<16,y<<16,65536L,0,ac,-128,17,dabits,0,0,xdim-1,ydim-1); x += tilesiz[ac].x; } else x += 4; t++; } return x; } int minitext(int x,int y,char *t,char p,char sb) { short ac; while (*t) { *t = toupper(*t); if (*t == 32) {x+=5; t++; continue; } else ac = *t - '!' + MINIFONT; rotatesprite(x<<16,y<<16,65536L,0,ac,0,p,sb,0,0,xdim-1,ydim-1); x += 4; // tilesiz[ac].x+1; t++; } return x; } int minitextshade(int x,int y,char *t,char s,char p,char sb) { short ac; while (*t) { *t = toupper(*t); if (*t == 32) {x+=5; t++; continue; } else ac = *t - '!' + MINIFONT; rotatesprite(x<<16,y<<16,65536L,0,ac,s,p,sb,0,0,xdim-1,ydim-1); x += 4; // tilesiz[ac].x+1; t++; } return x; } int quotebot, quotebotgoal; short user_quote_time[MAXUSERQUOTES]; char user_quote[MAXUSERQUOTES][256]; void adduserquote(const char *daquote) { int i; SetRedrawScreen(Player+myconnectindex); for (i=MAXUSERQUOTES-1; i>0; i--) { strcpy(user_quote[i],user_quote[i-1]); user_quote_time[i] = user_quote_time[i-1]; } strcpy(user_quote[0],daquote); user_quote_time[0] = 180; } void operatefta(void) { int i, j, k; j=MESSAGE_LINE; // Base line position on screen quotebot = min(quotebot,j); quotebotgoal = min(quotebotgoal,j); if (MessageInputMode) j -= 6; // Bump all lines up one to make room for new line quotebotgoal = j; j = quotebot; for (i=0; i 4) minigametext(320>>1,j,user_quote[i],0,2+8); else if (k > 2) minigametext(320>>1,j,user_quote[i],0,2+8+1); else minigametext(320>>1,j,user_quote[i],0,2+8+1+32); } else { // dont fade out minigametext(320>>1,j,user_quote[i],0,2+8); } j -= 6; } } //////////// Console Message Queue //////////////////////////////////// int conbot, conbotgoal; char con_quote[MAXCONQUOTES][256]; void addconquote(char *daquote) { int i; for (i=MAXCONQUOTES-1; i>0; i--) { strcpy(con_quote[i],con_quote[i-1]); } strcpy(con_quote[0],daquote); } #define CON_ROT_FLAGS (ROTATE_SPRITE_CORNER|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK) void operateconfta(void) { int i, j, k; if (!ConPanel) return; // If panel isn't up, don't draw anything // Draw the background console pic rotatesprite((0)<<16,(0)<<16,65536L,0,5119,0,0,CON_ROT_FLAGS,0,0,xdim-1,ydim-1); j=99; // Base line position on screen conbot = min(conbot,j); conbotgoal = min(conbotgoal,j); if (ConInputMode) j -= 6; // Bump all lines up one to make room for new line conbotgoal = j; j = conbot; for (i=0; iInventoryNum == targetitem) syn->bits |= (1<bits |= (1<bits |= (1<WeaponNum == WPN_MICRO && p->WpnRocketNuke && p->WpnRocketType != 2) { syn->bits ^= 15; syn->bits |= 4; } else for (weap=9; weap>=0; weap--) { if (weap <= u->WeaponNum) break; if (TEST(p->WpnFlags, BIT(weap)) && p->WpnAmmo[weap] > DamageData[weap].min_ammo) { syn->bits ^= 15; syn->bits |= weap; break; } } } int getspritescore(int snum, int dapicnum) { switch (dapicnum) { case ICON_STAR: return 5; case ICON_UZI: return 20; case ICON_UZIFLOOR: return 20; case ICON_LG_UZI_AMMO: return 15; case ICON_HEART: return 160; case ICON_HEART_LG_AMMO: return 60; case ICON_GUARD_HEAD: return 170; case ICON_FIREBALL_LG_AMMO: return 70; case ICON_ROCKET: return 100; case ICON_SHOTGUN: return 130; case ICON_LG_ROCKET: return 100; case ICON_LG_SHOTSHELL: return 30; case ICON_MICRO_GUN: return 200; case ICON_MICRO_BATTERY: return 100; case ICON_GRENADE_LAUNCHER: return 150; case ICON_LG_GRENADE: return 50; case ICON_LG_MINE: return 150; case ICON_RAIL_GUN: return 180; case ICON_RAIL_AMMO: return 80; case ST_QUICK_EXIT: case ST_QUICK_SCAN: case ICON_MEDKIT: case ICON_CHEMBOMB: case ICON_FLASHBOMB: case ICON_NUKE: case ICON_CALTROPS: case TRACK_SPRITE: case ST1: case ST2: case ST_QUICK_JUMP: case ST_QUICK_JUMP_DOWN: case ST_QUICK_SUPER_JUMP: return 120; break; // Commented out for now, example. // case FREEZEAMMO: if (ps[snum].ammo_amount[FREEZE_WEAPON] < max_ammo_amount[FREEZE_WEAPON]) return(10); else return(0); } return 0; } static int fdmatrix[13][13] = { //SWRD SHUR UZI SHOT RPG 40MM MINE RAIL HEAD HEAD2HEAD3HEART { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, //SWRD {1024, 512, 128, 128,2560, 128,2560, 128,2560,2560,2560, 128, 128}, //SHUR {2560,1024, 512, 512,2560, 128,2560,2560,1024,2560,2560,2560,2560}, //UZI { 512, 512, 512, 512,2560, 128,2560, 512, 512, 512, 512, 512, 512}, //SHOT {2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560}, //RPG { 512, 512, 512, 512,2048, 512,2560,2560, 512,2560,2560,2560,2560}, //40MM { 128, 128, 128, 128, 512, 128, 128, 128, 128, 128, 128, 128, 128}, //MINE {1536,1536,1536,1536,2560,1536,1536,1536,1536,1536,1536,1536,1536}, //RAIL {2560,1024, 512,1024,1024,1024,2560, 512,1024,2560,2560, 512, 512}, //HEAD1 { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, //HEAD2 { 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}, //HEAD3 {1024, 512, 128, 128,2560, 512,2560,1024, 128,2560,1024,1024,1024}, //HEART }; static int goalx[MAX_SW_PLAYERS_REG], goaly[MAX_SW_PLAYERS_REG], goalz[MAX_SW_PLAYERS_REG]; static int goalsect[MAX_SW_PLAYERS_REG], goalwall[MAX_SW_PLAYERS_REG], goalsprite[MAX_SW_PLAYERS_REG]; static int goalplayer[MAX_SW_PLAYERS_REG], clipmovecount[MAX_SW_PLAYERS_REG]; short searchsect[MAXSECTORS], searchparent[MAXSECTORS]; char dashow2dsector[(MAXSECTORS+7)>>3]; void computergetinput(int snum, SW_PACKET *syn) { int i, j, k, l, x1, y1, z1, x2, y2, z2, dx, dy, nextj; int dist, daang, zang, fightdist, damyang, damysect; int startsect, endsect, splc, send, startwall, endwall; hitdata_t hitinfo; PLAYERp p; walltype *wal; int myx, myy, myz, myang, mycursectnum; USERp u; short weap; //extern SWBOOL Pachinko_Win_Cheat; if (!MoveSkip4) return; // Make it so the bots don't slow the game down so bad! p = &Player[snum]; u = User[p->PlayerSprite]; // Set user struct // Copy current weapon number to player struct p->WpnNum = u->WeaponNum; if (p->WpnNum >= MAX_WEAPONS) p->WpnNum = MAX_WEAPONS-1; // Init local position variables myx = p->posx; myy = p->posy; myz = p->posz; myang = p->pang; mycursectnum = p->cursectnum; // Reset input bits syn->vel = 0; syn->svel = 0; syn->angvel = 0; syn->aimvel = 0; syn->bits = 0; x1 = p->posx; y1 = p->posy; z1 = p->posz; damyang = p->pang; damysect = sprite[p->PlayerSprite].sectnum; if ((numplayers >= 2) && (snum == myconnectindex)) { x1 = myx; y1 = myy; z1 = myz+PLAYER_HEIGHT; damyang = myang; damysect = mycursectnum; } // Always operate everything syn->bits |= (1< 800) goalplayer[snum] = snum; else { x2 = Player[goalplayer[snum]].posx; y2 = Player[goalplayer[snum]].posy; z2 = Player[goalplayer[snum]].posz; if (!FAFcansee(x1,y1,z1-(48<<8),damysect,x2,y2,z2-(48<<8),sprite[Player[goalplayer[snum]].PlayerSprite].sectnum)) goalplayer[snum] = snum; } // Pick a new target player if goal is dead or target is itself if (goalplayer[snum] == snum) { j = 0x7fffffff; for (i=connecthead; i>=0; i=connectpoint2[i]) if (i != snum) { if (TEST(Player[i].Flags, PF_DEAD)) continue; x2 = Player[i].posx; y2 = Player[i].posy; z2 = Player[i].posz; if (!FAFcansee(x1,y1,z1-(48<<8),damysect,x2,y2,z2-(48<<8),sprite[Player[i].PlayerSprite].sectnum)) continue; dist = ksqrt((sprite[Player[i].PlayerSprite].x-x1)*(sprite[Player[i].PlayerSprite].x-x1)+(sprite[Player[i].PlayerSprite].y-y1)*(sprite[Player[i].PlayerSprite].y-y1)); if (dist < j) { j = dist; goalplayer[snum] = i; } } } // Pick a weapon BOT_ChooseWeapon(p, u, syn); // x2,y2,z2 is the coordinates of the target sprite x2 = Player[goalplayer[snum]].posx; y2 = Player[goalplayer[snum]].posy; z2 = Player[goalplayer[snum]].posz; // If bot is dead, either barf or respawn if (TEST(p->Flags, PF_DEAD)) { if (STD_RANDOM_RANGE(1000) > 990) { syn->bits |= (1<bits |= (1<Health < p->MaxHealth) BOT_UseInventory(p, INVENTORY_MEDKIT, syn); // Check the missile stat lists to see what's being fired and // take the appropriate action TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISSILE], j, nextj) { switch (sprite[j].picnum) { case FIREBALL: k = 0; break; case BOLT_THINMAN_R0: k = 0; syn->bits |= (1<>4,(hitinfo.pos.z-z1)>>4) < 3072) { dx = sintable[(sprite[j].ang+512)&2047]; dy = sintable[sprite[j].ang&2047]; if ((x1-hitinfo.pos.x)*dy > (y1-hitinfo.pos.y)*dx) i = -k*512; else i = k*512; syn->vel -= mulscale17(dy,i); syn->svel += mulscale17(dx,i); } if (l < 7) { hitinfo.pos.x += (mulscale14(sprite[j].xvel,sintable[(sprite[j].ang+512)&2047])<<2); hitinfo.pos.y += (mulscale14(sprite[j].xvel,sintable[sprite[j].ang&2047])<<2); hitinfo.pos.z += (sprite[j].zvel<<2); } else { hitscan((vec3_t *)&sprite[j],sprite[j].sectnum, mulscale14(sprite[j].xvel,sintable[(sprite[j].ang+512)&2047]), mulscale14(sprite[j].xvel,sintable[sprite[j].ang&2047]), (int)sprite[j].zvel, &hitinfo,CLIPMASK1); } } } } if (!TEST(Player[goalplayer[snum]].Flags, PF_DEAD) && snum != goalplayer[snum] && ((FAFcansee(x1,y1,z1-(24<<8),damysect,x2,y2,z2-(24<<8),sprite[Player[goalplayer[snum]].PlayerSprite].sectnum)) || (FAFcansee(x1,y1,z1-(48<<8),damysect,x2,y2,z2-(48<<8),sprite[Player[goalplayer[snum]].PlayerSprite].sectnum)))) { // Shoot how often by skill level short shootrnd=0; shootrnd = STD_RANDOM_RANGE(1000); if ((Skill == 0 && shootrnd > 990) || (Skill == 1 && shootrnd > 550) || (Skill == 2 && shootrnd > 350) || (Skill == 3)) syn->bits |= (1<bits &= ~(1< 252) syn->bits |= (1<WpnNum < MAX_WEAPONS); //ASSERT(Player[goalplayer[snum]].WpnNum < MAX_WEAPONS); // Only fire explosive type weaps if you are not too close to the target! if (u->WeaponNum == WPN_MICRO || u->WeaponNum == WPN_GRENADE || u->WeaponNum == WPN_RAIL) { vec3_t hit_pos = { x1, y1, z1-PLAYER_HEIGHT }; hitscan(&hit_pos,damysect,sintable[(damyang+512)&2047],sintable[damyang&2047], (100-p->horiz-p->horizoff)*32,&hitinfo,CLIPMASK1); if ((hitinfo.pos.x-x1)*(hitinfo.pos.x-x1)+(hitinfo.pos.y-y1)*(hitinfo.pos.y-y1) < 2560*2560) syn->bits &= ~(1<WpnNum][Player[goalplayer[snum]].WpnNum]; if (fightdist < 128) fightdist = 128; // Figure out your distance from the enemy target sprite dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (dist == 0) dist = 1; daang = NORM_ANGLE(getangle(x2+(Player[goalplayer[snum]].xvect>>14)-x1,y2+(Player[goalplayer[snum]].yvect>>14)-y1)); zang = 100-((z2-z1)*8)/dist; fightdist = max(fightdist,(klabs(z2-z1)>>4)); hitinfo.pos.x = x2+((x1-x2)*fightdist/dist); hitinfo.pos.y = y2+((y1-y2)*fightdist/dist); syn->vel += (hitinfo.pos.x-x1)*2047/dist; syn->svel += (hitinfo.pos.y-y1)*2047/dist; //Strafe attack if (fightdist) { j = (int32_t) totalclock+snum*13468; i = sintable[(j<<6)&2047]; i += sintable[((j+4245)<<5)&2047]; i += sintable[((j+6745)<<4)&2047]; i += sintable[((j+15685)<<3)&2047]; dx = sintable[(sprite[Player[goalplayer[snum]].PlayerSprite].ang+512)&2047]; dy = sintable[sprite[Player[goalplayer[snum]].PlayerSprite].ang&2047]; if ((x1-x2)*dy > (y1-y2)*dx) i += 8192; else i -= 8192; syn->vel += ((sintable[(daang+1024)&2047]*i)>>17); syn->svel += ((sintable[(daang+512)&2047]*i)>>17); } // Make aiming and running speed suck by skill level if (Skill == 0) { daang = NORM_ANGLE((daang-256) + STD_RANDOM_RANGE(512)); syn->vel -= syn->vel/2; syn->svel -= syn->svel/2; } else if (Skill == 1) { daang = NORM_ANGLE((daang-128) + STD_RANDOM_RANGE(256)); syn->vel -= syn->vel/8; syn->svel -= syn->svel/8; } else if (Skill == 2) daang = NORM_ANGLE((daang-64) + STD_RANDOM_RANGE(128)); // Below formula fails in certain cases //syn->angvel = min(max((((daang+1024-damyang)&2047)-1024)>>1,-MAXANGVEL),MAXANGVEL); //was 127 p->pang = daang; syn->aimvel = min(max((zang-p->horiz)>>1,-PLAYER_HORIZ_MAX),PLAYER_HORIZ_MAX); // Sets type of aiming, auto aim for bots syn->bits |= (1<PlayerSprite].sectnum; endsect = sprite[Player[goalplayer[snum]].PlayerSprite].sectnum; clearbufbyte(dashow2dsector,(MAXSECTORS+7)>>3,0L); searchsect[0] = startsect; searchparent[0] = -1; dashow2dsector[startsect>>3] |= (1<<(startsect&7)); for (splc=0,send=1; splcnextsector; if (j < 0) continue; dx = ((wall[wal->point2].x+wal->x)>>1); dy = ((wall[wal->point2].y+wal->y)>>1); if ((getceilzofslope(j,dx,dy) > getflorzofslope(j,dx,dy)-(28<<8)) && ((sector[j].lotag < 15) || (sector[j].lotag > 22))) continue; if (getflorzofslope(j,dx,dy) < getflorzofslope(searchsect[splc],dx,dy)-(72<<8)) continue; if ((dashow2dsector[j>>3]&(1<<(j&7))) == 0) { dashow2dsector[j>>3] |= (1<<(j&7)); searchsect[send] = (short)j; searchparent[send] = (short)splc; send++; if (j == endsect) { clearbufbyte(dashow2dsector,(MAXSECTORS+7)>>3,0L); for (k=send-1; k>=0; k=searchparent[k]) dashow2dsector[searchsect[k]>>3] |= (1<<(searchsect[k]&7)); for (k=send-1; k>=0; k=searchparent[k]) if (!searchparent[k]) break; goalsect[snum] = searchsect[k]; startwall = sector[goalsect[snum]].wallptr; endwall = startwall+sector[goalsect[snum]].wallnum; hitinfo.pos.x = hitinfo.pos.y = 0; for (i=startwall; i= dy*(x2-wall[i].x)) if ((hitinfo.pos.x-x1)*(wall[i].y-y1) <= (hitinfo.pos.y-y1)*(wall[i].x-x1)) if ((hitinfo.pos.x-x1)*(wall[wall[i].point2].y-y1) >= (hitinfo.pos.y-y1)*(wall[wall[i].point2].x-x1)) { k = i; break; } dist = ksqrt(dx*dx+dy*dy); if (dist > l) { l = dist; k = i; } } goalwall[snum] = k; daang = ((getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y)+1536)&2047); goalx[snum] = ((wall[k].x+wall[wall[k].point2].x)>>1)+(sintable[(daang+512)&2047]>>8); goaly[snum] = ((wall[k].y+wall[wall[k].point2].y)>>1)+(sintable[daang&2047]>>8); goalz[snum] = sector[goalsect[snum]].floorz-(32<<8); break; } } } #if 0 for (i=headspritesect[searchsect[splc]]; i>=0; i=nextspritesect[i]) if (sprite[i].lotag == 7) { j = sprite[sprite[i].owner].sectnum; if ((dashow2dsector[j>>3]&(1<<(j&7))) == 0) { dashow2dsector[j>>3] |= (1<<(j&7)); searchsect[send] = (short)j; searchparent[send] = (short)splc; send++; if (j == endsect) { clearbufbyte(dashow2dsector,(MAXSECTORS+7)>>3,0L); for (k=send-1; k>=0; k=searchparent[k]) dashow2dsector[searchsect[k]>>3] |= (1<<(searchsect[k]&7)); for (k=send-1; k>=0; k=searchparent[k]) if (!searchparent[k]) break; goalsect[snum] = searchsect[k]; startwall = sector[startsect].wallptr; endwall = startwall+sector[startsect].wallnum; l = 0; k = startwall; for (i=startwall; i l)) { l = dist; k = i; } } goalwall[snum] = k; daang = ((getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y)+1536)&2047); goalx[snum] = ((wall[k].x+wall[wall[k].point2].x)>>1)+(sintable[(daang+512)&2047]>>8); goaly[snum] = ((wall[k].y+wall[wall[k].point2].y)>>1)+(sintable[daang&2047]>>8); goalz[snum] = sector[goalsect[snum]].floorz-(32<<8); break; } } } if (goalwall[snum] >= 0) break; #endif } } if ((goalsect[snum] < 0) || (goalwall[snum] < 0)) { if (goalsprite[snum] < 0) { for (k=0; k<4; k++) { i = (rand()%numsectors); for (j=headspritesect[i]; j>=0; j=nextspritesect[j]) { if ((sprite[j].xrepeat <= 0) || (sprite[j].yrepeat <= 0)) continue; if (getspritescore(snum,sprite[j].picnum) <= 0) continue; if (FAFcansee(x1,y1,z1-(32<<8),damysect,sprite[j].x,sprite[j].y,sprite[j].z-(4<<8),i)) { goalx[snum] = sprite[j].x; goaly[snum] = sprite[j].y; goalz[snum] = sprite[j].z; goalsprite[snum] = j; break; } } } } x2 = goalx[snum]; y2 = goaly[snum]; dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (!dist) return; daang = getangle(x2-x1,y2-y1); syn->vel += (x2-x1)*2047/dist; syn->svel += (y2-y1)*2047/dist; syn->angvel = min(max((((daang+1024-damyang)&2047)-1024)>>3,-MAXANGVEL),MAXANGVEL); } else goalsprite[snum] = -1; #endif hitinfo.pos.x = p->posx; hitinfo.pos.y = p->posy; hitinfo.pos.z = p->posz; hitinfo.sect = p->cursectnum; i = clipmove(&hitinfo.pos,&hitinfo.sect,p->xvect,p->yvect,164L,4L<<8,4L<<8,CLIPMASK0); if (!i) { hitinfo.pos.x = p->posx; hitinfo.pos.y = p->posy; hitinfo.pos.z = p->posz+(24<<8); hitinfo.sect = p->cursectnum; i = clipmove(&hitinfo.pos,&hitinfo.sect,p->xvect,p->yvect,164L,4L<<8,4L<<8,CLIPMASK0); } if (i) { clipmovecount[snum]++; j = 0; if ((i&0xc000) == 32768) //Hit a wall (49152 for sprite) if (wall[i&(MAXWALLS-1)].nextsector >= 0) { if (getflorzofslope(wall[i&(MAXWALLS-1)].nextsector,p->posx,p->posy) <= p->posz+(24<<8)) j |= 1; if (getceilzofslope(wall[i&(MAXWALLS-1)].nextsector,p->posx,p->posy) >= p->posz-(24<<8)) j |= 2; } if ((i&0xc000) == 49152) j = 1; // Jump if (j&1) if (clipmovecount[snum] == 4) syn->bits |= (1<bits |= (1<vel += ((sintable[(daang+1024)&2047]*i)>>17); syn->svel += ((sintable[(daang+512)&2047]*i)>>17); // Try to Open if ((clipmovecount[snum]&31) == 2) syn->bits |= (1<bits |= (1<<22); if (clipmovecount[snum] > 32) { goalsect[snum] = -1; goalwall[snum] = -1; clipmovecount[snum] = 0; } goalsprite[snum] = -1; } else clipmovecount[snum] = 0; if ((goalsect[snum] >= 0) && (goalwall[snum] >= 0)) { x2 = goalx[snum]; y2 = goaly[snum]; dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (!dist) return; daang = getangle(x2-x1,y2-y1); if ((goalwall[snum] >= 0) && (dist < 4096)) daang = ((getangle(wall[wall[goalwall[snum]].point2].x-wall[goalwall[snum]].x,wall[wall[goalwall[snum]].point2].y-wall[goalwall[snum]].y)+1536)&2047); syn->vel += (x2-x1)*2047/dist; syn->svel += (y2-y1)*2047/dist; syn->angvel = min(max((((daang+1024-damyang)&2047)-1024)>>3,-MAXANGVEL),MAXANGVEL); } /* // Use extended bot logic for navigation through level goalsect[snum] = -1; goalwall[snum] = -1; goalsprite[snum] = -1; // Go to a goal place if ((goalsect[snum] >= 0) && (goalwall[snum] >= 0)) { x2 = goalx[snum]; y2 = goaly[snum]; dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (!dist) return; daang = getangle(x2-x1,y2-y1); if ((goalwall[snum] >= 0) && (dist < 4096)) daang = ((getangle(wall[wall[goalwall[snum]].point2].x-wall[goalwall[snum]].x,wall[wall[goalwall[snum]].point2].y-wall[goalwall[snum]].y)+1536)&2047); syn->vel += (x2-x1)*2047/dist; syn->svel += (y2-y1)*2047/dist; syn->angvel = min(max((((daang+1024-damyang)&2047)-1024)>>3,-MAXANGVEL),MAXANGVEL); } */ } END_SW_NS