struct UserCmd native { native uint buttons; native int16 pitch; // up/down native int16 yaw; // left/right native int16 roll; // "tilt" native int16 forwardmove; native int16 sidemove; native int16 upmove; } class PlayerPawn : Actor native { const CROUCHSPEED = (1./12); native int crouchsprite; native int MaxHealth; native int BonusHealth; native int MugShotMaxHealth; native int RunHealth; native int PlayerFlags; native clearscope Inventory InvFirst; // first inventory item displayed on inventory bar native clearscope Inventory InvSel; // selected inventory item native Name SoundClass; // Sound class native Name Face; // Doom status bar face (when used) native Name Portrait; native Name Slot[10]; native double HexenArmor[5]; native uint8 ColorRangeStart; // Skin color range native uint8 ColorRangeEnd; // [GRB] Player class properties native double JumpZ; native double GruntSpeed; native double FallingScreamMinSpeed, FallingScreamMaxSpeed; native double ViewHeight; native double ForwardMove1, ForwardMove2; native double SideMove1, SideMove2; native TextureID ScoreIcon; native int SpawnMask; native Name MorphWeapon; native double AttackZOffset; // attack height, relative to player center native double UseRange; // [NS] Distance at which player can +use native double AirCapacity; // Multiplier for air supply underwater. native Class FlechetteType; native color DamageFade; // [CW] Fades for when you are being damaged. native double ViewBob; // [SP] ViewBob Multiplier native double FullHeight; meta Name HealingRadiusType; meta Name InvulMode; property prefix: Player; property HealRadiusType: HealingradiusType; property InvulnerabilityMode: InvulMode; property AttackZOffset: AttackZOffset; property JumpZ: JumpZ; property GruntSpeed: GruntSpeed; property FallingScreamSpeed: FallingScreamMinSpeed, FallingScreamMaxSpeed; property ViewHeight: ViewHeight; property UseRange: UseRange; property AirCapacity: AirCapacity; property MaxHealth: MaxHealth; property MugshotMaxHealth: MugshotMaxHealth; property RunHealth: RunHealth; property MorphWeapon: MorphWeapon; property FlechetteType: FlechetteType; property Portrait: Portrait; Default { Health 100; Radius 16; Height 56; Mass 100; Painchance 255; Speed 1; +SOLID +SHOOTABLE +DROPOFF +PICKUP +NOTDMATCH +FRIENDLY +SLIDESONWALLS +CANPASS +CANPUSHWALLS +FLOORCLIP +WINDTHRUST +TELESTOMP +NOBLOCKMONST Player.AttackZOffset 8; Player.JumpZ 8; Player.GruntSpeed 12; Player.FallingScreamSpeed 35,40; Player.ViewHeight 41; Player.UseRange 64; Player.ForwardMove 1,1; Player.SideMove 1,1; Player.ColorRange 0,0; Player.SoundClass "player"; Player.DamageScreenColor "ff 00 00"; Player.MugShotMaxHealth 0; Player.FlechetteType "ArtiPoisonBag3"; Player.AirCapacity 1; Player.ViewBob 1; Obituary "$OB_MPDEFAULT"; } //---------------------------------------------------------------------------- // // // //---------------------------------------------------------------------------- virtual void PlayIdle () { if (InStateSequence(CurState, SeeState)) SetState (SpawnState); } virtual void PlayRunning () { if (InStateSequence(CurState, SpawnState) && SeeState != NULL) SetState (SeeState); } virtual void PlayAttacking () { if (MissileState != null) SetState (MissileState); } virtual void PlayAttacking2 () { if (MeleeState != null) SetState (MeleeState); } virtual void MorphPlayerThink() { } //---------------------------------------------------------------------------- // // // //---------------------------------------------------------------------------- virtual void OnRespawn() { if (sv_respawnprotect && (multiplayer || alwaysapplydmflags)) { let invul = Powerup(Spawn("PowerInvulnerable")); invul.EffectTics = 3 * TICRATE; invul.BlendColor = 0; // don't mess with the view invul.bUndroppable = true; // Don't drop this bRespawnInvul = true; // [RH] special effect } } //---------------------------------------------------------------------------- // // // //---------------------------------------------------------------------------- override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack) { if (victim.player != player && victim.IsTeammate(self)) { victim = self; return String.Format("$OB_FRIENDLY%c", random[Obituary](49, 53)); } else { if (mod == 'Telefrag') return "$OB_MPTELEFRAG"; String message; if (inflictor != NULL && inflictor != self) { message = inflictor.GetObituary(victim, inflictor, mod, playerattack); } if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL) { message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack); } if (message.Length() == 0) { if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH"; if (mod == 'Railgun') return "$OB_RAILGUN"; message = Obituary; } return message; } } //---------------------------------------------------------------------------- // // This is for SBARINFO. // //---------------------------------------------------------------------------- clearscope int, int GetEffectTicsForItem(class item) const { let pg = (class)(item); if (pg != null) { let powerupType = (class)(GetDefaultByType(pg).PowerupType); let powerup = Powerup(FindInventory(powerupType)); if(powerup != null) { let maxtics = GetDefaultByType(pg).EffectTics; if (maxtics == 0) maxtics = powerup.default.EffectTics; return powerup.EffectTics, maxtics; } } return -1, -1; } //---------------------------------------------------------------------------- // // PROC P_CheckFOV // //---------------------------------------------------------------------------- virtual void CheckFOV() { let player = self.player; // [RH] Zoom the player's FOV float desired = player.DesiredFOV; // Adjust FOV using on the currently held weapon. if (player.playerstate != PST_DEAD && // No adjustment while dead. player.ReadyWeapon != NULL && // No adjustment if no weapon. player.ReadyWeapon.FOVScale != 0) // No adjustment if the adjustment is zero. { // A negative scale is used to prevent G_AddViewAngle/G_AddViewPitch // from scaling with the FOV scale. desired *= abs(player.ReadyWeapon.FOVScale); } if (player.FOV != desired) { if (abs(player.FOV - desired) < 7.) { player.FOV = desired; } else { float zoom = MAX(7., abs(player.FOV - desired) * 0.025); if (player.FOV > desired) { player.FOV = player.FOV - zoom; } else { player.FOV = player.FOV + zoom; } } } } //---------------------------------------------------------------------------- // // PROC P_CheckCheats // //---------------------------------------------------------------------------- virtual void CheckCheats() { let player = self.player; // No-clip cheat if ((player.cheats & (CF_NOCLIP | CF_NOCLIP2)) == CF_NOCLIP2) { // No noclip2 without noclip player.cheats &= ~CF_NOCLIP2; } bNoClip = (player.cheats & (CF_NOCLIP | CF_NOCLIP2) || Default.bNoClip); if (player.cheats & CF_NOCLIP2) { bNoGravity = true; } else if (!bFly && !Default.bNoGravity) { bNoGravity = false; } } //---------------------------------------------------------------------------- // // PROC P_CheckFrozen // //---------------------------------------------------------------------------- virtual bool CheckFrozen() { let player = self.player; UserCmd cmd = player.cmd; bool totallyfrozen = player.IsTotallyFrozen(); // [RH] Being totally frozen zeros out most input parameters. if (totallyfrozen) { if (gamestate == GS_TITLELEVEL) { cmd.buttons = 0; } else { cmd.buttons &= BT_USE; } cmd.pitch = 0; cmd.yaw = 0; cmd.roll = 0; cmd.forwardmove = 0; cmd.sidemove = 0; cmd.upmove = 0; player.turnticks = 0; } else if (player.cheats & CF_FROZEN) { cmd.forwardmove = 0; cmd.sidemove = 0; cmd.upmove = 0; } return totallyfrozen; } virtual bool CanCrouch() const { return player.morphTics == 0 || bCrouchableMorph; } //---------------------------------------------------------------------------- // // PROC P_CrouchMove // //---------------------------------------------------------------------------- virtual void CrouchMove(int direction) { let player = self.player; double defaultheight = FullHeight; double savedheight = Height; double crouchspeed = direction * CROUCHSPEED; double oldheight = player.viewheight; player.crouchdir = direction; player.crouchfactor += crouchspeed; // check whether the move is ok Height = defaultheight * player.crouchfactor; if (!TryMove(Pos.XY, false, NULL)) { Height = savedheight; if (direction > 0) { // doesn't fit player.crouchfactor -= crouchspeed; return; } } Height = savedheight; player.crouchfactor = clamp(player.crouchfactor, 0.5, 1.); player.viewheight = ViewHeight * player.crouchfactor; player.crouchviewdelta = player.viewheight - ViewHeight; // Check for eyes going above/below fake floor due to crouching motion. CheckFakeFloorTriggers(pos.Z + oldheight, true); } //---------------------------------------------------------------------------- // // PROC P_CheckCrouch // //---------------------------------------------------------------------------- virtual void CheckCrouch(bool totallyfrozen) { let player = self.player; UserCmd cmd = player.cmd; if (cmd.buttons & BT_JUMP) { cmd.buttons &= ~BT_CROUCH; } if (CanCrouch() && player.health > 0 && level.IsCrouchingAllowed()) { if (!totallyfrozen) { int crouchdir = player.crouching; if (crouchdir == 0) { crouchdir = (cmd.buttons & BT_CROUCH) ? -1 : 1; } else if (cmd.buttons & BT_CROUCH) { player.crouching = 0; } if (crouchdir == 1 && player.crouchfactor < 1 && pos.Z + height < ceilingz) { CrouchMove(1); } else if (crouchdir == -1 && player.crouchfactor > 0.5) { CrouchMove(-1); } } } else { player.Uncrouch(); } player.crouchoffset = -(ViewHeight) * (1 - player.crouchfactor); } //---------------------------------------------------------------------------- // // PROC P_PlayerThink // //---------------------------------------------------------------------------- native void CheckMusicChange(); native void DeathThink (); native void CheckPitch(); native void HandleMovement(); native void CalcHeight (); native void CheckEnvironment(); native void CheckUse(); native void CheckUndoMorph(); // Cycle psprites native void CheckPoison(); native void CheckDegeneration(); native void CheckAirSupply(); virtual void PlayerThink() { let player = self.player; UserCmd cmd = player.cmd; CheckFOV(); if (player.inventorytics) { player.inventorytics--; } CheckCheats(); if (bJustAttacked) { // Chainsaw/Gauntlets attack auto forward motion cmd.yaw = 0; cmd.forwardmove = 0xc800/2; cmd.sidemove = 0; bJustAttacked = false; } bool totallyfrozen = CheckFrozen(); // Handle crouching CheckCrouch(totallyfrozen); CheckMusicChange(); if (player.playerstate == PST_DEAD) { DeathThink (); return; } if (player.jumpTics != 0) { player.jumpTics--; if (player.onground && player.jumpTics < -18) { player.jumpTics = 0; } } if (player.morphTics && !(player.cheats & CF_PREDICTING)) { MorphPlayerThink (); } CheckPitch(); HandleMovement(); CalcHeight (); if (!(player.cheats & CF_PREDICTING)) { CheckEnvironment(); CheckUse(); CheckUndoMorph(); // Cycle psprites player.TickPSprites(); // Other Counters if (player.damagecount) player.damagecount--; if (player.bonuscount) player.bonuscount--; if (player.hazardcount) { player.hazardcount--; if (!(level.time % player.hazardinterval) && player.hazardcount > 16*TICRATE) DamageMobj (NULL, NULL, 5, player.hazardtype); } CheckPoison(); CheckDegeneration(); CheckAirSupply(); } } //---------------------------------------------------------------------------- // // // //---------------------------------------------------------------------------- native clearscope int GetMaxHealth(bool withupgrades = false) const; native bool ResetAirSupply (bool playgasp = false); native void CheckWeaponSwitch(class item); native clearscope static String GetPrintableDisplayName(Class cls); } class PlayerChunk : PlayerPawn { Default { +NOSKIN -SOLID -SHOOTABLE -PICKUP -NOTDMATCH -FRIENDLY -SLIDESONWALLS -CANPUSHWALLS -FLOORCLIP -WINDTHRUST -TELESTOMP } } class PSprite : Object native play { enum PSPLayers { STRIFEHANDS = -1, WEAPON = 1, FLASH = 1000, TARGETCENTER = 0x7fffffff - 2, TARGETLEFT, TARGETRIGHT, }; native readonly State CurState; native Actor Caller; native readonly PSprite Next; native readonly PlayerInfo Owner; native SpriteID Sprite; native int Frame; //native readonly int RenderStyle; had to be blocked because the internal representation was not ok. Renderstyle is still pending a proper solution. native readonly int ID; native Bool processPending; native double x; native double y; native double oldx; native double oldy; native double alpha; native Bool firstTic; native int Tics; native bool bAddWeapon; native bool bAddBob; native bool bPowDouble; native bool bCVarFast; native bool bFlip; native void SetState(State newstate, bool pending = false); } enum EPlayerState { PST_LIVE, // Playing or camping. PST_DEAD, // Dead on the ground, view follows killer. PST_REBORN, // Ready to restart/respawn??? PST_ENTER, // [BC] Entered the game PST_GONE // Player has left the game } struct PlayerInfo native play // this is what internally is known as player_t { // technically engine constants but the only part of the playsim using them is the player. const NOFIXEDCOLORMAP = -1; const NUMCOLORMAPS = 32; native PlayerPawn mo; native uint8 playerstate; native readonly uint buttons; native uint original_oldbuttons; native readonly Class cls; native float DesiredFOV; native float FOV; native double viewz; native double viewheight; native double deltaviewheight; native double bob; native vector2 vel; native bool centering; native uint8 turnticks; native bool attackdown; native bool usedown; native uint oldbuttons; native int health; native clearscope int inventorytics; native uint8 CurrentPlayerClass; native int frags[MAXPLAYERS]; native int fragcount; native int lastkilltime; native uint8 multicount; native uint8 spreecount; native uint16 WeaponState; native Weapon ReadyWeapon; native Weapon PendingWeapon; native PSprite psprites; native int cheats; native int timefreezer; native int16 refire; native int16 inconsistent; native bool waiting; native int killcount; native int itemcount; native int secretcount; native int damagecount; native int bonuscount; native int hazardcount; native int hazardinterval; native Name hazardtype; native int poisoncount; native Name poisontype; native Name poisonpaintype; native Actor poisoner; native Actor attacker; native int extralight; native int16 fixedcolormap; native int16 fixedlightlevel; native int morphtics; native ClassMorphedPlayerClass; native int MorphStyle; native Class MorphExitFlash; native Class PremorphWeapon; native int chickenPeck; native int jumpTics; native bool onground; native int respawn_time; native Actor camera; native int air_finished; native Name LastDamageType; native Actor MUSINFOactor; native int8 MUSINFOtics; native bool settings_controller; native int8 crouching; native int8 crouchdir; native Bot bot; native float BlendR; native float BlendG; native float BlendB; native float BlendA; native String LogText; native double MinPitch; native double MaxPitch; native double crouchfactor; native double crouchoffset; native double crouchviewdelta; native Actor ConversationNPC; native Actor ConversationPC; native double ConversationNPCAngle; native bool ConversationFaceTalker; native @WeaponSlots weapons; native @UserCmd cmd; native readonly @UserCmd original_cmd; native bool MorphPlayer(playerinfo p, Class spawntype, int duration, int style, Class enter_flash = null, Class exit_flash = null); native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); native bool PoisonPlayer(Actor poisoner, Actor source, int poison); native void PoisonDamage(Actor source, int damage, bool playPainSound); native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id) const; native PSprite FindPSprite(int id) const; native void SetLogNumber (int text); native void SetLogText (String text); native void DropWeapon(); native void BringUpWeapon(); native bool Resurrect(); native String GetUserName() const; native Color GetColor() const; native Color GetDisplayColor() const; native int GetColorSet() const; native int GetPlayerClassNum() const; native int GetSkin() const; native bool GetNeverSwitch() const; native int GetGender() const; native int GetTeam() const; native float GetAutoaim() const; native bool GetNoAutostartMap() const; native void SetFOV(float fov); native clearscope bool HasWeaponsInSlot(int slot) const; native void TickPSprites(); bool IsTotallyFrozen() { return gamestate == GS_TITLELEVEL || (cheats & CF_TOTALLYFROZEN) || (level.frozen && timefreezer == 0); } void Uncrouch() { if (crouchfactor != 1) { crouchfactor = 1; crouchoffset = 0; crouchdir = 0; crouching = 0; crouchviewdelta = 0; viewheight = mo.ViewHeight; } } clearscope int fragSum () const { int i; int allfrags = 0; int playernum = mo.PlayerNumber(); for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && i!=playernum) { allfrags += frags[i]; } } // JDC hack - negative frags. allfrags -= frags[playernum]; return allfrags; } } struct PlayerClass native { native class Type; native uint Flags; native Array Skins; native bool CheckSkin(int skin); native void EnumColorsets(out Array data); native Name GetColorsetName(int setnum); } struct PlayerSkin native { native readonly String SkinName; native readonly String Face; native readonly uint8 gender; native readonly uint8 range0start; native readonly uint8 range0end; native readonly bool othergame; native readonly Vector2 Scale; native readonly int sprite; native readonly int crouchsprite; native readonly int namespc; }; struct Team native { const NoTeam = 255; const Max = 16; native String mName; }