Truevision Targa - .tga
Tagged Image File Format - .tif
Gamecube Texture - .tpl
Unreal Texture - .utx
Quake 2 Texture - .wal
Valve Texture Format - .vtf
Oh, look at that, one can potentially implement Source texture support in a HL mod. GLint myNewTexture;
... // after some TGA parsing with DevIL and texture creation via gl functions
texture->gl_texturenum = myNewTexture;
As for resizing, i.e. updating the original texture, we'll see. I am definitely thinking of writing some tutorials about this.water
or !
, but I'm thinking of potential applications of this elsewhere too."Now i'm getting a "could not load library" ctd."Are you trying to run it on WON Half-Life or Steam Half-Life? If you got any pre-2013 Half-Life version, that ain't gonna work.
"Compiles but produces no .dll"Explain. How are you compiling? What are you using to compile? Are there any errors in the compile log? Etc.
// Raise monster off the floor one unit, then drop to floor
if ( pev->movetype != MOVETYPE_FLY && !FBitSet( pev->spawnflags, SF_MONSTER_FALL_TO_GROUND ) )
{
pev->origin.z += 1;
DROP_TO_FLOOR ( ENT(pev) );
// Try to move the monster to make sure it's not stuck in a brush.
if (!WALK_MOVE ( ENT(pev), 0, 0, WALKMOVE_NORMAL ) )
{
ALERT(at_error, "Monster %s stuck in wall--level design error", STRING(pev->classname));
pev->effects = EF_BRIGHTFIELD;
}
}
Around line 2085, in monsters.cpppev->effects = EF_BRIGHTFIELD;
and you should get rid of the yellow aura."using the Spirit engine"...
"engine"URBY!
"You are correctly: Blender is brilliantly. But Unity with Probuilder or CSG Shake too."I don't like Unity.
Mushrooms are nice. They're especially good on pizza. uwuWe're gonna have a fight about the mushrooms, thoughI'm afraid I'm gonna have to double down on this one. Mushrooms can fuck off forever.
studiohdr_t
pointer (header
in the example code), we can access the bodygroup, then the submodel of said bodygroup, and then the vertices of the submodel.
void StudioExampleStuff( studiohdr_t* header, mstudiobodyparts_t* bodygroup, mstudiomodel_t* submodel, Vector& vert, int cntr )
{
static float flWave = 0.0;
flWave += M_PI/240.0;
if ( flWave > M_PI )
flWave *= -1;
if ( header )
{
bodygroup = (mstudiobodyparts_t*)((byte*)header + header->bodypartindex);
if ( bodygroup )
{
submodel = (mstudiomodel_t*)((byte*)header + bodygroup->modelindex);
if ( submodel )
{
for ( int i = 0; i < submodel->numverts; i++ )
{
float* vertFl = (float*)((byte*)header + submodel->vertindex) + i;
float indexWave = (float)i / (float)submodel->numverts;
float indexOffset = (indexWave * 2.0) - 1.0;
indexWave *= 4.0 * M_PI;
vertFl[ 2 ] += sin(flWave + indexWave) * 0.004 * (indexOffset*2.0) + sin(flWave*4.0 + indexWave)*0.01;
}
}
}
}
}
So, they aren't read-only.models/something.mdl
and you change the vertices on it, you will change it on them all. Maybe some mods will have a use for this, where for example, if the player damages one object and its vertices bend, it affects basically every other object in the map.539
1330
4 0 123 (28672.000000 12288.000000 0.000000) (32768.000000 12288.000000 0.000000) (32768.000000 12288.000000 16384.000000) (28672.000000 12288.000000 16384.000000)
4 1 122 (28672.000000 12288.000000 16384.000000) (28672.000000 12288.000000 20480.000000) (20480.000000 12288.000000 20480.000000) (20480.000000 12288.000000 16384.000000)
4 1 28 (20480.000000 12288.000000 16384.000000) (20480.000000 12288.000000 20480.000000) (20480.000000 28672.000000 20480.000000) (20480.000000 28672.000000 16384.000000)
4 2 10 (26624.000000 28672.000000 1419.636364) (26624.000000 28672.000000 16384.000000) (26624.000000 30208.000000 16384.000000) (26624.000000 30208.000000 1280.000000)
mapname_viscache.prt:
539
1330
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
4 0 123 (28672.000000 12288.000000 0.000000) (32768.000000 12288.000000 0.000000) (32768.000000 12288.000000 16384.000000) (28672.000000 12288.000000 16384.000000)
4 1 122 (28672.000000 12288.000000 16384.000000) (28672.000000 12288.000000 20480.000000) (20480.000000 12288.000000 20480.000000) (20480.000000 12288.000000 16384.000000)
4 1 28 (20480.000000 12288.000000 16384.000000) (20480.000000 12288.000000 20480.000000) (20480.000000 28672.000000 20480.000000) (20480.000000 28672.000000 16384.000000)
4 2 10 (26624.000000 28672.000000 1419.636364) (26624.000000 28672.000000 16384.000000) (26624.000000 30208.000000 16384.000000) (26624.000000 30208.000000 1280.000000)
539 stands for the number of visleaves, 1330 is the number of visportals.BOLIDHINT
works. BOLIDHINT
is apparently the same as SOLIDHINT
. However, now let's look at the clipnode counts:NULL
- 7148 clipnodesBEVEL
- 4318 clipnodesSOLIDHINT
- 7158 clipnodesBOLIDHINT
- 4122 clipnodesNULL
and SOLIDHINT
aren't supposed to create the same number of clipnodes, considering the fact that SOLIDHINT
generally produces less wpolys. Keep that in mind.SOLIDHINT
and BOLIDHINT
compared to the other two."I remember trying to get the texture data for models or sprites but couldn't find a way."At that point I'd probably do a MDL and SPR parser, if I just wanted to read the texture data. It'd be easy too, there are several open-source apps doing that stuff, so, we can use it as a reference / steal the code.
if ( FClassnameIs( pEnemy->pev, "monster_something" ) )
This will work if the monster has already chosen an enemy and is about to attack it."entities would be read only but a lot of the others should be modifiable."Yes, but what do you exactly mean by "entities"? cl_entity_t, sending the modified data back to the server etc.?
char* entities;
for ( int i = 0; i < 120; i++ )
{
cl_entity_t *pEnt = gEngfuncs.GetEntityByIndex( i );
// this doesn't guarantee that the entity exists or doesn't exist
// but we needed something quick and dirty
if ( (pEnt->curstate.origin != Vector(0,0,0)) || i == 0 )
{
if ( pEnt->model )
gEngfuncs.Con_Printf( "\nEntindex %i - model->entities %s", i, pEnt->model->entities);
else
gEngfuncs.Con_Printf( "\nEntindex %i - no model here", i );
}
else
{
gEngfuncs.Con_Printf( "\nEntindex %i - no entity here", i );
}
}
And it looks like vertex manipulation just isn't gonna work on studio models. Can't even read, let alone write to it, LOL. It looks like model_t only provides all data for brush models. For sprites and studio models, it doesn't do much.BOGUS_RANGE
macro refers to g_iMaxEntityRange
instead of a hardcoded value. g_iMaxEntityRange
is, of course, set by the -maxentrange
param in HLCSG.For example, if you have two light entities with identical names and one is checked with "start dark", both the lights would start dark.This also makes sense to an extent, however, this is likely done on the compiler level. HLRAD probably works like a state machine when it's dealing with flags of lights. It treats one 'name' as a single entity, but radiates light for each of them individually. It associates the 'start dark' flag with that one name because one of the entities happens to have it.
"Hm, I wonder why it was software only."Because of graphics programming.
if ( texturePalette < 224 )
color = textureColor * lightmap;
else
color = textureColor;
This is the kind of 'control' that I'm talking about. We're basically modifying the texture before uploading it to draw the current wpoly. But, this isn't my area yet and I'm likely incorrect."And with the map coordinate bounds I thought that server to client messages 1 through 64 (or whatever is handled by the engine) might have clamped coordinates - is that right?"Well, it seems so. Any TE_ message has clamped coordinates. Hence explosions end up spawning at 0,0,0 if they're outside of the +-4096 range. :/
"Or you could use dynamic lights but I haven't played with them enough to know their limitations."God no. Dlights are horrible for performance. And there can't be many of them either at the same time.
"there is lighting data in the model_s struct in client.dll but I suspect it's read only (maybe?)"Speaking of model_s, after some brief experimentation with reading vertices from the map model (one way was getting the worldspawn entity with
gEngfuncs.GetEntityByIndex(0)
and the other was IEngineStudio.GetModelByIndex(1)
), I've come to a conclusion that some things are surprisingly not just read-only.
m_pWorld = gEngfuncs.GetEntityByIndex( 0 );
if ( m_pWorld )
{
m_pWorld->model->leafs[ 0 ].firstmarksurface[ 0 ]->polys[ 0 ].verts[ 0 ][ 2 ] += m_flWave;
// etc. etc.
This here is a really quick test to see if I can manipulate the Z position of the first vertex, of the first polygon, of the first marksurface, of the first leaf. // first vertex of the first edge in the map model
// NOT the same as pModel->vertexes[0].position.z
pModel->vertexes[ pModel->edges[ 0 ].v[ 0 ] ].position.z += m_flWave;
or something like that, it wouldn't change anything, at least visually. This seems like pretty dangerous stuff, to be honest.if ( m_pWorld )
{
msurface_t* surf = m_pWorld->model->leafs[ 0 ].firstmarksurface[ 0 ];
surf->polys[ 0 ].verts[ 0 ][ 2 ] += m_flWave;
for ( int i = 0; i < 64*64; i++ )
{
surf->samples[ i ].r += 1;
if ( surf->samples[ i ].r >= 255 )
surf->samples[ i ].r = 0;
}
}
"samples" is allegedly the actual lightmap data of a surface. delta.lst
file. In a nutshell, it defines how many bits are used to carry entity data (position, angles, velocity etc.) and at what precision. More about it can be found in NetworkEntity.doc inside the HL SDK. The format for delta.lst is straightforward. The only lines that require additional explanation are the actual definitions, which take the form:So, what does this mean? Imagine the player is located at 2050 units on the X axis. This gets multiplied by 128, and it's 262400. So, the engine is gonna send this number to us. We receive it, then divide by 128, and we get 2050. For example, if we were located at 0.5 units on the X axis, which is perfectly possible, the engine would send 64 to us. We divide by 128, and we get 0.5 again.
DEFINE_DELTA( origin[0], DT_SIGNED | DT_FLOAT, 21, 128.0 ),
This definition specifies that the x – array index [0] -- coordinate of the field named origin ( a three component vector field in this data structure ) represents a signed floating point value. When sending this value over the network, the value should be multiplied by 128.0, converted to an integer, and sent in 21 bits ( 20 for the value, 1 for the sign bit ). The receiving side will know to cast it to a floating point value and divide by 128.0 to obtain the final value on the remote side.
-maxentrange
, defaults to 32768 units) that will let you set your own world boundaries, so for example, if an entity goes outside of +-65k units, it warns you about it. "some Fiat"Close, now take Fiat's home and go approximately 10° to the east. Maybe a degree or two to the south as well.
"BTW, you are using Blender, right?"Yeah, I'm using Blender.
"They must get close to the trolley guys, as a bodyguard."Still doesn't tell me what exactly the movement is supposed to be.
EMIT_SOUND
is for the serverside.gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/pl_gun3.wav", gEngfuncs.pfnRandomFloat(0.92, 1.0), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
Or a much simpler version, which can be found in `cl_util.h`:
inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); }
Example usage:
PlaySound("common/wpn_moveselect.wav", 1);
As for the gunners following the trolleys, I dunno, how do you exactly mean following them?if (name[0] == '!') //optimized -- don't check for current unless it's liquid (KGP)
{
if (!strncasecmp(name, "!cur_90", 7))
return CONTENTS_CURRENT_90;
if (!strncasecmp(name, "!cur_0", 6))
return CONTENTS_CURRENT_0;
if (!strncasecmp(name, "!cur_270", 8))
return CONTENTS_CURRENT_270;
if (!strncasecmp(name, "!cur_180", 8))
return CONTENTS_CURRENT_180;
if (!strncasecmp(name, "!cur_up", 7))
return CONTENTS_CURRENT_UP;
if (!strncasecmp(name, "!cur_dwn", 8))
return CONTENTS_CURRENT_DOWN;
Location: VHLT v34, HLCSG, brush.cpp, TextureContents()!cur_90_alternate
will also work.