Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - Sebastian
Videos & Screenshots / Extreme Racing
« on May 8th, 01:14 AM »
Who's the owner of this ? KL (vito told me)
It was fun to play there!



Extract the archive and rename it into ""

(so it will no longer have the server name)

Put the directory in

Bugs and Crashes / [not-a-bug] 2 custom generic.txd instead of one
« on April 11th, 02:57 PM »
This is not a bug, but it worths a mention.

So, if we want to use a custom generic.txd instead of VC's default, we can just place our "generic.txd" inside /store/maps/
But, if we gonna load custom objects which use generic.txd as a texture pack, we must place another copy of it inside /store/, so we end up having 2 exact same files, but in different locations... so more data to download.

It would be better to have it only once, and do both jobs.

PS: I also suggest a way for our /store/objects/.xmls to be able to load the default generic.txd, if there is no custom one, so custom objects will fit perfectly no matter what textures a player uses.
Client Scripting / About compiled scripts
« on March 15th, 01:17 AM »
Everything you need to know about compiled client-side scripts!

It is posible since rel004 2017-05-24 Update
Quote from Stormeus
Added support for loading precompiled client-side scripts (i.e. .cnut files). These must be compiled on a 32-bit Squirrel instance.

In order to make it work, you have 2 options:
(click to show/hide)
1. Multiple scriptfiles - you must give up on calling constants/enums from other files except the ones they are used in.

You are declaring const MAX_PLAYERS=50; in main.cnut and then later trying to call it from utils.cnut. The constant MAX_PLAYERS won't be recognized, and that's why it will throw the following error:
Code: [Select]
AN ERROR HAS OCCURRED [the index '<constant name>' does not exist]
Also, don't forget to use :: prefix when you call global variables from different scriptfiles.
(click to show/hide)
2. One BIG main file - merge all scriptfiles into one

Doing this way, you won't be needed to avoid constants/enums.
But, be aware of dofile/include functions. They will still call the files they are supposed to.
So I suggest you to create your own function, like I did, and just change a constant:

Code: [Select]
const wayLoadScripts = 0;
function include2( path )
          if( wayLoadScripts == 0 ) return 0;
          else include( path );

@DizzasTeR 's worthy mention:

to compile .nut into compiled .cnut (or whatever format you like)

When you use compiled scripts, you may notice the following warnings and error in debuglog.txt:
Code: [Select]
MSG: <filename> line = (1) column = (1) : error expression expected
Warning in CScriptFunctions::DoFile: (script/<filename>.cnut) expression expected
Warning in CScriptFunctions::DoFile: Attempting bytecode read of file.
Don't worry, it is not a problem. The client just tries to read the file as uncompiled first.

MSG: Scripts initialised.
Videos & Screenshots / The Last Station
« on March 12th, 02:02 AM »
Tutorials / [work-around fix] Custom Vehicles return no handling
« on March 8th, 12:59 PM »
If you have ever added a custom vehicle in your server, and later tried to edit it's handling, you know for sure that
Custom Vehicles return no handling data

This happens because server is not taking the info out of yourcars.7z, so it will always return 0 when tring to read some handling rule/data.
If you played long enough with handlings, you could notice that once you vehicle.SetHandlingData, then vehicle.GetHandlingData will return the value you just setted earlier.

So what this means? We must load the handling everytime we create a new vehicle, no ?

There is SetHandlingRule which sets the handling of the model and not the vehicle instance!
"Yeah, but we knew this already. What's the thing with it?!"
Well, here comes the magic. If you set it once, then all the vehicles with that model will get the wanted handling, and return the correct values whenever using GetHandlingRule( model, rule ) or vehicle.GetHandlingData( rule ).

(the work-around) Personally, I'm setting all the Handling Rules when server stars. This way, no matter when I want to create a new vehicle during the gameplay, it will get the presetted handlings by "default", and I will be able to play with it's handling data however I want.
Even vehicle.ResetHandlingData( rule ) will return back to the value you setted through SetHandlingRule( model, rule, val ), so it is a very safe alternative.

