quake-rerelease-qc/quakec_mg1/lights.qc

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);
};