//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2003 - 3D Realms Entertainment
Copyright (C) 2020 - Christoph Oelckers

This file is part of Duke Nukem 3D version 1.5 - Atomic Edition

Duke Nukem 3D 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
aint with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Original Source: 1996 - Todd Replogle
Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
*/
//------------------------------------------------------------------------- 

#include "ns.h"	// Must come before everything else!

#include "duke3d.h"
#include "sbar.h"
#include "m_argv.h"
#include "mapinfo.h"
#include "texturemanager.h"

BEGIN_DUKE_NS 


int myx, omyx, myxvel, myy, omyy, myyvel, myz, omyz, myzvel;
short globalskillsound;
fixed_t q16myang, oq16myang, q16myhoriz, oq16myhoriz, q16myhorizoff, oq16myhorizoff;
short mycursectnum, myjumpingcounter;
char myjumpingtoggle, myonground, myhardlanding,myreturntocenter;
int fakemovefifoplc;
int myxbak[MOVEFIFOSIZ], myybak[MOVEFIFOSIZ], myzbak[MOVEFIFOSIZ];
int myhorizbak[MOVEFIFOSIZ];
short myangbak[MOVEFIFOSIZ];


void resetmys()
{
	myx = omyx = ps[myconnectindex].posx;
	myy = omyy = ps[myconnectindex].posy;
	myz = omyz = ps[myconnectindex].posz;
	myxvel = myyvel = myzvel = 0;
	q16myang = oq16myang = ps[myconnectindex].q16ang;
	q16myhoriz = oq16myhoriz = ps[myconnectindex].q16horiz;
	q16myhorizoff = oq16myhorizoff = ps[myconnectindex].q16horizoff;
	mycursectnum = ps[myconnectindex].cursectnum;
	myjumpingcounter = ps[myconnectindex].jumping_counter;
	myjumpingtoggle = ps[myconnectindex].jumping_toggle;
	myonground = ps[myconnectindex].on_ground;
	myhardlanding = ps[myconnectindex].hard_landing;
	myreturntocenter = ps[myconnectindex].return_to_center;
}

#if 0 // todo: fix this when networking works again
void fakedomovethingscorrect(void)
{
	 int i;
	 struct player_struct *p;

	 if (numplayers < 2) return;

	 i = ((movefifoplc-1)&(MOVEFIFOSIZ-1));
	 p = &ps[myconnectindex];

	 if (p->posx == myxbak[i] && p->posy == myybak[i] && p->posz == myzbak[i]
		  && p->horiz == myhorizbak[i] && p->ang == myangbak[i]) return;

	 myx = p->posx; omyx = p->oposx; myxvel = p->posxv;
	 myy = p->posy; omyy = p->oposy; myyvel = p->posyv;
	 myz = p->posz; omyz = p->oposz; myzvel = p->poszv;
	 myang = p->ang; omyang = p->oang;
	 mycursectnum = p->cursectnum;
	 myhoriz = p->horiz; omyhoriz = p->ohoriz;
	 myhorizoff = p->horizoff; omyhorizoff = p->ohorizoff;
	 myjumpingcounter = p->jumping_counter;
	 myjumpingtoggle = p->jumping_toggle;
	 myonground = p->on_ground;
	 myhardlanding = p->hard_landing;
	 myreturntocenter = p->return_to_center;

	 fakemovefifoplc = movefifoplc;
	 while (fakemovefifoplc < movefifoend[myconnectindex])
		  fakedomovethings();

}