Here is a function example of how it should work:
Code: [Select]
function RegisterHandling( model, path )
    print( "Registering handling " + model + " from " + path );

        local file = ReadTextFromFile( path );
        local   bias = GetBetweenEvery( file, "<bias>", "</bias>" ),
                x = GetBetweenEvery( file, "<x>", "</x>" ),
                y = GetBetweenEvery( file, "<y>", "</y>" ),
                z = GetBetweenEvery( file, "<z>", "</z>" ),
                drivetype = GetBetween( file, "<drivetype>", "</drivetype>" ),
                enginetype = GetBetween( file, "<enginetype>", "</enginetype>" );

        if( drivetype == "4" ) drivetype = 52;
        else if( drivetype == "F" ) drivetype = 70;
        else if( drivetype == "R" ) drivetype = 82;

        if( enginetype == "P" ) enginetype = 80;
        else if( enginetype == "D" ) enginetype = 68;
        else if( enginetype == "E" ) enginetype = 69;
        SetHandlingRule( model, 1, GetBetween( file, "<mass>", "</mass>" ).tofloat() );
        if( x.len() == 2 )
            // dimensions
            SetHandlingRule( model, 2, x[0].tofloat() );
            SetHandlingRule( model, 3, y[0].tofloat() );
            SetHandlingRule( model, 4, z[0].tofloat() );

            // centre of mass
            SetHandlingRule( model, 5, x[1].tofloat() );
            SetHandlingRule( model, 6, y[1].tofloat() );
            SetHandlingRule( model, 7, z[1].tofloat() );
            SetHandlingRule( model, 5, x[0].tofloat() );
            SetHandlingRule( model, 6, y[0].tofloat() );
            SetHandlingRule( model, 7, z[0].tofloat() );
        // SetHandlingRule( model, 8, GetBetween( file, "<percentsubmerged>", "</percentsubmerged>" ).tofloat() ); // at the moment, it is buggy to set this value. (vehicles will teleport when touching water)
        SetHandlingRule( model, 9, GetBetween( file, "<multiplier>", "</multiplier>" ).tofloat() );
        SetHandlingRule( model, 10, GetBetween( file, "<loss>", "</loss>" ).tofloat() );
        SetHandlingRule( model, 11, bias[0].tofloat() );
        SetHandlingRule( model, 12, GetBetween( file, "<numofgears>", "</numofgears>" ).tofloat() );
        SetHandlingRule( model, 13, GetBetween( file, "<maxspeed>", "</maxspeed>" ).tofloat() );
        SetHandlingRule( model, 14, GetBetween( file, "<acceleration>", "</acceleration>" ).tofloat() );
        SetHandlingRule( model, 15, drivetype.tofloat() );
        SetHandlingRule( model, 16, enginetype.tofloat() );
        SetHandlingRule( model, 17, GetBetween( file, "<deceleration>", "</deceleration>" ).tofloat() );
        SetHandlingRule( model, 18, bias[1].tofloat() );
        SetHandlingRule( model, 19, GetBetween( file, "<steeringlock>", "</steeringlock>" ).tofloat() ); // "<abs>", "</abs>" ).tofloat() );
        SetHandlingRule( model, 20, GetBetween( file, "<forcelevel>", "</forcelevel>" ).tofloat() );
        SetHandlingRule( model, 21, GetBetween( file, "<dampening>", "</dampening>" ).tofloat() );
        SetHandlingRule( model, 22, GetBetween( file, "<seatoffset>", "</seatoffset>" ).tofloat() );
        SetHandlingRule( model, 23, GetBetween( file, "<damagemultiplier>", "</damagemultiplier>" ).tofloat() );
        SetHandlingRule( model, 24, GetBetween( file, "<upperlimit>", "</upperlimit>" ).tofloat() );
        SetHandlingRule( model, 25, GetBetween( file, "<lowerlimit>", "</lowerlimit>" ).tofloat() );
        SetHandlingRule( model, 26, bias[2].tofloat() );
        SetHandlingRule( model, 27, GetBetween( file, "<antidive>", "</antidive>" ).tofloat() );
        SetHandlingRule( model, 28, ("0x" + GetBetween( file, "<flags>", "</flags>" )).tofloat() );
        SetHandlingRule( model, 29, GetBetween( file, "<front>", "</front>" ).tofloat() );
        SetHandlingRule( model, 30, GetBetween( file, "<rear>", "</rear>" ).tofloat() );
        SetHandlingRule( model, 31, 0.0 );
        SetHandlingRule( model, 32, 0.0 );
        SetHandlingRule( model, 33, 0.0 );
        print( ". Loaded handling for " + model );

