390 lines
10 KiB
C
390 lines
10 KiB
C
// Copyright © 2016-2017 Graham Sanderson, all rights reserved.
|
|
#include "lith_common.h"
|
|
#include "lith_player.h"
|
|
#include "lith_version.h"
|
|
#include "lith_world.h"
|
|
#include "lith_monster.h"
|
|
|
|
#include <math.h>
|
|
|
|
// Static Functions ----------------------------------------------------------|
|
|
|
|
//
|
|
// SetupAttributes
|
|
//
|
|
static void SetupAttributes(struct player *p)
|
|
{
|
|
p->attr.names[at_acc] = "ACC";
|
|
p->attr.names[at_def] = "DEF";
|
|
p->attr.names[at_str] = "STR";
|
|
p->attr.names[at_vit] = "VIT";
|
|
p->attr.names[at_stm] = "STM";
|
|
p->attr.names[at_luk] = "LUK";
|
|
p->attr.names[at_rge] = "RGE";
|
|
|
|
if(p->pclass & pcl_robot) {
|
|
p->attr.names[at_vit] = "POT";
|
|
p->attr.names[at_stm] = "REP";
|
|
} else if(p->pclass & pcl_nonhuman) {
|
|
p->attr.names[at_vit] = "POT";
|
|
p->attr.names[at_stm] = "REG";
|
|
}
|
|
|
|
p->attr.expnext = 500;
|
|
p->attr.level = 1;
|
|
}
|
|
|
|
//
|
|
// SetPClass
|
|
//
|
|
static void SetPClass(struct player *p)
|
|
{
|
|
__with(__str cl = p->pcstr = ACS_GetActorClass(0);) {
|
|
if(cl == "Lith_MarinePlayer" ) p->pclass = pcl_marine;
|
|
else if(cl == "Lith_CyberMagePlayer") p->pclass = pcl_cybermage;
|
|
else if(cl == "Lith_InformantPlayer") p->pclass = pcl_informant;
|
|
else if(cl == "Lith_WandererPlayer" ) p->pclass = pcl_wanderer;
|
|
else if(cl == "Lith_AssassinPlayer" ) p->pclass = pcl_assassin;
|
|
else if(cl == "Lith_DarkLordPlayer" ) p->pclass = pcl_darklord;
|
|
else if(cl == "Lith_ThothPlayer" ) p->pclass = pcl_thoth;
|
|
else if(cl == "FDPlutPlayer" || cl == "FDTNTPlayer" ||
|
|
cl == "FDDoom2Player" || cl == "FDAliensPlayer" ||
|
|
cl == "FDJPCPPlayer" || cl == "FDBTSXPlayer")
|
|
p->pclass = pcl_fdoomer;
|
|
else if(cl == "DoomRLMarine" || cl == "DoomRLScout" ||
|
|
cl == "DoomRLTechnician" || cl == "DoomRLRenegade" ||
|
|
cl == "DoomRLDemolitionist" || cl == "DoomRLCommando")
|
|
p->pclass = pcl_drla;
|
|
else for(;;)
|
|
{
|
|
Log("Invalid player class detected, everything is going to explode!");
|
|
ACS_Delay(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extern Functions ----------------------------------------------------------|
|
|
|
|
//
|
|
// Lith_PlayerCurWeaponType
|
|
//
|
|
stkcall int Lith_PlayerCurWeaponType(struct player *p)
|
|
{
|
|
return p->weapon.cur->info->type;
|
|
}
|
|
|
|
//
|
|
// Lith_ButtonPressed
|
|
//
|
|
stkcall bool Lith_ButtonPressed(struct player *p, int bt)
|
|
{
|
|
return p->buttons & bt && !(p->old.buttons & bt);
|
|
}
|
|
|
|
//
|
|
// Lith_SetPlayerVelocity
|
|
//
|
|
stkcall bool Lith_SetPlayerVelocity(struct player *p, fixed velx, fixed vely, fixed velz, bool add)
|
|
{
|
|
if(add)
|
|
p->velx += velx, p->vely += vely, p->velz += velz;
|
|
else
|
|
p->velx = velx, p->vely = vely, p->velz = velz;
|
|
|
|
return ACS_SetActorVelocity(p->tid, velx, vely, velz, add, true);
|
|
}
|
|
|
|
//
|
|
// Lith_ValidatePlayerTID
|
|
//
|
|
void Lith_ValidatePlayerTID(struct player *p)
|
|
{
|
|
if(ACS_ActivatorTID() == 0) {
|
|
ACS_Thing_ChangeTID(0, p->tid = ACS_UniqueTID());
|
|
LogDebug(log_dev, "set ptid from 0 to %i", p->tid);
|
|
} else if(p->tid != ACS_ActivatorTID()) {
|
|
LogDebug(log_dev, "set ptid from %i to %i", p->tid, ACS_ActivatorTID());
|
|
p->tid = ACS_ActivatorTID();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lith_PlayerUpdateData
|
|
//
|
|
// Update all of the player's data.
|
|
//
|
|
script void Lith_PlayerUpdateData(struct player *p)
|
|
{
|
|
static int const warpflags = WARPF_NOCHECKPOSITION | WARPF_MOVEPTR |
|
|
WARPF_WARPINTERPOLATION | WARPF_COPYINTERPOLATION | WARPF_COPYPITCH;
|
|
|
|
ACS_Warp(p->cameratid, 4, 0, ACS_GetActorViewHeight(0), 0, warpflags);
|
|
ACS_Warp(p->weathertid, 4, 0, ACS_GetActorViewHeight(0), 0, warpflags);
|
|
|
|
p->x = ACS_GetActorX(0);
|
|
p->y = ACS_GetActorY(0);
|
|
p->z = ACS_GetActorZ(0);
|
|
p->floorz = ACS_GetActorFloorZ(0);
|
|
|
|
p->velx = ACS_GetActorVelX(0);
|
|
p->vely = ACS_GetActorVelY(0);
|
|
p->velz = ACS_GetActorVelZ(0);
|
|
|
|
p->pitch = ACS_GetActorPitch(0) - p->addpitch;
|
|
p->yaw = ACS_GetActorAngle(0) - p->addyaw;
|
|
p->roll = ACS_GetActorRoll (0) - p->addroll;
|
|
|
|
p->pitchf = ((-p->pitch + 0.25) * 2) * pi;
|
|
p->yawf = p->yaw * tau - pi;
|
|
|
|
p->pitchv = ACS_GetPlayerInputFixed(-1, INPUT_PITCH);
|
|
p->yawv = ACS_GetPlayerInputFixed(-1, INPUT_YAW);
|
|
|
|
p->forwardv = ACS_GetPlayerInputFixed(-1, INPUT_FORWARDMOVE);
|
|
p->sidev = ACS_GetPlayerInputFixed(-1, INPUT_SIDEMOVE);
|
|
p->upv = ACS_GetPlayerInputFixed(-1, INPUT_UPMOVE);
|
|
|
|
p->buttons = ACS_GetPlayerInput(-1, INPUT_BUTTONS);
|
|
|
|
p->name = StrParam("%tS", p->num);
|
|
p->weaponclass = ACS_GetWeapon();
|
|
|
|
p->scopetoken = InvNum("Lith_WeaponScopedToken");
|
|
|
|
p->keys.rc = InvNum("RedCard") ||
|
|
InvNum("KeyGreen");
|
|
p->keys.yc = InvNum("YellowCard") ||
|
|
InvNum("KeyYellow");
|
|
p->keys.bc = InvNum("BlueCard") ||
|
|
InvNum("KeyBlue");
|
|
p->keys.rs = InvNum("RedSkull");
|
|
p->keys.ys = InvNum("YellowSkull");
|
|
p->keys.bs = InvNum("BlueSkull");
|
|
|
|
DebugStat("attr points: %u\nexp: lv.%u %lu/%lu\n",
|
|
p->attr.points, p->attr.level, p->attr.exp, p->attr.expnext);
|
|
DebugStat("x: %k\ny: %k\nz: %k\n", p->x, p->y, p->z);
|
|
DebugStat("vx: %k\nvy: %k\nvz: %k\nvel: %k\n", p->velx, p->vely, p->velz, p->getVel());
|
|
DebugStat("a.y: %k\na.p: %k\n", p->yaw * 360, p->pitch * 360);
|
|
}
|
|
|
|
//
|
|
// Lith_GiveMail
|
|
//
|
|
script acs void Lith_GiveMail(int num)
|
|
{
|
|
static __str const names[] = {
|
|
"Intro",
|
|
"Cluster1",
|
|
"Cluster2",
|
|
"Cluster3",
|
|
"Phantom",
|
|
"JamesDefeated",
|
|
"MakarovDefeated",
|
|
"IsaacDefeated"
|
|
};
|
|
|
|
num %= countof(names);
|
|
|
|
withplayer(LocalPlayer)
|
|
p->deliverMail(names[num]);
|
|
}
|
|
|
|
//
|
|
// Lith_ClearTextBuf
|
|
//
|
|
stkcall void Lith_ClearTextBuf(struct player *p)
|
|
{
|
|
memset(p->txtbuf, 0, sizeof(p->txtbuf));
|
|
p->tbptr = 0;
|
|
}
|
|
|
|
//
|
|
// Lith_KeyDown
|
|
//
|
|
script acs void Lith_KeyDown(int pnum, int ch)
|
|
{
|
|
withplayer(&players[pnum])
|
|
if(p->tbptr + 1 < countof(p->txtbuf))
|
|
p->txtbuf[p->tbptr++] = ch;
|
|
}
|
|
|
|
//
|
|
// Lith_GiveEXP
|
|
//
|
|
stkcall void Lith_GiveEXP(struct player *p, u64 amt)
|
|
{
|
|
#pragma GDCC FIXED_LITERAL OFF
|
|
struct player_attributes *a = &p->attr;
|
|
|
|
while(a->exp + amt >= a->expnext) {
|
|
a->level++;
|
|
a->points += 5;
|
|
a->expnext = 500 + (a->level * pow(1.385, a->level * 0.2) * 340);
|
|
p->attr.sup = p->attr.cur;
|
|
}
|
|
|
|
a->exp += amt;
|
|
}
|
|
|
|
//
|
|
// Lith_ResetPlayer
|
|
//
|
|
// Reset some things on the player when they spawn.
|
|
//
|
|
script void Lith_ResetPlayer(struct player *p)
|
|
{
|
|
//
|
|
// Zero-init
|
|
|
|
if(!p->wasinit) {
|
|
*p = (struct player){};
|
|
p->wasinit = true;
|
|
}
|
|
|
|
//
|
|
// Constant data
|
|
|
|
p->active = true;
|
|
p->reinit = p->dead = false;
|
|
p->num = ACS_PlayerNumber();
|
|
p->bipptr = &p->bip;
|
|
|
|
//
|
|
// Static data (pre-init)
|
|
|
|
if(!p->staticinit)
|
|
{
|
|
SetPClass(p);
|
|
SetupAttributes(p);
|
|
|
|
// i cri tears of pain for APROP_SpawnHealth
|
|
p->viewheight = ACS_GetActorViewHeight(0);
|
|
p->jumpheight = ACS_GetActorPropertyFixed(0, APROP_JumpZ);
|
|
p->spawnhealth = ACS_GetActorProperty(0, APROP_Health);
|
|
p->spawndfactor = ACS_GetActorPropertyFixed(0, APROP_DamageFactor);
|
|
p->maxhealth = p->spawnhealth;
|
|
p->discount = 1.0;
|
|
p->stepnoise = StrParam("player/%S/step", p->classname);
|
|
|
|
switch(ACS_GetPlayerInfo(p->num, PLAYERINFO_GENDER))
|
|
{
|
|
case 0: p->pronoun = pro_male; break;
|
|
case 1: p->pronoun = pro_female; break;
|
|
case 2: p->pronoun = pro_object; break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Map-static data
|
|
|
|
p->old = (struct player_delta){};
|
|
|
|
// If the map sets the TID on the first tic, it could already be set here.
|
|
p->tid = 0;
|
|
p->validateTID();
|
|
|
|
// This keeps spawning more camera actors when you die, but that should be
|
|
// OK as long as you don't die 2 billion times.
|
|
ACS_SpawnForced("Lith_CameraHax", 0, 0, 0, p->cameratid = ACS_UniqueTID());
|
|
ACS_SpawnForced("Lith_CameraHax", 0, 0, 0, p->weathertid = ACS_UniqueTID());
|
|
|
|
if(world.dbgScore)
|
|
p->score = 0xFFFFFFFFFFFFFFFFll;
|
|
|
|
//
|
|
// Reset data
|
|
|
|
// Any linked lists on the player need to be initialized here.
|
|
p->loginfo.hud.free();
|
|
p->hudstrlist.free(true);
|
|
if(!p->loginfo.full.next) p->loginfo.full.construct();
|
|
if(!p->loginfo.maps.next) p->loginfo.maps.construct();
|
|
|
|
// pls not exit map with murder thingies out
|
|
// is bad practice
|
|
ACS_SetPlayerProperty(0, false, PROP_INSTANTWEAPONSWITCH);
|
|
ACS_SetActorPropertyFixed(0, APROP_ViewHeight, p->viewheight);
|
|
InvTake("Lith_WeaponScopedToken", 999);
|
|
|
|
Lith_PlayerResetCBIGUI(p);
|
|
|
|
p->frozen = 0;
|
|
p->semifrozen = 0;
|
|
|
|
p->addpitch = 0.0f;
|
|
p->addyaw = 0.0f;
|
|
p->addroll = 0.0f;
|
|
|
|
p->bobpitch = 0.0f;
|
|
p->bobyaw = 0.0f;
|
|
|
|
p->extrpitch = 0.0f;
|
|
p->extryaw = 0.0f;
|
|
|
|
p->scoreaccum = 0;
|
|
p->scoreaccumtime = 0;
|
|
p->scoremul = 1.3;
|
|
|
|
p->alpha = 1;
|
|
|
|
//
|
|
// Re-init data
|
|
|
|
if(!p->bip.init)
|
|
Lith_PlayerInitBIP(p);
|
|
|
|
if(!p->upgrinit)
|
|
Lith_PlayerInitUpgrades(p);
|
|
else
|
|
Lith_PlayerReinitUpgrades(p);
|
|
|
|
//
|
|
// Static data
|
|
|
|
if(!p->staticinit)
|
|
{
|
|
p->log("> Lithia " Lith_Version " :: Compiled %S", __DATE__);
|
|
|
|
if(world.dbgLevel) {
|
|
p->logH("> player is %u bytes long!", sizeof(struct player) * 4);
|
|
p->logH("> strnull is \"%S\"", strnull);
|
|
PrintDmonAllocSize(p);
|
|
} else {
|
|
p->logH("> Press \"%jS\" to open the menu.", "lith_k_opencbi");
|
|
}
|
|
|
|
p->deliverMail("Intro");
|
|
|
|
p->staticinit = true;
|
|
}
|
|
|
|
if(world.dbgItems)
|
|
{
|
|
for(int i = weapon_min; i < weapon_max; i++) {
|
|
weaponinfo_t const *info = &weaponinfo[i];
|
|
if(info->classname != null && info->pclass & p->pclass && !(info->flags & wf_magic))
|
|
InvGive(info->classname, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Lith_PlayerUpdateStats
|
|
//
|
|
stkcall void Lith_PlayerUpdateStats(struct player *p)
|
|
{
|
|
fixed boost = 1 + p->jumpboost;
|
|
|
|
if(p->frozen != p->old.frozen)
|
|
ACS_SetPlayerProperty(0, p->frozen > 0, PROP_TOTALLYFROZEN);
|
|
|
|
if(p->speedmul != p->old.speedmul)
|
|
ACS_SetActorPropertyFixed(0, APROP_Speed, 0.7 + p->speedmul);
|
|
|
|
if(p->jumpboost != p->old.jumpboost)
|
|
ACS_SetActorPropertyFixed(0, APROP_JumpZ, p->jumpheight * boost);
|
|
}
|
|
|
|
// EOF
|