// This still needs fixing for the magic numbers in the input bits
void fakedomovethings(void)
{
		input *syn;
		struct player_struct *p;
		int i, j, k, doubvel, fz, cz, hz, lz, x, y;
		short psect, psectlotag, tempsect, backcstat;
		uint8_t shrunk, spritebridge;
		ESyncBits actions;

		syn = (input *)&inputfifo[fakemovefifoplc&(MOVEFIFOSIZ-1)][myconnectindex];

		p = &ps[myconnectindex];

		backcstat = sprite[p->i].cstat;
		sprite[p->i].cstat &= ~257;

		actions = syn->actions;

		psect = mycursectnum;
		psectlotag = sector[psect].lotag;
		spritebridge = 0;

		shrunk = (sprite[p->i].yrepeat < (isRR()? 8 : 32));

		if( ud.clipping == 0 && ( sector[psect].floorpicnum == MIRROR || psect < 0 || psect >= MAXSECTORS) )
		{
			myx = omyx;
			myy = omyy;
		}
		else
		{
			omyx = myx;
			omyy = myy;
		}

		omyhoriz = myhoriz;
		omyhorizoff = myhorizoff;
		omyz = myz;
		omyang = myang;

		getzrange(myx,myy,myz,psect,&cz,&hz,&fz,&lz,163L,CLIPMASK0);

		j = getflorzofslope(psect,myx,myy);

		if( (lz&49152) == 16384 && psectlotag == 1 && klabs(myz-j) > PHEIGHT+(16<<8) )
			psectlotag = 0;

		if( p->aim_mode == 0 && myonground && psectlotag != 2 && (sector[psect].floorstat&2) )
		{
				x = myx+(sintable[(myang+512)&2047]>>5);
				y = myy+(sintable[myang&2047]>>5);
				tempsect = psect;
				updatesector(x,y,&tempsect);
				if (tempsect >= 0)
				{
					 k = getflorzofslope(psect,x,y);
					 if (psect == tempsect)
						  myhorizoff += mulscale16(j-k,160);
					 else if (klabs(getflorzofslope(tempsect,x,y)-k) <= (4<<8))
						  myhorizoff += mulscale16(j-k,160);
				}
		}
		if (myhorizoff > 0) myhorizoff -= ((myhorizoff>>3)+1);
		else if (myhorizoff < 0) myhorizoff += (((-myhorizoff)>>3)+1);

		if(hz >= 0 && (hz&49152) == 49152)
		{
				hz &= (MAXSPRITES-1);
				if (sprite[hz].statnum == 1 && sprite[hz].extra >= 0)
				{
					hz = 0;
					cz = getceilzofslope(psect,myx,myy);
				}
		}

		if(lz >= 0 && (lz&49152) == 49152)
		{
				 j = lz&(MAXSPRITES-1);
				 if ((sprite[j].cstat&33) == 33)
				 {
						psectlotag = 0;
						spritebridge = 1;
				 }
				 if(badguy(&sprite[j]) && sprite[j].xrepeat > 24 && klabs(sprite[p->i].z-sprite[j].z) < (84<<8) )
				 {
					j = getangle( sprite[j].x-myx,sprite[j].y-myy);
					myxvel -= sintable[(j+512)&2047]<<4;
					myyvel -= sintable[j&2047]<<4;
				}
		}

		if( sprite[p->i].extra <= 0 )
		{
				 if( psectlotag == 2 )
				 {
							if(p->on_warping_sector == 0)
							{
									 if( klabs(myz-fz) > (PHEIGHT>>1))
											 myz += 348;
							}
							clipmove(&myx,&myy,&myz,&mycursectnum,0,0,164L,(4L<<8),(4L<<8),CLIPMASK0);
				 }

				 updatesector(myx,myy,&mycursectnum);
				 pushmove(&myx,&myy,&myz,&mycursectnum,128L,(4L<<8),(20L<<8),CLIPMASK0);

				myhoriz = 100;
				myhorizoff = 0;

				 goto ENDFAKEPROCESSINPUT;
		}

		doubvel = TICSPERFRAME;

		if(p->on_crane >= 0) goto FAKEHORIZONLY;

		if(p->one_eighty_count < 0) myang += 128;

		i = 40;

		if( psectlotag == 2)
		{
				 myjumpingcounter = 0;

				 if ( (sb_snum&1) && !(p->OnMotorcycle || p->OnBoat) )
				 {
							if(myzvel > 0) myzvel = 0;
							myzvel -= 348;
							if(myzvel < -(256*6)) myzvel = -(256*6);
				 }
				 else if ( (sb_snum&(1<<1)) && !(p->OnMotorcycle || p->OnBoat) )
				 {
							if(myzvel < 0) myzvel = 0;
							myzvel += 348;
							if(myzvel > (256*6)) myzvel = (256*6);
				 }
				 else
				 {
					if(myzvel < 0)
					{
						myzvel += 256;
						if(myzvel > 0)
							myzvel = 0;
					}
					if(myzvel > 0)
					{
						myzvel -= 256;
						if(myzvel < 0)
							myzvel = 0;
					}
				}

				if(myzvel > 2048) myzvel >>= 1;

				 myz += myzvel;

				 if(myz > (fz-(15<<8)) )
							myz += ((fz-(15<<8))-myz)>>1;

				 if(myz < (cz+(4<<8)) )
				 {
							myz = cz+(4<<8);
							myzvel = 0;
				 }
		}

		else if(p->jetpack_on)
		{
				 myonground = 0;
				 myjumpingcounter = 0;
				 myhardlanding = 0;

				 if(p->jetpack_on < 11)
							myz -= (p->jetpack_on<<7); //Goin up

				 if(shrunk) j = 512;
				 else j = 2048;
				 
				 if ((sb_snum&1) && !(p->OnMotorcycle || p->OnBoat))
							myz -= j;
				 if ((sb_snum&(1<<1)) && !(p->OnMotorcycle || p->OnBoat))
							myz += j;

				 if(shrunk == 0 && ( psectlotag == 0 || psectlotag == 2 ) ) k = 32;
				 else k = 16;

				 if(myz > (fz-(k<<8)) )
							myz += ((fz-(k<<8))-myz)>>1;
				 if(myz < (cz+(18<<8)) )
							myz = cz+(18<<8);
		}
		else if( psectlotag != 2 )
		{
			if (psectlotag == 1 && p->spritebridge == 0)
			{
				 if(shrunk == 0) i = 34;
				 else i = 12;
			}
				 if(myz < (fz-(i<<8)) && (floorspace(psect)|ceilingspace(psect)) == 0 ) //falling
				 {
							if( (sb_snum&3) == 0 && !(p->OnMotorcycle || p->OnBoat) && myonground && (sector[psect].floorstat&2) && myz >= (fz-(i<<8)-(16<<8) ) )
									 myz = fz-(i<<8);
							else
							{
									 myonground = 0;

									 myzvel += (gc+80);

									 if(myzvel >= (4096+2048)) myzvel = (4096+2048);
							}
				 }

				 else
				 {
							if(psectlotag != 1 && psectlotag != 2 && myonground == 0 && myzvel > (6144>>1))
								 myhardlanding = myzvel>>10;
							myonground = 1;

							if(i==40)
							{
									 //Smooth on the ground

									 k = ((fz-(i<<8))-myz)>>1;
									 if( klabs(k) < 256 ) k = 0;
									 myz += k; // ((fz-(i<<8))-myz)>>1;
									 myzvel -= 768; // 412;
									 if(myzvel < 0) myzvel = 0;
							}
							else if(myjumpingcounter == 0)
							{
								myz += ((fz-(i<<7))-myz)>>1; //Smooth on the water
								if(p->on_warping_sector == 0 && myz > fz-(16<<8))
								{
									myz = fz-(16<<8);
									myzvel >>= 1;
								}
							}

							if( (sb_snum&2) && !(p->OnMotorcycle || p->OnBoat) )
									 myz += (2048+768);

							if( (sb_snum&1) == 0 && !(p->OnMotorcycle || p->OnBoat) && myjumpingtoggle == 1)
									 myjumpingtoggle = 0;

							else if( (sb_snum&1) && !(p->OnMotorcycle || p->OnBoat) && myjumpingtoggle == 0 )
							{
									 if( myjumpingcounter == 0 )
											 if( (fz-cz) > (56<<8) )
											 {
												myjumpingcounter = 1;
												myjumpingtoggle = 1;
											 }
							}
							if(!isRR() && myjumpingcounter && (sb_snum&1) == 0 )
								myjumpingcounter = 0;
				 }

				 if(myjumpingcounter)
				 {
							if( (sb_snum&1) == 0 && !(p->OnMotorcycle || p->OnBoat) && myjumpingtoggle == 1)
									 myjumpingtoggle = 0;

							if( myjumpingcounter < (1024+256) )
							{
									 if(psectlotag == 1 && myjumpingcounter > 768)
									 {
											 myjumpingcounter = 0;
											 myzvel = -512;
									 }
									 else
									 {
											 myzvel -= (sintable[(2048-128+myjumpingcounter)&2047])/12;
											 myjumpingcounter += 180;

											 myonground = 0;
									 }
							}
							else
							{
									 myjumpingcounter = 0;
									 myzvel = 0;
							}
				 }

				 myz += myzvel;

				 if(myz < (cz+(4<<8)) )
				 {
							myjumpingcounter = 0;
							if(myzvel < 0) myxvel = myyvel = 0;
							myzvel = 128;
							myz = cz+(4<<8);
				 }

		}

		if (movementBlocked(snum) || myhardlanding)
		{
				 doubvel = 0;
				 myxvel = 0;
				 myyvel = 0;
		}
		else if ( syn->avel )          //p->ang += syncangvel * constant
		{                         //ENGINE calculates angvel for you
			int tempang;

			tempang = syn->avel<<1;

			if(psectlotag == 2)
				myang += (tempang-(tempang>>3))*sgn(doubvel);
			else myang += (tempang)*sgn(doubvel);
			myang &= 2047;
		}

		if ( myxvel || myyvel || syn->fvel || syn->svel )
		{
				 if(p->steroids_amount > 0 && p->steroids_amount < 400)
					 doubvel <<= 1;

				 myxvel += ((syn->fvel*doubvel)<<6);
				 myyvel += ((syn->svel*doubvel)<<6);

				 if( ( p->curr_weapon == KNEE_WEAPON && p->kickback_pic > 10 && myonground ) || ( myonground && (sb_snum&2) && !(p->OnMotorcycle || p->OnBoat)) )
				 {
							myxvel = mulscale16(myxvel,dukefriction-0x2000);
							myyvel = mulscale16(myyvel,dukefriction-0x2000);
				 }
				 else
				 {
					if(psectlotag == 2)
					{
						myxvel = mulscale16(myxvel,dukefriction-0x1400);
						myyvel = mulscale16(myyvel,dukefriction-0x1400);
					}
					else
					{
						myxvel = mulscale16(myxvel,dukefriction);
						myyvel = mulscale16(myyvel,dukefriction);
					}
				 }

				 if( abs(myxvel) < 2048 && abs(myyvel) < 2048 )
					 myxvel = myyvel = 0;

				 if( shrunk )
				 {
					 myxvel =
						 mulscale16(myxvel,(dukefriction)-(dukefriction>>1)+(dukefriction>>2));
					 myyvel =
						 mulscale16(myyvel,(dukefriction)-(dukefriction>>1)+(dukefriction>>2));
				 }
		}

FAKEHORIZONLY:
		if(psectlotag == 1 || spritebridge == 1) i = (4L<<8); else i = (20L<<8);

		clipmove(&myx,&myy,&myz,&mycursectnum,myxvel,myyvel,164L,4L<<8,i,CLIPMASK0);
		pushmove(&myx,&myy,&myz,&mycursectnum,164L,4L<<8,4L<<8,CLIPMASK0);

		if( p->jetpack_on == 0 && psectlotag != 1 && psectlotag != 2 && shrunk)
			myz += 30<<8;

		if ((sb_snum&(1<<18)) || myhardlanding)
			myreturntocenter = 9;

		if (sb_snum&(1<<13))
		{
				myreturntocenter = 9;
				if (sb_snum&(1<<5)) myhoriz += 6;
				myhoriz += 6;
		}
		else if (sb_snum&(1<<14))
		{
				myreturntocenter = 9;
				if (sb_snum&(1<<5)) myhoriz -= 6;
				myhoriz -= 6;
		}
		else if ((sb_snum&(1<<3)) && !(p->OnMotorcycle || p->OnBoat))
		{
				if (sb_snum&(1<<5)) myhoriz += 6;
				myhoriz += 6;
		}
		else if ((sb_snum&(1<<4)) && !(p->OnMotorcycle || p->OnBoat))
		{
				if (sb_snum&(1<<5)) myhoriz -= 6;
				myhoriz -= 6;
		}

		if (myreturntocenter > 0)
			if ((sb_snum&(1<<13)) == 0 && (sb_snum&(1<<14)) == 0)
		{
			 myreturntocenter--;
			 myhoriz += 33-(myhoriz/3);
		}

		if(p->aim_mode)
			myhoriz += syn->horz>>1;
		else
		{
			if( myhoriz > 95 && myhoriz < 105) myhoriz = 100;
			if( myhorizoff > -5 && myhorizoff < 5) myhorizoff = 0;
		}

		if (myhardlanding > 0)
		{
			myhardlanding--;
			myhoriz -= (myhardlanding<<4);
		}

		myhoriz = clamp(myhoriz, HORIZ_MIN, HORIZ_MAX);

		if(p->knee_incs > 0)
		{
			myhoriz -= 48;
			myreturntocenter = 9;
		}


ENDFAKEPROCESSINPUT:

		myxbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myx;
		myybak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myy;
		myzbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myz;
		myangbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myang;
		myhorizbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myhoriz;
		fakemovefifoplc++;

		sprite[p->i].cstat = backcstat;
}
#endif

END_DUKE_NS