Example: RegisterHandling( 6400, "/XMLs/mycar.xml" );
I/O Functionality thanks to @SLC !

So, you must have your XMLs extracted out of the .7z archives, somewhere (e.g: server/XMLs/here) in your server files, for the server to access them.
Unfortunately, I don't know how to open an archive through script, to load them directly from inside. If you know how to, land a hand ;p

PS: The only thing you should not do is using ResetHandlingRule( model, rule ), because it will return to the 'default' value: 0
PS2: SetHandlingRule( model, 8, .. ) was commented due to a weird behaviour of the game.
( no matter what value you set it, the vehicle will get teleported to Vector(0,0,0) when touching th water )
(( in order to recover things back, just use ResetHandlingData/Rule( 8 ) ))

Vehicle Showroom / Bobster
« on March 3rd, 10:38 PM »
Took a look in some OLD files, since when @maxorator was just spoiling the custom vehicles' feature
(click to show/hide)


Script Showroom / Racing System (with checkpoints)
« on February 16th, 01:15 AM »

Racing System
(with checkpoints)

This is basic and ready for you to use and even customize !

Some info about how it works?! Somebody /startrace, and then, for the next 20seconds (by def), people can join it and race.
It loads all the saved tracks to check if everything is alright, then free the table so we don't unnecessary keep a lot of data in the memory. So, we load it only when we need it.
(didn't start the script with this idea though, so IF -big if- there are some bugs, I'm pretty sure it is because of the few changes I did to the 'mechanism')
The racing track is using checkpoints, together with 2 markers on radar: 1 for the next cp, 1 for the second next cp.
You can join as many racers as you want in a race, but I've limited it to const race_max_spots = 20;
(so, just change that if you want more)
There is a likes variable too, saved in the database, but never used. I consider it needs to be a lil' bit more hardcoded
in each server, as you need to know who voted already, when players have some time for voting, etc
For more, check it out!

My Racing System is something everybody can use in their servers, as a side activity.
I also suggest you to use some GUI on it :P

Available commands:
  • /race - info and list of cmds
  • /startrace //<trackID> <newVehModel> <newLaps> - all params are optional!
  • /joinrace
  • /quitrace
  • /flip
  • /lastcp

Developer mode:
  • /racedev - toggle developer mode
  • /createtrack <name> //<laps> - name must be 1-word
  • /createcp - creates the next checkpoint position


Some things/functions you might already have

Code: [Select]
const COLOR_BLUE = "[#4baaff]";
const COLOR_GREY = "[#b0b0b0]";
const COLOR_WHITE = "[#ffffff]";

Code: [Select]
function random( min, max )
        if ( min < max )
                return rand() % (max - min + 1) + min.tointeger();
        else if ( min > max )
                return rand() % (min - max + 1) + max.tointeger();
        else if ( min == max )
                return min.tointeger();

function GetTok(string, separator, n, ...)
    local m = vargv.len() > 0 ? vargv[0] : n,
    tokenized = split(string, separator),
    text = "";
    if (n > tokenized.len() || n < 1) return null;
    for (; n <= m; n++)
        text += text == "" ? tokenized[n-1] : separator + tokenized[n-1];
    return text;

