marrub
/
Lithia
Archived
1
0
Fork 0
This repository has been archived on 2023-06-17. You can view files and clone it, but cannot push or open issues/pull-requests.
Lithia/source/Main/w_world.c

731 lines
16 KiB
C

// Copyright © 2016-2017 Graham Sanderson, all rights reserved.
#include "lith_common.h"
#include "lith_player.h"
#include "lith_world.h"
#include "lith_monster.h"
#include "lith_version.h"
#include <math.h>
#define InSecret \
(world.game == Game_Doom2 && (world.cluster == 9 || world.cluster == 10))
#define InHell \
(world.game == Game_Doom2 && world.cluster >= 8)
#define OnEarth \
(world.game == Game_Doom2 && world.cluster == 7)
// Extern Objects ------------------------------------------------------------|
__addrdef __mod_arr lmvar;
__addrdef __hub_arr lwvar;
bool lmvar mapinit;
int lmvar mapid;
worldinfo_t world = {.apiversion = Lith_APIVersion};
payoutinfo_t payout;
// Static Objects ------------------------------------------------------------|
static bool lmvar rain_chk;
static fixed lmvar rain_px;
static fixed lmvar rain_py;
static int lmvar rain_dist;
static bool reopen;
static bool dorain;
// Extern Functions ----------------------------------------------------------|
script acs void Lith_SpawnBosses(i96 sum, bool force);
//
// Lith_GetWorldExtern
//
worldinfo_t *Lith_GetWorldExtern(void)
{
return &world;
}
//
// Lith_FreezeTime
//
stkcall void Lith_FreezeTime(bool on)
{
static int lmvar frozen;
if(on)
{
if(!frozen++)
{
Lith_ForPlayer()
{
p->frozen++;
p->setVel(0, 0, 0);
}
Lith_ForPlayer()
{
Lith_GiveActorInventory(p->tid, "Lith_TimeHax", 1);
Lith_GiveActorInventory(p->tid, "Lith_TimeHax2", 1);
break;
}
}
}
else
{
if(!--frozen)
{
Lith_ForPlayer() p->frozen--;
Lith_ForPlayer()
{
Lith_TakeActorInventory(p->tid, "PowerTimeFreezer", 1);
Lith_TakeActorInventory(p->tid, "Lith_TimeHax2", 1);
break;
}
}
}
}
//
// Lith_BeginAngles
//
stkcall void Lith_BeginAngles(int x, int y)
{
world.a_cur = 0;
for(int i = 0; i < countof(world.a_angles); i++)
{
world.a_angles[i].ang = 0;
world.a_angles[i].dst = 0;
}
world.a_x = x;
world.a_y = y;
}
//
// Lith_AddAngle
//
stkcall fixed Lith_AddAngle(int x, int y)
{
if(world.a_cur >= countof(world.a_angles))
return 0;
struct polar *p = &world.a_angles[world.a_cur++];
*p = ctopol(x - world.a_x, y - world.a_y);
return p->ang;
}
//
// Lith_AddAngleScript
//
script acs address("Lith_AddAngle") void Lith_AddAngleScript(int x, int y)
{
Lith_AddAngle(x, y);
}
//
// Lith_CanonTime
//
__str Lith_CanonTime(int type)
{
int seconds = 53 + (world.ticks / 35);
int minutes = 30 + (seconds / 60);
int hours = 14 + (minutes / 60);
int days = 25 + (hours / 24); // pls
switch(type)
{
case CANONTIME_FULL:
return StrParam("%0.2i:%0.2i:%0.2i %i-7-1649",
hours % 24, minutes % 60, seconds % 60, days);
case CANONTIME_SHORT:
return StrParam("%0.2i:%0.2i %i-7-49",
hours % 24, minutes % 60, days);
case CANONTIME_DATE:
return StrParam("%i-7-1649", days);
}
}
//
// Lith_UniqueID
//
int Lith_UniqueID(int tid)
{
int pn;
// Negative values are for players.
if((pn = Lith_GetPlayerNumber(tid)) != -1)
return -(pn + 1);
// If we already have a unique identifier, return that.
int id = Lith_CheckActorInventory(tid, "Lith_UniqueID");
// Otherwise we have to give a new unique identifier.
if(id == 0)
Lith_GiveActorInventory(tid, "Lith_UniqueID", id = ++mapid);
return id;
}
//
// Lith_EmitScore
//
script acs void Lith_EmitScore(int amount)
{
Lith_GiveAllScore(amount, false);
}
//
// Lith_EmitEXP
//
script acs void Lith_EmitEXP(int amount)
{
Lith_GiveAllEXP(amount);
}
//
// Lith_MakeSerious
//
script acs void Lith_MakeSerious()
{
ACS_SetActorProperty(0, APROP_RenderStyle, STYLE_None);
ACS_SetActorPropertyString(0, APROP_ActiveSound, "silence");
ACS_SetActorPropertyString(0, APROP_DeathSound, "silence");
ACS_SetActorPropertyString(0, APROP_PainSound, "silence");
}
//
// LPData
//
script acs int LPData(int info, int permutation, bool target)
{
if(target) ACS_SetActivatorToTarget(0);
withplayer(LocalPlayer)
switch(info)
{
case pdata_upgrade: return p->getUpgrActive(permutation);
case pdata_buttons: return p->buttons;
case pdata_rifle_firemode: return p->riflefiremode;
case pdata_has_sigil: return p->sigil.acquired;
case pdata_weapon_zoom: return bitsk(p->getCVarK("lith_weapons_zoomfactor"));
case pdata_pclass: return p->pclass;
}
return 0;
}
//
// LWData
//
script acs int LWData(int info)
{
switch(info)
{
case wdata_bossspawned: return world.bossspawned;
case wdata_enemycheck: return world.enemycheck;
case wdata_ptid: Lith_ForPlayer() return p->tid;
case wdata_pclass: Lith_ForPlayer() return p->pclass;
case wdata_magdrops: Lith_ForPlayer()
return p->getCVarI("lith_weapons_magdrops");
}
return 0;
}
//
// Lith_RainDropSpawn
//
script acs void Lith_RainDropSpawn()
{
if(rain_chk)
{
int dist =
mag2i(ACS_GetActorX(0) - rain_px, ACS_GetActorY(0) - rain_py);
if(dist < rain_dist)
rain_dist = dist;
}
}
// Static Functions ----------------------------------------------------------|
//
// DoRain
//
script static void DoRain()
{
// Doesn't work in multiplayer, sorry!
if(ACS_PlayerCount() > 1)
return;
dorain = true;
struct player *p = &players[0];
p->setActivator();
ACS_PlaySound(p->weathertid, "amb/wind", CHAN_BODY, 0.001, true, ATTN_NONE);
ACS_PlaySound(p->weathertid, "amb/rain", CHAN_VOICE, 0.001, true, ATTN_NONE);
fixed skydist, curskydist = 1;
for(;;)
{
if((rain_chk = !ACS_CheckActorCeilingTexture(0, "F_SKY1")))
{
rain_dist = 1024;
rain_px = p->x;
rain_py = p->y;
}
else
InvTake("Lith_SMGHeat", 1);
if((InHell || InSecret) && !world.islithmap)
ACS_GiveActorInventory(p->tid, "Lith_SpawnBloodRain", 1);
else
ACS_GiveActorInventory(p->tid, "Lith_SpawnRain", 1);
ACS_Delay(1);
if(rain_chk)
{
skydist = rain_dist / 1024.0;
skydist = minmax(skydist, 0, 1);
}
else
skydist = 0;
curskydist = lerpk(curskydist, skydist, 0.035);
ACS_SoundVolume(p->weathertid, CHAN_BODY, 1 - curskydist);
ACS_SoundVolume(p->weathertid, CHAN_VOICE, 1 - curskydist);
}
}
//
// DoPayout
//
static void DoPayout(void)
{
fixed64 taxpct = ACS_RandomFixed(0, 4 / 100.0);
#define GenPay(name) \
if(payout.name##max) \
{ \
payout.name##pct = (payout.name##num / (fixed64)payout.name##max) * 100; \
payout.name##scr = payout.name##pct * 600; \
}
GenPay(kill)
GenPay(item)
#undef GenPay
payout.total = payout.killscr + payout.itemscr;
payout.total -= payout.tax = payout.total * taxpct;
Lith_ForPlayer()
{
script extern void Lith_PlayerPayout(struct player *p);
Lith_PlayerPayout(p);
}
payout = (payoutinfo_t){};
}
//
// CheckEnemyCompat
//
script static void CheckEnemyCompat(void)
{
if(ACS_GetCVar("sv_nomonsters") || world.enemycheck)
return;
int tid;
if(ACS_SpawnForced("ZombieMan", 0, 0, 0, tid = ACS_UniqueTID(), 0))
{
ACS_SetActivator(tid);
InvGive("Lith_EnemyChecker", 1);
__str cl = ACS_GetActorClass(0);
LogDebug(log_dev, "Enemy check on %S", cl);
if(strstr_str(cl, "Lith_") || ACS_StrCmp(cl, "RLFormer", 8) == 0)
world.enemycompat = true;
if(world.enemycompat) LogDebug(log_dev, "Enemies are \Cdcompatible");
else LogDebug(log_dev, "Enemies are \Cgnot compatible");
world.enemycheck = true;
ACS_Thing_Remove(0);
}
}
//
// SpawnBoss
//
script static void SpawnBoss()
{
ACS_Delay(1); // Delay another tic for monster spawners.
Lith_ForPlayer() {
Lith_SpawnBosses(p->scoresum, false);
break;
}
}
//
// GetDebugInfo
//
static void GetDebugInfo(void)
{
bool all = ACS_GetCVar("__lith_debug_all");
world.dbgLevel = ACS_GetCVar("__lith_debug_level");
world.dbgItems = all || ACS_GetCVar("__lith_debug_items");
world.dbgBIP = all || ACS_GetCVar("__lith_debug_bip");
world.dbgScore = all || ACS_GetCVar("__lith_debug_score");
world.dbgUpgr = all || ACS_GetCVar("__lith_debug_upgrades");
world.dbgSave = all || ACS_GetCVar("__lith_debug_save");
world.dbgNoMon = ACS_GetCVar("__lith_debug_nomonsters");
}
//
// CheckModCompat
//
static void CheckModCompat(void)
{
int tid;
if((world.legendoom = ACS_SpawnForced("LDLegendaryMonsterMarker", 0, 0, 0, tid = ACS_UniqueTID(), 0))) ACS_Thing_Remove(tid);
world.drlamonsters = ACS_GetCVar("DRLA_is_using_monsters");
}
//
// UpdateGame
//
static void UpdateGame(void)
{
#define Update(n) \
if(ACS_GetCVarFixed("__lith_version") < n) \
__with(ACS_SetCVarFixed("__lith_version", n);)
Update(15.1) ACS_SetCVarFixed("lith_sv_scoremul", 1.25); // 2.0=>1.25
Update(15.2) ACS_SetCVar("lith_sv_difficulty", 10); // 1=>10
Update(16.0)
Lith_ForPlayer() p->setCVarK("lith_player_footstepvol", 0.2); // 1.0=>0.2
#undef Update
}
//
// GSInit
//
static void GSInit(void)
{
extern void Lith_GInit_Shop(void);
extern void Lith_GSReinit_Upgrade(void);
extern void Lith_GSInit_Upgrade(void);
extern void Lith_GSInit_Weapon(void);
extern void Lith_GSInit_Dialogue(void);
extern void Lith_InstallCBIItem(int num);
LogDebug(log_dev, "GINIT RUNNING");
CheckModCompat();
UpdateGame();
GetDebugInfo();
Lith_GInit_Shop();
if(!world.gsinit)
{
LogDebug(log_dev, "GSINIT RUNNING");
Lith_GSInit_Upgrade();
Lith_GSInit_Weapon();
Lith_GSInit_Dialogue();
CheckEnemyCompat();
world.game = ACS_GetCVar("__lith_game");
world.singleplayer = ACS_GameType() == GAME_SINGLE_PLAYER;
world.cbiperf = 10;
if(ACS_GetCVar("lith_sv_nobosses") || world.dbgItems)
for(int i = 0; i < cupg_max; i++)
Lith_InstallCBIItem(i);
world.gsinit = true;
}
else
Lith_GSReinit_Upgrade();
}
//
// MInit
//
static void MInit(void)
{
LogDebug(log_dev, "MINIT RUNNING");
extern void Lith_LoadMapDialogue(void);
Lith_LoadMapDialogue();
world.islithmap = (world.mapnum & 0xFFFFFC00) == 0x01202000;
// Init a random seed from the map.
world.mapseed = ACS_Random(0, 0x7FFFFFFF);
// Init global score multiplier per-map.
world.scoremul = round(ACS_GetCVarFixed("lith_sv_scoremul") * 10) / 10;
// Give players some extra score if they're playing on extra hard or above.
if(ACS_GameSkill() >= skill_extrahard)
world.scoremul += 0.15;
// Set the air control because ZDoom's default sucks.
ACS_SetAirControl(0.77);
// Set up translations.
for(int i = 0; i < 8; i++)
{
static struct {int r,g,b;} const trs[8] = {
{0xF5,0x22,0x22},
{0xF5,0x22,0xC4},
{0xC0,0x22,0xF5},
{0x50,0x22,0xF5},
{0x22,0xF5,0xF5},
{0x22,0xF5,0x8C},
{0xF5,0xF5,0x22},
{0xF5,0xB2,0x22},
};
ACS_CreateTranslationStart(42470 + i);
ACS_CreateTranslationRGB(80, 111, trs[i].r, trs[i].g, trs[i].b,
trs[i].r/4, trs[i].g/4, trs[i].b/4);
ACS_CreateTranslationEnd();
}
}
//
// MSInit
//
static void MSInit(void)
{
LogDebug(log_dev, "MSINIT RUNNING");
payout.killmax += world.mapkillmax;
payout.itemmax += world.mapitemmax;
// Line 1888300 is used as a control line for mod features.
// Check for if rain should be used.
if(!ACS_GetLineUDMFInt(1888300, "user_lith_norain") &&
(ACS_GetCVar("lith_sv_rain") || ACS_GetLineUDMFInt(1888300, "user_lith_userain")))
DoRain();
}
//
// WSInit
//
static void WSInit(void)
{
LogDebug(log_dev, "WSINIT RUNNING");
dmonid = 0;
world.bossspawned = false;
if(world.unloaded)
world.mapscleared++;
if(ACS_GetCVar("lith_sv_sky") && !world.islithmap)
{
if(InHell)
{
ACS_ChangeSky("LITHSKRD", "LITHSKRD");
ACS_SetSkyScrollSpeed(1, 0.01);
}
else if(OnEarth)
ACS_ChangeSky("LITHSKDE", "LITHSKDE");
else
ACS_ChangeSky("LITHSKS1", "LITHSKS1");
}
}
//
// WInit
//
static void WInit(void)
{
LogDebug(log_dev, "WINIT RUNNING");
if(!ACS_GetCVar("lith_sv_nobosses"))
SpawnBoss();
// Payout, which is not done on the first map.
if(world.mapscleared != 0)
DoPayout();
// Cluster messages.
#define Message(cmp, n, name) \
if(world.cluster cmp && !msgs[n]) { \
Lith_ForPlayer() \
p->deliverMail(name); \
msgs[n] = true; \
} else ((void)0)
static bool msgs[5];
if(world.game == Game_Doom2)
{
Message(>= 6, 0, "Cluster1");
Message(>= 7, 1, "Cluster2");
Message(== 8, 2, "Cluster3");
Message(== 9, 3, "Secret1");
Message(== 10, 4, "Secret2");
}
}
// Scripts -------------------------------------------------------------------|
//
// Lith_World
//
script type("open") static void Lith_World(void)
{
begin:
if(ACS_GameType() == GAME_TITLE_MAP) {
script extern void Lith_Title(void);
Lith_Title();
return;
}
LogDebug(log_dev, "LITH OPEN");
if(world.mapnum == 1911777)
{
ACS_Exit_Normal(0);
return;
}
dbgnotenum = 0;
ACS_Delay(1);
GSInit(); // Init global state.
MInit(); // Map init.
// World-static pre-player init.
bool doworldinit = false;
if(ACS_Timer() <= 2)
{
WSInit();
doworldinit = true;
}
world.unloaded = false; // World unloaded flag can be reset now.
mapinit = true; // Sigil for when Lith_PlayerEntry can run.
ACS_Delay(1); // Delay so players get initialized.
// World-static post-player init.
if(doworldinit)
WInit();
// Map-static post-world init.
MSInit();
// Main loop.
int prevsecrets = 0;
int prevkills = 0;
int previtems = 0;
int missionkill = 0;
int missionprc = 0;
for(;;)
{
if(reopen) {
mapinit = reopen = false;
goto begin;
}
if(world.ticks > 67 * 35 * 60 * 60 && !world.islithmap)
ACS_Teleport_NewMap(1911777, 0, 0);
int secrets = world.mapsecrets;
int kills = world.mapkills;
int items = world.mapitems;
if(secrets > prevsecrets) {
int delta = secrets - prevsecrets;
Lith_GiveAllScore(9000 * delta, true);
world.secretsfound += delta;
}
if(kills > prevkills) payout.killnum += kills - prevkills;
if(items > previtems) payout.itemnum += items - previtems;
prevsecrets = secrets;
prevkills = kills;
previtems = items;
if(world.enemycheck && !world.dbgNoMon) {
extern void DmonDebugInfo(void);
ACS_SpawnForced("Lith_MonsterInfoEmitter", 0, 0, 0);
DmonDebugInfo();
}
if(ACS_Timer() % 5 == 0 && missionkill < kills)
{
if(++missionprc >= 150) {
Lith_SpawnBosses(0, true);
missionprc = 0;
}
missionkill = kills;
}
DebugStat("mission%%: %i\n", missionprc);
ACS_Delay(1);
dbgstatnum = 0;
world.ticks++;
if(world.autosave && world.ticks % (35 * 60 * world.autosave) == 0)
ACS_Autosave();
}
}
//
// Lith_WorldReopen
//
script acs void Lith_WorldReopen(void)
{
reopen = true;
}
//
// Lith_WorldUnload
//
script type("unloading") static void Lith_WorldUnload(void)
{
extern void Lith_InstallSpawnedCBIItems(void);
world.unloaded = true;
LogDebug(log_dev, "WORLD UNLOADED");
Lith_InstallSpawnedCBIItems();
Lith_ForPlayer() {
p->setActivator();
Lith_PlayerDeinitUpgrades(p);
p->closeGUI();
Lith_PlayerUpdateStats(p);
}
}
// EOF