mirror of
https://github.com/id-Software/quake-rerelease-qc.git
synced 2024-11-25 05:31:13 +00:00
409 lines
9.7 KiB
C++
409 lines
9.7 KiB
C++
|
/* Copyright (C) 1996-2022 id Software LLC
|
||
|
|
||
|
This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
||
|
See file, 'COPYING', for details.
|
||
|
*/
|
||
|
|
||
|
const string LightStyles[] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
|
||
|
const float LightStyles_MAX = LightStyles.length - 1;
|
||
|
const string LightStylesHalf[] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"};
|
||
|
const float LightStylesHalf_MAX = LightStylesHalf.length - 1;
|
||
|
|
||
|
|
||
|
//============================================================================
|
||
|
// No special functionality, just to hold dynamic shadowcasting lights for KEX
|
||
|
const float DYNAMICLIGHT_NOT_IN_COOP = 1;
|
||
|
void dynamiclight()
|
||
|
{
|
||
|
if(coop && self.spawnflags & DYNAMICLIGHT_NOT_IN_COOP)
|
||
|
{
|
||
|
remove(self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
|
||
|
void InitLightStyles()
|
||
|
{
|
||
|
//
|
||
|
// Setup light animation tables. 'a' is total darkness, 'z' is maxbright.
|
||
|
//
|
||
|
|
||
|
// 0 normal
|
||
|
lightstyle(0, "m");
|
||
|
|
||
|
// 1 FLICKER (first variety)
|
||
|
lightstyle(1, "mmnmmommommnonmmonqnmmo");
|
||
|
|
||
|
// 2 SLOW STRONG PULSE
|
||
|
lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
|
||
|
|
||
|
// 3 CANDLE (first variety)
|
||
|
lightstyle(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
|
||
|
|
||
|
// 4 FAST STROBE
|
||
|
lightstyle(4, "ma");
|
||
|
|
||
|
// 5 GENTLE PULSE 1
|
||
|
lightstyle(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
|
||
|
|
||
|
// 6 FLICKER (second variety)
|
||
|
lightstyle(6, "nmonqnmomnmomomno");
|
||
|
|
||
|
// 7 CANDLE (second variety)
|
||
|
lightstyle(7, "mmmaaaabcdefgmmmmaaaammmaamm");
|
||
|
|
||
|
// 8 CANDLE (third variety)
|
||
|
lightstyle(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
|
||
|
|
||
|
// 9 SLOW STROBE (fourth variety)
|
||
|
lightstyle(9, "aaaaaaaazzzzzzzz");
|
||
|
|
||
|
// 10 FLUORESCENT FLICKER
|
||
|
lightstyle(10, "mmamammmmammamamaaamammma");
|
||
|
|
||
|
// 11 SLOW PULSE NOT FADE TO BLACK
|
||
|
lightstyle(11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
|
||
|
|
||
|
// New styles under here if needed:
|
||
|
|
||
|
// styles 32-62 are assigned by the light program for switchable lights
|
||
|
|
||
|
// 63 testing
|
||
|
lightstyle(63, "a");
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
|
||
|
string LightFractionToStyle(float frac)
|
||
|
{
|
||
|
if(frac <= 0) return LightStyles[0];
|
||
|
if(frac >= 1) return LightStyles[LightStyles_MAX];
|
||
|
frac*= LightStyles.length;
|
||
|
frac = floor(frac);
|
||
|
return LightStyles[frac];
|
||
|
}
|
||
|
|
||
|
string LightFractionToStyleHalf(float frac)
|
||
|
{
|
||
|
if(frac <= 0) return LightStylesHalf[0];
|
||
|
if(frac >= 1) return LightStylesHalf[LightStylesHalf_MAX];
|
||
|
frac*= LightStylesHalf.length;
|
||
|
frac = floor(frac);
|
||
|
return LightStylesHalf[frac];
|
||
|
}
|
||
|
|
||
|
enum : int
|
||
|
{
|
||
|
LightRampStateOff,
|
||
|
LightRampStateFadeUp,
|
||
|
LightRampStateOn,
|
||
|
LightRampStateFadeDown
|
||
|
};
|
||
|
|
||
|
float LIGHTRAMP_FULLRANGE = 1;
|
||
|
|
||
|
void target_lightramp_setlight(float style, float frac)
|
||
|
{
|
||
|
if(self.spawnflags & LIGHTRAMP_FULLRANGE)
|
||
|
lightstyle(style, LightFractionToStyle(frac));
|
||
|
else
|
||
|
lightstyle(style, LightFractionToStyleHalf(frac));
|
||
|
}
|
||
|
|
||
|
void target_lightramp_tick(float dt)
|
||
|
{
|
||
|
float diff = dt * self.delay;
|
||
|
switch(self.state)
|
||
|
{
|
||
|
case LightRampStateFadeDown:
|
||
|
self.cnt-= diff;
|
||
|
break;
|
||
|
|
||
|
case LightRampStateFadeUp:
|
||
|
self.cnt+= diff;
|
||
|
break;
|
||
|
}
|
||
|
target_lightramp_setlight(self.owner.style, self.cnt);
|
||
|
if(self.cnt >= 1)
|
||
|
{
|
||
|
self.cnt = 1;
|
||
|
self.state = LightRampStateOn;
|
||
|
RemoveFrameTickEntity(self);
|
||
|
}
|
||
|
if(self.cnt <= 0)
|
||
|
{
|
||
|
self.cnt = 0;
|
||
|
self.state = LightRampStateOff;
|
||
|
RemoveFrameTickEntity(self);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void target_lightramp_use()
|
||
|
{
|
||
|
switch(self.state)
|
||
|
{
|
||
|
case LightRampStateFadeDown:
|
||
|
self.state = LightRampStateFadeUp;
|
||
|
return;
|
||
|
|
||
|
case LightRampStateOff:
|
||
|
self.state = LightRampStateFadeUp;
|
||
|
RegisterFrameTickEntity(self);
|
||
|
return;
|
||
|
|
||
|
case LightRampStateOn:
|
||
|
self.state = LightRampStateFadeDown;
|
||
|
RegisterFrameTickEntity(self);
|
||
|
return;
|
||
|
|
||
|
case LightRampStateFadeUp:
|
||
|
self.state = LightRampStateFadeDown;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
void target_lightramp_init()
|
||
|
{
|
||
|
self.think = SUB_Null;
|
||
|
if(!self.target) objerror("\n\ntarget_lightramp with no target.\n\n");
|
||
|
if(!self.targetname) objerror("\n\ntarget_lightramp with no targetname.\n\n");
|
||
|
|
||
|
self.owner = find(world, targetname, self.target);
|
||
|
if(!self.owner) objerror("\n\ntarget_lightramp with unmatched target.\n\n");
|
||
|
|
||
|
if(self.owner.spawnflags & START_OFF)
|
||
|
{
|
||
|
self.state = LightRampStateOff;
|
||
|
self.cnt = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
self.state = LightRampStateOn;
|
||
|
self.cnt = 1;
|
||
|
}
|
||
|
|
||
|
self.use = target_lightramp_use;
|
||
|
self.tick = target_lightramp_tick;
|
||
|
}
|
||
|
|
||
|
void target_lightramp()
|
||
|
{
|
||
|
|
||
|
if(!self.delay) self.delay = 1;
|
||
|
self.delay = 1 / self.delay;
|
||
|
|
||
|
self.think = target_lightramp_init;
|
||
|
self.nextthink = time + 0.1;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
|
||
|
const float LIGHT_TARGETNAME_IS_STYLE = 2;
|
||
|
|
||
|
void() light_use =
|
||
|
{
|
||
|
if (self.spawnflags & START_OFF)
|
||
|
{
|
||
|
lightstyle(self.style, "m");
|
||
|
self.spawnflags = self.spawnflags - START_OFF;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lightstyle(self.style, "a");
|
||
|
self.spawnflags = self.spawnflags + START_OFF;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
|
||
|
Non-displayed light.
|
||
|
Default light value is 300
|
||
|
Default style is 0
|
||
|
If targeted, it will toggle between on or off.
|
||
|
*/
|
||
|
void() light =
|
||
|
{
|
||
|
if (!self.targetname)
|
||
|
{ // inert light
|
||
|
remove(self);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (self.style >= 32)
|
||
|
{
|
||
|
if(self.spawnflags & LIGHT_TARGETNAME_IS_STYLE)
|
||
|
{
|
||
|
lightstyle(self.style, self.targetname);
|
||
|
remove(self);
|
||
|
return;
|
||
|
}
|
||
|
self.use = light_use;
|
||
|
if (self.spawnflags & START_OFF)
|
||
|
lightstyle(self.style, "a");
|
||
|
else
|
||
|
lightstyle(self.style, "m");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_fluoro (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
|
||
|
Non-displayed light.
|
||
|
Default light value is 300
|
||
|
Default style is 0
|
||
|
If targeted, it will toggle between on or off.
|
||
|
Makes steady fluorescent humming sound
|
||
|
*/
|
||
|
void() light_fluoro =
|
||
|
{
|
||
|
if (self.style >= 32)
|
||
|
{
|
||
|
self.use = light_use;
|
||
|
if (self.spawnflags & START_OFF)
|
||
|
lightstyle(self.style, "a");
|
||
|
else
|
||
|
lightstyle(self.style, "m");
|
||
|
}
|
||
|
|
||
|
precache_sound ("ambience/fl_hum1.wav");
|
||
|
ambientsound (self.origin, "ambience/fl_hum1.wav", 0.5, ATTN_STATIC);
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_fluorospark (0 1 0) (-8 -8 -8) (8 8 8)
|
||
|
Non-displayed light.
|
||
|
Default light value is 300
|
||
|
Default style is 10
|
||
|
Makes sparking, broken fluorescent sound
|
||
|
*/
|
||
|
void() light_fluorospark =
|
||
|
{
|
||
|
if (!self.style)
|
||
|
self.style = 10;
|
||
|
|
||
|
precache_sound ("ambience/buzz1.wav");
|
||
|
ambientsound (self.origin, "ambience/buzz1.wav", 0.5, ATTN_STATIC);
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_globe (0 1 0) (-8 -8 -8) (8 8 8)
|
||
|
Sphere globe light.
|
||
|
Default light value is 300
|
||
|
Default style is 0
|
||
|
*/
|
||
|
void() light_globe =
|
||
|
{
|
||
|
precache_model ("progs/s_light.spr");
|
||
|
setmodel (self, "progs/s_light.spr");
|
||
|
makestatic (self);
|
||
|
};
|
||
|
|
||
|
void() FireAmbient =
|
||
|
{
|
||
|
precache_sound ("ambience/fire1.wav");
|
||
|
// attenuate fast
|
||
|
ambientsound (self.origin, "ambience/fire1.wav", 0.5, ATTN_STATIC);
|
||
|
};
|
||
|
|
||
|
const float UPSIDEDOWN = 4;
|
||
|
|
||
|
/*QUAKED light_torch_small_walltorch (0 .5 0) (-10 -10 -20) (10 10 20)
|
||
|
Short wall torch
|
||
|
Default light value is 200
|
||
|
Default style is 0
|
||
|
*/
|
||
|
void() light_torch_small_walltorch =
|
||
|
{
|
||
|
precache_model ("progs/flame.mdl");
|
||
|
setmodel (self, "progs/flame.mdl");
|
||
|
|
||
|
if (self.spawnflags & UPSIDEDOWN)
|
||
|
self.angles = '180 0 0';
|
||
|
|
||
|
FireAmbient ();
|
||
|
makestatic (self);
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_flame_large_yellow (0 1 0) (-10 -10 -12) (12 12 18)
|
||
|
Large yellow flame ball
|
||
|
*/
|
||
|
void() light_flame_large_yellow =
|
||
|
{
|
||
|
precache_model ("progs/flame2.mdl");
|
||
|
setmodel (self, "progs/flame2.mdl");
|
||
|
self.frame = 1;
|
||
|
|
||
|
if (self.spawnflags & UPSIDEDOWN)
|
||
|
self.angles = '180 0 0';
|
||
|
|
||
|
FireAmbient ();
|
||
|
makestatic (self);
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_flame_small_yellow (0 1 0) (-8 -8 -8) (8 8 8) START_OFF
|
||
|
Small yellow flame ball
|
||
|
*/
|
||
|
void() light_flame_small_yellow =
|
||
|
{
|
||
|
precache_model ("progs/flame2.mdl");
|
||
|
setmodel (self, "progs/flame2.mdl");
|
||
|
|
||
|
if (self.spawnflags & UPSIDEDOWN)
|
||
|
self.angles = '180 0 0';
|
||
|
|
||
|
FireAmbient ();
|
||
|
makestatic (self);
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_flame_small_white (0 1 0) (-10 -10 -40) (10 10 40) START_OFF
|
||
|
Small white flame ball
|
||
|
*/
|
||
|
void() light_flame_small_white =
|
||
|
{
|
||
|
precache_model ("progs/flame2.mdl");
|
||
|
setmodel (self, "progs/flame2.mdl");
|
||
|
|
||
|
if (self.spawnflags & UPSIDEDOWN)
|
||
|
self.angles = '180 0 0';
|
||
|
|
||
|
FireAmbient ();
|
||
|
makestatic (self);
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_flame_gas (0 1 0) (-10 -10 -40) (10 10 40) START_OFF
|
||
|
Gas flare (spawns two entites)
|
||
|
*/
|
||
|
void() light_flame_gas =
|
||
|
{
|
||
|
precache_model ("progs/flame3.mdl");
|
||
|
setmodel (self, "progs/flame3.mdl");
|
||
|
self.alpha = 0.6;
|
||
|
|
||
|
entity s = spawn();
|
||
|
setorigin(s, self.origin);
|
||
|
setmodel (s, "progs/flame3.mdl");
|
||
|
s.alpha = 0.4;
|
||
|
s.frame = 1;
|
||
|
};
|
||
|
|
||
|
/*QUAKED light_candle (0 .5 0) (-4 -4 -10) (4 4 10)
|
||
|
Candle
|
||
|
Default light value is 200
|
||
|
Default style is 0
|
||
|
*/
|
||
|
void() light_candle =
|
||
|
{
|
||
|
precache_model ("progs/candle.mdl");
|
||
|
setmodel (self, "progs/candle.mdl");
|
||
|
makestatic (self);
|
||
|
};
|