function NumTok( string, separator )
    local tokenized = split(string, separator);
    return tokenized.len();

Some a lil' bit more custom, but still
thought, you might want to edit them
Code: [Select]
function devprint( text )
MSG( COLOR_GREY + text + "" );
print( text );

function pMSG( text, player )
return MessagePlayer( COLOR_BLUE + text, player );

function MSG( text )
return Message( COLOR_BLUE + text );

function SQLC( db, column )
    return GetSQLColumnData( db, column );


1.First, we must load the RacingSystem.nut
then, for the future, we gonna check if tracks data is good
Code: [Select]
function onScriptLoad()
dofile( "scripts/RacingSystem.nut" );

2.Then we make sure we rage quit the players when needed
Code: [Select]
function onPlayerPart( player, reason )
if( racedev == player.ID ) racedev = null;
QuitTrack( player );
function onPlayerDeath( player, reason )
QuitTrack( player );

function onPlayerKill( player, killer, reason, bodypart )
QuitTrack( player );

function onPlayerTeamKill( player, killer, reason, bodypart )
QuitTrack( player );

3.Now, onPlayerCommand
Code: [Select]
else if ( cmd == "race" )
pMSG( "Racing System by Sebastian (aka sseebbyy)", player );
pMSG( "Commands: (/) racedev, startrace, joinrace, quitrace, flip, lastcp", player );

else if( cmd == "startrace" )
if( !text ) return AnnounceRace();

local param = array( NumTok( text, " " ) );

local i = 0;
for( i = 0; i < param.len(); i++ ) param[i] = GetTok( text, " ", i+1 );

if( ( param.len() == 1 ) && IsNum( param[0] ) ) return AnnounceRace( param[0] );
else if( ( param.len() == 2 ) && IsNum( param[1] ) ) return AnnounceRace( param[0], param[1] );
else if( ( param.len() == 3 ) && IsNum( param[2] ) ) return AnnounceRace( param[0], param[1], param[2] );
else return pMSG( COLO_GREY + "Error - One/more params are not numbers. Every parameter must be number.", player );

else if( cmd == "joinrace" )
JoinTrack( player );

else if ( cmd == "quitrace" )
QuitTrack( player );

else if ( cmd == "flip" )
local veh = player.Vehicle;
            if ( !veh ) pMSG( COLOR_GREY + "You need to be in a vehicle to use this command.", player );
local rot = veh.Rotation;
                veh.Rotation = Quaternion( 0.0, 0.0, veh.z, veh.w ); // by Xmair
                pMSG( COLOR_BLUE + "Vehicle flipped.", player);

else if ( cmd == "lastcp" )
LastCP( player );

else if( cmd == "racedev" )
if( racedev == player.ID ) return devExit( player );
else if( racedev == null ) return devEnter( player );

else if( cmd == "createtrack" )
if( racedev == null ) return pMSG( COLOR_GREY + "Error - You must be in the developer mode!", player );
else if( racedev != player.ID ) return pMSG( COLOR_GREY + "Error - You must be in the developer mode!", player );
else if( !text ) return pMSG( COLOR_GREY + "Error - Correct Syntax: /" + cmd + " <name> <laps?>", player );

local track,
name = GetTok( text, " ", 1 );

if( NumTok( text, " " ) != 2 )
track = CreateTrack( name, player );
if( track )
Race.ID = track.ID;
pMSG( COLOR_BLUE + "[RACEDEV] " + player.Name + " created a new racetrack " + name, player );

local laps = GetTok( text, " ", 2 );
if( ( laps != null ) && !IsNum( laps ) ) return pMSG( COLOR_GREY + "Error - Second parameter '<laps>' must be a number!", player );

track = CreateTrack( name, player, laps.tointeger() );
if( track )
Race.ID = track.ID;
pMSG( COLOR_BLUE + "[RACEDEV] " + player.Name + " created a new racetrack " + name + " with " + laps + " laps.", player );

else if( cmd == "createcp" )
if( racedev == null ) return pMSG( COLOR_GREY + "Error - You must be in the developer mode!", player );
else if( racedev != player.ID ) return pMSG( COLOR_GREY + "Error - You must be in the developer mode!", player );

local tid = Race.ID;
if( tid == null ) return pMSG( "Unfortunately, there is no race announced yet.", player );

local track = trackTable.rawget( tid );
CreateCP( tid, player.Pos );
pMSG( COLOR_BLUE + "[RACEDEV] " + track.Name + " got a new checkpoint by " + player.Name, player );

4.Finally, the magic function
Code: [Select]
function onCheckpointEntered( player, checkpoint )
if( Race.ID != null && trackTable.rawin( Race.ID ) )
local tid = Race.ID,
track = trackTable.rawget( tid );

if( track.pptTable.rawin( player.ID ) )
local ppt = track.pptTable.rawget( player.ID );
if( ppt.UCP.ID != checkpoint.ID ) return 0;

ReachCP( player );
Tutorials / [Video] Load Custom Maps in VC Map Editors
« on February 15th, 10:16 AM »
I've been hunting this for a while, and finally did it!

With the help of our beloved @Thijn  , we have all the tools we need to properly load
Custom Objects/Maps in GTA Map Editors
  • MEd (the one I'm gonna use in my video tutorials)
  • KEd (updated version of MooMapper)
Yes, Thijn made yet another great converter:

Short theory about how things work:
Simply redoing what R* did: place all needed .dff .txd inside Vice City/models/gta3.img.
Then, we need to register them in some .ide file (just like we do in vc:mp, in .xml, just different format) to let the game know which .txd we want for the specified .dff, etc.
Once we did that too, we must let the game know we created a new .ide file that we want to load, so, we just open Vice City/data/gta_vc.dat and write it down there too.

That's it!
Now the game knows we have new objects, so we can just start do our maps with Map Editors.
PS: The Single Player won't load anymore though, as we are pretty sure crossing some limits there.
That's why I suggest you to make a copy of the game, which will be used only for Mapping.

Good luck in mapping!

I've split this tutorial in 2 as we may need 2 different things:
  • Load just the custom objects, and then create our own maps from scratch
  • Load entire custom maps from store/maps/ and edit them through the Editor

For the ones who fits the second option, it might help watching the first video tutorial too.

PS: It might look complicated, but it is not. It's easy. All you need is some practice.

(click to show/hide)
HOW TO load and play with your VC:MP Custom Objects in Map Editor ! (aka Med)
So, in order to do this, you will need:
1.   Your custom objects’ .txd and .dff
2.   (any) IMG Editor
3.   Map Editor (MEd)

I also suggest you to create a copy of your Vice City and use it for such jobs, as we gonna edit files inside.

So, let’s start:
1.   Add custom objects (.txd and .dff) inside gta3.img
We will do it with IMG Editor.
(always rebuild archive after)
2.   Convert .xml to .ide and load it into gta_vc.dat
We gonna use Thijn’s converter for it.
Preferably to create a separated folder for our custom maps, so we have everything organized.
3.   Open MEd and load your new VCMP Mapping
4.   Create a new .ipl file and start mapping with your custom objects!
5.   Once you finished, save all the progress/changes.
6.   Convert the new <mapname>.ipl to .xml and load it in your server
7.   Start server and check what have you accomplished!

(click to show/hide)
If last time we learnt how to load and play with VC:MP Custom Objects in MEd, this time we gonna learn
HOW TO Load entire custom maps and objects in MEd !
So you will be able to do changes to the already made-map.
I suggest you to make a copy of your server store folder before such jobs, so you don’t lose anything.

In order to start, make sure you have:
1.   all the .txd .dff files of the custom map
2.   objects.xml from store/objects/ where all the above objects are registered
3.   map.xml from store/maps/ of the wanted map
4.   and ofc MEd, IMG Editor

Let’s start!
1.   Load all the .txd and .dff into the gta3.img and rebuild the archive!
2.   Convert objects.xml to .ide and place it in the wanted folder in VCMP Mapping/data/vcmp_maps/
3.   Convert map.xml to .ipl and place it in the same location as above
4.   Load the new added .ide and .ipl inside gta_vc.dat
MAKE SURE that your new map won’t conflict with some other maps.ide/.ipl !
If you have an object on id 6000 on 2 maps.ide, the object will be defined only one – the first time.
So, to avoid such unpleasures, comment the other maps, if they are not part of this new one!
5.   Open MEd, load VCMP Mapping, and check your new map’s box so it will load.
6.   Do all the edits you want to the custom map you added.
7.   Save all the progress, close MEd/KEd and convert the new map.ipl to .xml and replace it in your server files.
8.   Start server and see if it worked!
Client Scripting / [Beta] Realistic Bullet Holes
« on October 16th, 2020, 03:30 PM »

Sorry for being late, but I've faced a surprise which is just amazing!
The Bullet Holes I told you about, won't be just local, but synced on everybody's screen !!
What ?? Yes!  And all just by client-side. (no data is sent to server)

(onPlayerShoot is called for everybody, not just for the local player)

I've set a limit for bullet holes, as we don't want to use too many resources.
(even if I'm not sure how hard will this hit some low-end pc)
So, if you face lag when playing alongside other players, reply to this post with your pc details, and according to the replies I get, I will try to find a way around to fix it.

How does it work ?
Well, it creates a sprite on the hit position, in client side.
With help from habi, sprites are rotated to be facing the player in the moment of shooting, so they won't look like ugly dots around.
Every player has a limit of 10 bullet holes that can create, so once the limit is touched, the first one created will be removed, and so on.

Sprites won't be removed, because:
Quote from MEGAMIND on October 14th, 2020, 07:24 AM
Suggestion : Donot let the holes fade away, it will bring more realism,  if anyone passes by he/she may see that someone here fought here before
But, as I said, if some players will start facing lag using this script, then I will rethink it and solve it out.
Meanwhile, big thanks goes to @habi for his math skills which I Iack alot !

That's all I guess, so I will just post the code which you need to use CLIENT-SIDE
Also, better save the "hole.png" and place it in server/store/sprites

Code: [Select]
const MAX_PLAYERS = 100;
llplayer <- World.FindLocalPlayer();

/* per player */
const MAX_HOLES = 10; // -1 for never removing holes, 0 for turning off the effect

local bulletTable = array( MAX_PLAYERS ),
holes = array( MAX_PLAYERS ),
last_hole_picked = array( MAX_PLAYERS );

bulletTable[ llplayer.ID ] = {};
holes[ llplayer.ID ] = 0;
last_hole_picked[ llplayer.ID ] = 0;

class leHole
    inst = null;
    ID = null;

Code: [Select]
function Player::PlayerShoot( player, weapon, hitEntity, hitPosition )
    if( hitEntity && hitEntity.Type == OBJ_BUILDING )
CreateBulletHole( player, hitPosition );

Code: [Select]
function CreateBulletHole( player, pos )
local ppos = player.Position;
if( MAX_HOLES == 0 ) return 0;
else if( !bulletTable[ player.ID ] )
// this means the 'player' was not registered by this client, yet
bulletTable[ player.ID ] = null;
bulletTable[ player.ID ] = {};
holes[ player.ID ] = 0;
last_hole_picked[ player.ID ] = 0;

local   hole,
id = holes[ player.ID ],
angle = atan2( pos.X - ppos.X, pos.Y - ppos.Y );

if( MAX_HOLES != -1 && holes[ player.ID ] == MAX_HOLES )
if( bulletTable[ player.ID ].rawin( last_hole_picked[ player.ID ] ) )
id = last_hole_picked[ player.ID ];
local lhp = id + 1;

hole = bulletTable[ player.ID ].rawget( id );
hole.inst = null;
bulletTable[ player.ID ].rawdelete( id );
holes[ player.ID ]--;

if( last_hole_picked[ player.ID ] == MAX_HOLES-1 ) lhp = 0;

last_hole_picked[ player.ID ] = lhp;

bulletTable[ player.ID ].rawset( id, leHole() );
hole = bulletTable[ player.ID ].rawget( id );
hole.ID = id;

hole.inst = GUISprite( "hole.png", VectorScreen( 0, 0 ) );
hole.inst.Alpha = 90;

hole.inst.AddFlags( GUI_FLAG_3D_ENTITY );
hole.inst.Set3DTransform( Vector( pos.X, pos.Y, pos.Z ),  Vector( -PI/2, 0, -angle ), Vector( 0.35, 0.35, 0.0 ) );
fixsprite( hole.inst );
centersprite( hole.inst );
holes[ player.ID ]++;

@habi 's magic
Code: [Select]
// habi's magic
function move( pos, distance, angle )
local newx = pos.X - sin( angle ) * distance,
newy = pos.Y + cos( angle ) * distance;
return Vector( newx, newy, pos.Z ); //assuming z more or less same.

function move2( pos, pangle, dis, angle )
return move( pos, dis, pangle + angle )
function fixsprite( sp )
local x = sp.Position3D,
rot = sp.Rotation3D,
size = sp.Size3D, //(pos,pangle,dis,angle)
newPos = move2( x, rot.Z, 1, PI );

sp.Position3D = newPos;
function centersprite( sp )
local x = sp.Position3D,
rot = sp.Rotation3D,
size = sp.Size3D, //(pos,pangle,dis,angle)
newPos = move2( x, rot.Z, size.X / 2, PI / 2 );

newPos.Z += 1.15;
sp.Position3D = newPos;

PS: If you find bugs, let me know!
Videos & Screenshots / Realistic Bullet Holes (prototype)
« on October 13th, 2020, 02:41 PM »

Will definetely improve it and then release it for public.
Tutorials / [Blender] Lighting up buildings' windows
« on July 19th, 2020, 08:52 AM »

Just like R* did ?!
(click to show/hide)

Lately, I've been spending my time lighting up buildings for my server's map, because it was too dark.
(check the last seconds of the video to see what I'm talking about)

I recorded a video tutorial about it, maybe it will help some of you.

(click to show/hide)
Editing the textures in order to keep the windows only, and remove everything else, was cut from the full video.
It is something you can achieve through other softwares too - but I shown you the very basic way instead.

(click to show/hide)
Editing the textures is up to you and your skills.

Im gonna use a way that's basic and everyone can do.
For this, we gonna need TXD Workshop and  TXD Magic we already have.

This 222.txd is mine for such things. As you can see, this is howfinal products should look.
(so we remove everything and leave just what we wanna see lighted up in the darkness)

So, first, I'm gonna light up the textures.
I'm using PHOTOSCAPE because it is an easy software.

Now, here comes the "trick". We must create a copy of those textures, and edit them.
(but before, add "_lighted" sufix to your textures' names, so they don't conflict with the originals)

We gonna use the "alpha way". So, in the copies we created, we gonna paint with white everything we wanna keep visible in-game, and with black everything we wanna hide.

In order to make it look realistic, we should hide one/two windows, as rarely buildings have all lights opened.
(better to start with that idea - I just remembered now to tell you)

Ok, so we have done the first one; we move to the second one.

Also finished the second one. As I said, we make white just what we want to keep visible.

OH! totally forgot.
The black'n'white textures must be in .BMP format.
(we don't need .png for them anymore, so we delete them)

Now, comes the TXD Workshop trick. That software allows us to set an alpha variant for our texture.
( TXD Magic doesn't )

As you can see, both images mixed into one, and only the white part was kept visible.
So, we just open it now with TXD Magic. It reads it as a .png with transparency.
That's what we need.

So, all that matters is the result:
texture with transparency!

(click to show/hide)
Hello there!

Today I will show you my way of lighting up
buildings' windows !


In order to light them up, we will edit the original
object and remove everything else except windows.
Then, move the windows out of the building a bit, so
they won't interfere with each other. (nor with the LOD)
3rd step is to light them up through Blender.


Used:     MEd ( to export the object )
   Blender ( to edit the object ) with I/O DFF plugin!
   .TXD Magic ( to deal with .txd files )
   7zip ( to archive in .7z the files for vcmp )

__1st STEP_____________
We are going to export the object we wanna light up.
(using MEd)

__2nd STEP_____________
Once we got the .dff and .txd files, we can export the
needed textures out of the .txd (as .PNG)
(as I said, we need only the windows, so we will get rid of
the rest of the object, later)

The easiest and fastest way is to guess what textures
you need, by looking at the object itself and the .txd file.
(so you extract the textures you see)

__3rd STEP_____________
We take every texture apart and edit it.
(lighting up, cutting)
All we care about are the windows, so that's all we gonna
Ok, I did that in the pause, so here is the result.
(but I also kept the lighted up .png textures, because
Blender won't load textures with transparency)
((renamed the .dff and .txd as we don't need conflicts))

__4th STEP_____________
Load the object in Blender.
as we can see, there is no texture loaded.
Why ? because we also renamed the original textured.
We added the sufix "_lighted" so the model can't recognize it

We must set them, so we gonna look in the list of textures of
the model, and find our textures' names.

We found them, so now we have to remove everything else.

Now we need to select the faces we want to keep (windows part)
(( we select them with right-click and do multiple selection
by keeping SHIFT pressed down ))

Then separate them from the rest which we will delete later.
(( press 'space' key and write 'separate'.
Now, we have 2 objects. We can remove the other one
and keep the one we just created.
We can also remove anything else like collisions.
Those faces are all that matter ))

After that, we move the faces a bit.
(since we gonna spawn the new object in the same position
as our target object, we don't want them to interfere.
Just like R* did - see the image >no image< )

When we done with that, we must replace the textures with
the ones with more light on.
^ we already did that, earlier.

We must now paint the 'Vertex' of the object in bright white
otherwise, the object won't be bright.
they are lighted windows afterall; they must be as visible
as posible.

Then, we export the .dff
(( if you get such error, then there are some textures
registered but not used, with no textures, or something like
that. We just remove them ))

Done. The export gave no errors anymore.

__5th STEP_____________
We archive the .dff and .txd into an .7z with sufix "_unp"
(like "myname_unp.7z") and place it inside store directory.
Then we register the object inside store/objects/
(( use flag 8 for objects with transparency ))
And create a static object inside store/maps/

Now, since we did everything, we can join the server and
see our work ;p

Registering the object in store/objects/
Code: [Select]
<object id="0">
<flags value="8"/>
<collision type="none"/>
<texture path="night_windows.txd"/>
<model path="wshbuildws20_nt.dff" distance="1000" />
<time on="20" off="5"/>

Spawning the object as a static one, via .xml, in store/maps/
Code: [Select]
<item model="6000" name="wshbuildws20_nt">
<position x="-39.41270447" y="-1106.622192" z="14.09233856" />
<rotation format="axisangle" x="0" y="0" z="0.7071067691" angle="0.7071067691" />

Bugs and Crashes / [Bug/Crash] /recordkey crashing - no logs
« on May 24th, 2020, 02:52 PM »
As the title say, /recordkey seems to crash once you press a button.
@Xmair confirmed that it is not working in rel004 either.
Videos & Screenshots / Developer Preview Program v1.3
« on May 8th, 2020, 12:44 AM » (Embedding disabled, limit reached)

Follow the instructions on the video!