Compare commits
5 commits
2576f803cd
...
9871e93a10
Author | SHA1 | Date | |
---|---|---|---|
9871e93a10 | |||
225039f71f | |||
061cdbd257 | |||
412c8f984e | |||
8422ddd26b |
41 changed files with 1303 additions and 516 deletions
|
@ -9,8 +9,8 @@
|
|||
Determines the alpha test function used when rendering this surface.
|
||||
|
||||
Valid values are **GT0**, **LT128**, and **GE128**. These correspond to
|
||||
**"GREATER THAN 0"**, **"LESS THAN 128"**, and **"GREATER THAN OR EQUAL
|
||||
TO 128"**.
|
||||
**GREATER THAN 0**, **LESS THAN 128**, and **GREATER THAN OR EQUAL
|
||||
TO 128**.
|
||||
|
||||
This function is used when determining if a pixel should be written to
|
||||
the frame-buffer. For example, if **GT0** is specified, the only the
|
||||
|
@ -18,13 +18,12 @@ portions of the texture map with corresponding alpha values greater than
|
|||
zero will be written to the framebuffer. **By default alpha testing is
|
||||
disabled.**
|
||||
|
||||
Both alpha testing and normal [alpha
|
||||
blending](blendFunc) can be used to get
|
||||
Both alpha testing and normal [alpha blending](blendfunc.md) can be used to get
|
||||
textures that have see-through parts. The difference is that
|
||||
**alphaFunc** is an all-or-nothing test, while blending smoothly blends
|
||||
between opaque and translucent at pixel edges.
|
||||
|
||||
Alpha test can also be used with
|
||||
[depthWrite](depthWrite), allowing other
|
||||
[depthWrite](depthwrite.md), allowing other
|
||||
effects to be conditionally layered on top of just the opaque pixels by
|
||||
setting [depthFunc](depthFunc) to equal.
|
||||
setting [depthFunc](depthfunc.md) to equal.
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
### Overview
|
||||
|
||||
The alpha channel can be specified like the [rgb
|
||||
channels](rgbGen). If not specified, it
|
||||
The alpha channel can be specified like the [rgb channels](rgbgen.md). If not specified, it
|
||||
defaults to 1.0.
|
||||
|
||||
### Functions {#functions}
|
||||
|
@ -15,7 +14,7 @@ defaults to 1.0.
|
|||
#### portal {#portal}
|
||||
|
||||
This rendering stage keyword is used in conjunction with the
|
||||
[surfaceparm](surfaceparm) keyword
|
||||
[surfaceparm](surfaceparm.md) keyword
|
||||
portal. The function accomplishes the "fade" that causes the scene in
|
||||
the portal to fade from view. Specifically, it means "Generate alpha
|
||||
values based on the distance from the viewer to the portal."
|
||||
|
|
|
@ -23,10 +23,10 @@ It accepts the standard **wave** functions of the type: **sin**,
|
|||
**triangle**, **square**, **sawtooth** or **inversesawtooth**.
|
||||
|
||||
The "div" parameter is used to control the wave "spread" - a value equal
|
||||
to the [tessSize](vmap_tessSize) of the
|
||||
to the [tessSize](vmap_tesssize.md) of the
|
||||
surface is a good default value.
|
||||
|
||||
#### normal <siv> <func> <base> <amplitude ~0.1-~0.5> <frequency ~1.0-~4.0> {#normal_amplitude_0.1_0.5_frequency_1.0_4.0}
|
||||
#### normal <siv> <func> <base> <amplitude> <frequency> {#normal_amplitude}
|
||||
|
||||
This deformation affects the normals of a vertex without actually moving
|
||||
it, which will effect later material options like lighting and
|
||||
|
@ -43,14 +43,14 @@ rain, flags.
|
|||
This forces a bulge to move along the given s and t directions. Designed
|
||||
for use on curved pipes.
|
||||
|
||||
#### move<x> <y> <z> <func> <base> <amplitude> <phase> <freq> {#move}
|
||||
#### move <x> <y> <z> <func> <base> <amplitude> <phase> <freq> {#move}
|
||||
|
||||
This keyword is used to make a brush, curve patch or model appear to
|
||||
move together as a unit. The **<x>** **<y>** and **<z>** values are the
|
||||
move together as a unit. The **x** **y** and **z** values are the
|
||||
distance and direction in game units the object appears to move relative
|
||||
to it's point of origin in the map.
|
||||
|
||||
The **<func> <base> <amplitude> <phase>** and **<freq>** values are the
|
||||
The **func base amplitude phase** and **freq** values are the
|
||||
same as found in other wave form manipulations.
|
||||
|
||||
The product of the function modifies the values x, y, and z.Therefore,
|
||||
|
@ -101,9 +101,9 @@ smaller wave forms occurring in a given area. Larger values create a
|
|||
lesser density of waves, or otherwise put, the appearance of larger
|
||||
waves. To look correct this value should closely correspond to the value
|
||||
(in pixels) set for
|
||||
[tessSize](vmap_tessSize) of the texture.
|
||||
[tessSize](vmap_tesssize.md) of the texture.
|
||||
A value of 100.0 is a good default value (which means your
|
||||
[tessSize](vmap_tessSize) should be close
|
||||
[tessSize](vmap_tesssize.md) should be close
|
||||
to that for things tolook "wavelike").
|
||||
|
||||
#### <func> {#section_1}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
### Overview
|
||||
|
||||
By default, writes to the depth buffer when
|
||||
[depthFunc](depthFunc) passes will happen
|
||||
[depthFunc](depthfunc.md) passes will happen
|
||||
for opaque surfaces and not for translucent surfaces.
|
||||
|
||||
Blended surfaces can have the depth writes forced with this function.
|
|
@ -7,15 +7,15 @@
|
|||
### Overview
|
||||
|
||||
**Note**: you must also specify "surfaceparm fog" to cause
|
||||
[vmap](vmap) to identify the surfaces inside the volume.
|
||||
[vmap](vmap.md) to identify the surfaces inside the volume.
|
||||
Fogparms only describes how to render the fog on the surfaces.
|
||||
|
||||
**<red value> <green value> <blue value>** These are normalized values.
|
||||
**red value, green value, blue value**: These are normalized values.
|
||||
To obtain the values that define fog color divide the desired color's
|
||||
Red, Green and Blue values by 255 to obtain three normalized numbers
|
||||
within the 0.0 to 1.0 range.
|
||||
|
||||
**<distance toopaque>** This is the distance, in game units, until the
|
||||
**distance to opaque**: This is the distance, in game units, until the
|
||||
fog becomes totally opaque, as measured from the point of view of the
|
||||
observer. By making the height of the fog brush shorter than the
|
||||
distance to opaque, the apparent density of the fog can be reduced
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
### Overview
|
||||
|
||||
Similar to [vmap_surfaceModel (Material
|
||||
Command)](vmap_surfaceModel), however
|
||||
Similar to [vmap_surfaceModel (vmap_surfacemodel.md), however
|
||||
it'll place models at runtime. The density can be controlled via the
|
||||
cvar `r_clutter_density`.
|
|
@ -9,17 +9,17 @@
|
|||
The texture is essentially a fullbright overlay on top of the
|
||||
diffuse/albedomap.
|
||||
|
||||
Not all [Shaders](Shaders) support them. In some, like the
|
||||
[unlit](unlit_(Shader)) shader, the
|
||||
[diffusemap](diffusemap) is always
|
||||
Not all [Shaders](Shaders.md) support them. In some, like the
|
||||
[unlit](unlit.md) shader, the
|
||||
[diffusemap](diffusemap.md) is always
|
||||
fullbright.
|
||||
|
||||
### See also {#see_also}
|
||||
|
||||
- [diffusemap](diffusemap)
|
||||
- [normalmap](normalmap)
|
||||
- [specularmap](specularmap)
|
||||
- [uppermap](uppermap)
|
||||
- [lowermap](lowermap)
|
||||
- [reflectmask](reflectmask)
|
||||
- [reflectcube](reflectcube)
|
||||
- [diffusemap](diffusemap.md)
|
||||
- [normalmap](normalmap.md)
|
||||
- [specularmap](specularmap.md)
|
||||
- [uppermap](uppermap.md)
|
||||
- [lowermap](lowermap.md)
|
||||
- [reflectmask](reflectmask.md)
|
||||
- [reflectcube](reflectcube.md)
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
### Overview
|
||||
|
||||
This implies [noPicMip](noPicMip), but
|
||||
This implies [noPicMip](nopicmip.md), but
|
||||
also prevents the generation of any lower resolution mipmaps for use by
|
||||
the 3d card. This will cause the texture to alias when it gets smaller,
|
||||
but there are some cases where you would rather have this than a blurry
|
||||
|
|
|
@ -18,10 +18,10 @@ Check out our [Normal mapping guide](Normal_mapping_guide).
|
|||
|
||||
### See also {#see_also}
|
||||
|
||||
- [diffusemap](diffusemap)
|
||||
- [specularmap](specularmap)
|
||||
- [fullbrightmap](fullbrightmap)
|
||||
- [uppermap](uppermap)
|
||||
- [lowermap](lowermap)
|
||||
- [reflectmask](reflectmask)
|
||||
- [reflectcube](reflectcube)
|
||||
- [diffusemap](diffusemap.md)
|
||||
- [specularmap](specularmap.md)
|
||||
- [fullbrightmap](fullbrightmap.md)
|
||||
- [uppermap](uppermap.md)
|
||||
- [lowermap](lowermap.md)
|
||||
- [reflectmask](reflectmask.md)
|
||||
- [reflectcube](reflectcube.md)
|
|
@ -4,11 +4,11 @@
|
|||
material. It also accepts arguments that will recompile a shader with
|
||||
certain permutations. This is kinda ugly,
|
||||
|
||||
Starting in [The Wastes](The_Wastes) 1.2, there are the
|
||||
Starting in **The Wastes 1.2**, there are the
|
||||
following shader programs available to you:
|
||||
|
||||
- program [unlit](unlit_(Shader))
|
||||
- program [lightmapped](lightmapped_(Shader))
|
||||
- program [vertexlit](vertexlit_(Shader))
|
||||
- program [water](water_(Shader))
|
||||
- program [refract](refract_(Shader))
|
||||
- program [unlit](unlit.md)
|
||||
- program [lightmapped](lightmapped.md)
|
||||
- program [vertexlit](vertexlit.md)
|
||||
- program [water](water.md)
|
||||
- program [refract](refract.md)
|
|
@ -11,10 +11,10 @@ will pass the nearest in-world cubemap instead.
|
|||
|
||||
### See also {#see_also}
|
||||
|
||||
- [diffusemap](diffusemap)
|
||||
- [normalmap](normalmap)
|
||||
- [specularmap](specularmap)
|
||||
- [fullbrightmap](fullbrightmap)
|
||||
- [uppermap](uppermap)
|
||||
- [lowermap](lowermap)
|
||||
- [reflectmask](reflectmask)
|
||||
- [diffusemap](diffusemap.md)
|
||||
- [normalmap](normalmap.md)
|
||||
- [specularmap](specularmap.md)
|
||||
- [fullbrightmap](fullbrightmap.md)
|
||||
- [uppermap](uppermap.md)
|
||||
- [lowermap](lowermap.md)
|
||||
- [reflectmask](reflectmask.md)
|
|
@ -8,18 +8,18 @@
|
|||
|
||||
Defines a texture that specifies which parts of a material will reveal a
|
||||
reflective material, such as a
|
||||
[cubemap](reflectcube). This applies to
|
||||
[cubemap](reflectcube.md). This applies to
|
||||
standard FTEQW. In Nuclide the reflectmask is currently unused with the
|
||||
included shaders. If you want to apply reflectivity to your materials,
|
||||
use the alpha channel of your
|
||||
[normalmap](normalmap) instead.
|
||||
[normalmap](normalmap.md) instead.
|
||||
|
||||
### See also {#see_also}
|
||||
|
||||
- [diffusemap](diffusemap)
|
||||
- [normalmap](normalmap)
|
||||
- [specularmap](specularmap)
|
||||
- [fullbrightmap](fullbrightmap)
|
||||
- [uppermap](uppermap)
|
||||
- [lowermap](lowermap)
|
||||
- [reflectcube](reflectcube)
|
||||
- [diffusemap](diffusemap.md)
|
||||
- [normalmap](normalmap.md)
|
||||
- [specularmap](specularmap.md)
|
||||
- [fullbrightmap](fullbrightmap.md)
|
||||
- [uppermap](uppermap.md)
|
||||
- [lowermap](lowermap.md)
|
||||
- [reflectcube](reflectcube.md)
|
|
@ -13,20 +13,20 @@ to use for color, intensity etc.
|
|||
The renderer will take it into account only if you do not supply any
|
||||
Stages in the material.
|
||||
|
||||
**<farbox>** Specifies a set of files to use as an environment box
|
||||
**farbox**: Specifies a set of files to use as an environment box
|
||||
behind all cloudlayers. Specify "-" for no farbox, or a file base name.
|
||||
A base name of "env/test" would look for files "env/test_rt.tga",
|
||||
"env/test_lf.tga", "env/test_ft.tga", "env/test_bk.tga",
|
||||
"env/test_up.tga", "env/test_dn.tga" to use as the right / left / front
|
||||
/ back / up / down sides.
|
||||
|
||||
**<cloudheight>** controls apparent curvature of the cloud layers -
|
||||
**cloudheight**: controls apparent curvature of the cloud layers -
|
||||
lower numbers mean more curvature (and thus more distortion at the
|
||||
horizons). Higher height values create "flatter" skies with less horizon
|
||||
distortion. Think of height as the radius of a sphere on which the
|
||||
clouds are mapped. Good ranges are 64 to 256. The default value is 128.
|
||||
|
||||
**<nearbox>** Specified as farbox, to be alpha blended ontop of the
|
||||
**nearbox**: Specified as farbox, to be alpha blended ontop of the
|
||||
clouds. This has not be tested in a long time, so it probably doesn't
|
||||
actually work. Set to "-" to ignore.
|
||||
|
||||
|
|
|
@ -13,10 +13,10 @@ texture it for other purposes, too.
|
|||
|
||||
### See also {#see_also}
|
||||
|
||||
- [diffusemap](diffusemap)
|
||||
- [normalmap](normalmap)
|
||||
- [fullbrightmap](fullbrightmap)
|
||||
- [uppermap](uppermap)
|
||||
- [lowermap](lowermap)
|
||||
- [reflectmask](reflectmask)
|
||||
- [reflectcube](reflectcube)
|
||||
- [diffusemap](diffusemap.md)
|
||||
- [normalmap](normalmap.md)
|
||||
- [fullbrightmap](fullbrightmap.md)
|
||||
- [uppermap](uppermap.md)
|
||||
- [lowermap](lowermap.md)
|
||||
- [reflectmask](reflectmask.md)
|
||||
- [reflectcube](reflectcube.md)
|
|
@ -8,9 +8,9 @@ by the renderer. A few keywords will only apply to any one of them.
|
|||
All surfaceparm keywords are preceded by the word surfaceparm as
|
||||
follows:
|
||||
|
||||
:
|
||||
|
||||
: surfaceparm **fog**
|
||||
```
|
||||
surfaceparm **fog**
|
||||
```
|
||||
|
||||
### Behaviour Keywords {#behaviour_keywords}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
## tcmod
|
||||
### Syntax
|
||||
|
||||
**tcMod <func> <…>**
|
||||
**tcMod <func> [...]**
|
||||
|
||||
### Overview
|
||||
|
||||
|
@ -26,7 +26,7 @@ specified. In otherwords, if you see:
|
|||
 tcMod scroll 1 1
|
||||
```
|
||||
|
||||
Then the texture coordinates will be **scaled then**scrolled'''.
|
||||
Then the texture coordinates will be **scaled** then **scrolled**.
|
||||
|
||||
### Functions {#functions}
|
||||
|
||||
|
@ -81,20 +81,20 @@ Stretches the texture coordinates with the given function. Stretching is
|
|||
defined as stretching the texture coordinate away from the center of the
|
||||
polygon and then compressing it towards the center of the polygon.
|
||||
|
||||
**<base>**: A base value of one is the original dimension of the texture
|
||||
**base**: A base value of one is the original dimension of the texture
|
||||
when it reaches the stretch stage. Inserting other '''values positive or
|
||||
negative in this variable will produce unknown effects.
|
||||
|
||||
**<amplitude>**: This is the measurement of distance the texture will
|
||||
**amplitude**: This is the measurement of distance the texture will
|
||||
stretch from the base size. It is measured, like scroll, in textures. A
|
||||
value of 1 here will double the size of the texture at its peak.
|
||||
|
||||
**<phase>**: See the explanation for phase under the deform vertexes
|
||||
**phase**: See the explanation for phase under the deform vertexes
|
||||
keyword.
|
||||
|
||||
**<frequency>**: this is wave peaks per second.
|
||||
**frequency**: this is wave peaks per second.
|
||||
|
||||
**<func>**:
|
||||
**func**:
|
||||
|
||||
- **Sin**: the texture expands smoothly to its peak dimension and then
|
||||
shrinks smoothly to its valley dimension in a flowing manner.
|
||||
|
@ -122,13 +122,13 @@ forth churning and swirling effect on the texture.
|
|||
|
||||
The parameters for this are defined as follows:
|
||||
|
||||
- **<base>**: Currently undefined.
|
||||
- **<amplitude>**: This is essentially the intensity of the
|
||||
- **base**: Currently undefined.
|
||||
- **amplitude**: This is essentially the intensity of the
|
||||
disturbance or twisting and squiggling of the texture.
|
||||
- **<phase>**: See the explanation for phase under the
|
||||
- **phase**: See the explanation for phase under the
|
||||
[deformvertexes](DeformVertexes)
|
||||
keyword.
|
||||
- **<freq>**: Frequency. This value is expressed as repetitions or
|
||||
- **freq**: Frequency. This value is expressed as repetitions or
|
||||
cycles of the wave per second. A value of one would cycle once per
|
||||
second. A value of 10 would cycle 10 times per second. A value of
|
||||
0.1 would cycle once every 10 seconds.
|
15
Documentation/XR.md
Normal file
15
Documentation/XR.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# The XR Subsystem
|
||||
|
||||
To support XR (which is the support for Virtual, Augmented or Mixed Reality output) we have a few routines that help deal with this.
|
||||
|
||||
## Classes related to XR
|
||||
|
||||
We have 3 NSXRInput class instances per NSClient class, which itself belongs to a NSXRSpace.
|
||||
|
||||
### Head
|
||||
|
||||
The head is an NSXRInput of type XR_INPUT_HEAD. Yes, a head is just like any other XR compatible controller. It has a gyro and it potentially has buttons the user can press.
|
||||
|
||||
### Hands
|
||||
|
||||
We have two hands available, that will identify themselves as XR_INPUT_LEFT or XR_INPUT_RIGHT respectively. These are your primary tools for interacting with the 3D world.
|
|
@ -958,7 +958,7 @@ msgid "IDS_CONFIGURE_GOREHELP"
|
|||
msgstr "Disable visuals inappropriate for younger players and multiplayer."
|
||||
|
||||
msgid "IDS_CONFIGURE_AUTOPATCHHELP"
|
||||
msgstr "Download the latest version of %s."
|
||||
msgstr "Download updates for %s."
|
||||
|
||||
msgid "IDS_CHAT_NOSERVERS"
|
||||
msgstr "Could not locate any Frag-Net servers."
|
||||
|
@ -1652,3 +1652,33 @@ msgstr "Do you want to uncompress the files for game '%s'?"
|
|||
|
||||
msgid "IDS_FAVSVRS_CORRUPT"
|
||||
msgstr "The server data file favsvrs.dat appears to be corrupt.\n\nYou can request a new list of servers by pressing the Update button.\n\nDo you want to remove the corrupt file (you will have to re-enter your 'favorites' if you remove the file)?"
|
||||
|
||||
msgid "UPDATE_DISABLED"
|
||||
msgstr "Disabled"
|
||||
|
||||
msgid "UPDATE_ENABLED"
|
||||
msgstr "Enabled"
|
||||
|
||||
msgid "UPDATE_CORRUPT"
|
||||
msgstr "Corrupt"
|
||||
|
||||
msgid "UPDATE_NOTINSTALLED"
|
||||
msgstr "Not installed"
|
||||
|
||||
msgid "UPDATE_PENDING_INSTALL"
|
||||
msgstr "Install (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_REINSTALL"
|
||||
msgstr "Reinstall (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_UNINSTALL"
|
||||
msgstr "Uninstall (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_AUTOINSTALL"
|
||||
msgstr "Auto-install (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_DISABLE"
|
||||
msgstr "Disable (pending)"
|
||||
|
||||
msgid "UPDATE_PENDING_RETAIN"
|
||||
msgstr "Retain (pending)"
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
var int autocvar_menu_intro = TRUE;
|
||||
var int autocvar__menu_singleplayer;
|
||||
var bool autocvar_menu_steambg = false;
|
||||
|
||||
#define KEY_UNKNOWN -1
|
||||
#define KEY_GAME 0
|
||||
|
@ -59,50 +60,6 @@ typedef struct
|
|||
void(float evtype, float scanx, float chary, float devid) m_input;
|
||||
} menupage_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GAMEINFO_NONE,
|
||||
GAMEINFO_MANIFEST,
|
||||
GAMEINFO_GITXT,
|
||||
GAMEINFO_LIBLIST
|
||||
} gi_type;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
string game;
|
||||
string gamedir;
|
||||
string base_dir;
|
||||
string url_info;
|
||||
string url_dl;
|
||||
string version;
|
||||
string readme;
|
||||
int size;
|
||||
int svonly;
|
||||
int cldll;
|
||||
string type;
|
||||
string hlversion;
|
||||
string pkgname;
|
||||
string pkgfile;
|
||||
int pkgid;
|
||||
int nomodels;
|
||||
int nosprays;
|
||||
int installed;
|
||||
string mpentity;
|
||||
string gamedll;
|
||||
string startmap;
|
||||
string trainingmap;
|
||||
string fallback_dir;
|
||||
string chatroom;
|
||||
string menumap;
|
||||
string introvideo;
|
||||
int steambg;
|
||||
gi_type info_type;
|
||||
} gameinfo_t;
|
||||
|
||||
var int gameinfo_current = -1;
|
||||
int gameinfo_count;
|
||||
gameinfo_t *games;
|
||||
|
||||
int g_menupage;
|
||||
|
||||
enum
|
||||
|
|
|
@ -84,6 +84,7 @@ void
|
|||
m_init(void)
|
||||
{
|
||||
vector g_btnsize;
|
||||
string menuMap;
|
||||
|
||||
print("--------- Initializing Menu ----------\n");
|
||||
print("Built: " __DATE__ " " __TIME__"\n");
|
||||
|
@ -116,6 +117,7 @@ m_init(void)
|
|||
registercommand("map_background");
|
||||
registercommand("menu_musicstart");
|
||||
registercommand("richpresence_dump");
|
||||
registercommand("platformRefreshUpdates");
|
||||
|
||||
Font_Load("fonts/fontcon.font", font_console);
|
||||
Font_Load("fonts/menu_label.font", font_label);
|
||||
|
@ -133,38 +135,31 @@ m_init(void)
|
|||
g_btnofs = 26 / g_btnsize[1];
|
||||
|
||||
GameLibrary_Init();
|
||||
MapLibrary_Init();
|
||||
main_init();
|
||||
|
||||
Colors_Init();
|
||||
Strings_Init();
|
||||
Updates_Init();
|
||||
|
||||
if (games[gameinfo_current].gamedir != "valve" || games[gameinfo_current].steambg == 1) {
|
||||
if (GameLibrary_GetInfo(GAMEINFO_GAMEDIR) != "valve") {
|
||||
m_intro_skip();
|
||||
Music_MenuStart();
|
||||
}
|
||||
|
||||
if (games[gameinfo_current].pkgfile != "")
|
||||
if not (whichpack(games[gameinfo_current].pkgfile) || autocvar_menu_updating) {
|
||||
/* reload in case of video restarts? */
|
||||
shaderforname("logo_avi", "{\n{\nvideomap av:media/logo.avi\n}\n}");
|
||||
g_menupage = PAGE_UPDATES;
|
||||
}
|
||||
|
||||
Menu_AutoScale();
|
||||
Menu_GammaHack();
|
||||
|
||||
if (g_intro_stage == 0) {
|
||||
string videofile = games[gameinfo_current].introvideo;
|
||||
string videofile = GameLibrary_GetInfo(GAMEINFO_INTROVIDEO);
|
||||
|
||||
if (videofile) {
|
||||
localcmd(strcat("playvideo ", videofile, "\n"));
|
||||
}
|
||||
}
|
||||
|
||||
if (games[gameinfo_current].menumap != "") {
|
||||
string mapname = games[gameinfo_current].menumap;
|
||||
localcmd(strcat("map_background ", mapname, "\n"));
|
||||
menuMap = GameLibrary_GetInfo(GAMEINFO_MENUMAP);
|
||||
if (menuMap != "") {
|
||||
localcmd(strcat("map_background ", menuMap, "\n"));
|
||||
}
|
||||
|
||||
/* prepare spray logo keys */
|
||||
|
@ -285,7 +280,7 @@ m_draw(vector screensize)
|
|||
drawfill([0,0], screensize, [0,0,0], 1.0f);
|
||||
|
||||
/* draw either WON or Steam background */
|
||||
if (games[gameinfo_current].steambg == 0)
|
||||
if (autocvar_menu_steambg == false)
|
||||
Background_WON();
|
||||
else
|
||||
Background_Steam();
|
||||
|
@ -414,6 +409,9 @@ m_consolecommand(string cmd)
|
|||
localcmd(sprintf("maxplayers 2\nset coop 1\nset sv_background 1\nmap %s\n",
|
||||
argv(1)));
|
||||
break;
|
||||
case "platformRefreshUpdates":
|
||||
Updates_RefreshState();
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
|
|
|
@ -339,7 +339,7 @@ cr_makeconnection(void)
|
|||
string channel;
|
||||
i = TCP_Connect(&tcp_irc, "tcp://irc.frag-net.com:6667");
|
||||
|
||||
channel = games[gameinfo_current].chatroom;
|
||||
channel = GameLibrary_GetInfo(GAMEINFO_CHATROOM);
|
||||
|
||||
/* we're already setting a default channel, but a mod might set it
|
||||
set it to something empty to mess with us */
|
||||
|
|
|
@ -30,11 +30,6 @@ CFrame create_frMaps;
|
|||
CListBox create_lbMaps;
|
||||
CScrollbar create_sbMaps;
|
||||
|
||||
int g_mapcount;
|
||||
|
||||
int map_blacklist_count;
|
||||
string *map_blacklist;
|
||||
|
||||
void
|
||||
create_btnok_start(void)
|
||||
{
|
||||
|
@ -104,8 +99,7 @@ create_sbmaps_changed(int val)
|
|||
void
|
||||
menu_creategame_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
int realcount = 0;
|
||||
int mapCount = 0i;
|
||||
|
||||
fn_create = spawn(CWidget);
|
||||
create_btnAdv = spawn(CMainButton);
|
||||
|
@ -165,72 +159,15 @@ menu_creategame_init(void)
|
|||
create_sbMaps.SetCallback(create_sbmaps_changed);
|
||||
Widget_Add(fn_createshared, create_sbMaps);
|
||||
|
||||
/* map blacklist code */
|
||||
filestream fs_blacklist;
|
||||
fs_blacklist = fopen("scripts/map_blacklist", FILE_READ);
|
||||
/* fill in our list box */
|
||||
mapCount = MapLibrary_GetMapCount();
|
||||
|
||||
if (fs_blacklist < 0) {
|
||||
print("^1WARNING: ^7Could NOT load scripts/map_blacklist\n");
|
||||
for (int i = 0i; i < mapCount; i++) {
|
||||
string mapName = MapLibrary_GetInfo(i, MAPINFO_NAME);
|
||||
create_lbMaps.AddEntry(mapName);
|
||||
}
|
||||
|
||||
if (fs_blacklist >= 0) {
|
||||
string temp;
|
||||
|
||||
while ((temp = fgets(fs_blacklist))) {
|
||||
map_blacklist_count++;
|
||||
}
|
||||
|
||||
map_blacklist = memalloc(sizeof(string) * map_blacklist_count);
|
||||
fseek(fs_blacklist, 0);
|
||||
|
||||
i = 0;
|
||||
while ((temp = fgets(fs_blacklist))) {
|
||||
map_blacklist[i] = temp;
|
||||
i++;
|
||||
}
|
||||
|
||||
fclose(fs_blacklist);
|
||||
}
|
||||
|
||||
searchhandle mapsearch = search_begin("maps/*.bsp", SEARCH_NAMESORT | SEARCH_FULLPACKAGE, TRUE);
|
||||
g_mapcount = search_getsize(mapsearch);
|
||||
for (i = 0; i < g_mapcount; i++) {
|
||||
string tmp, dir;
|
||||
string gdir = games[gameinfo_current].gamedir;
|
||||
int list = TRUE;
|
||||
tmp = substring(search_getfilename(mapsearch, i), 5, -1);
|
||||
|
||||
/* work around FTEQW's path choice */
|
||||
if (gdir == "ftehl")
|
||||
gdir = "valve";
|
||||
|
||||
/* only look for maps in the current gamedir, requires SEARCH_FULLPACKAGE */
|
||||
dir = substring(search_getpackagename(mapsearch, i), 0, strlen(gdir));
|
||||
if (dir != gdir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ignore test_ prefix maps */
|
||||
if (substring(tmp, 0, 5) == "test_") {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* see if any of our blacklisted names match */
|
||||
for (int b = 0; b < map_blacklist_count; b++) {
|
||||
if (tmp == map_blacklist[b]) {
|
||||
list = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (list == TRUE) {
|
||||
create_lbMaps.AddEntry(tmp);
|
||||
realcount++;
|
||||
}
|
||||
}
|
||||
|
||||
create_sbMaps.SetMax(realcount);
|
||||
search_end(mapsearch);
|
||||
create_sbMaps.SetMax(mapCount);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -86,9 +86,9 @@ customgame_sbmods_changed(int val)
|
|||
void
|
||||
customgame_lbmods_changed(void)
|
||||
{
|
||||
int gid = customgame_lbMods.GetSelected();
|
||||
int gameID = customgame_lbMods.GetSelected();
|
||||
|
||||
if (games[gid].installed == TRUE) {
|
||||
if (GameLibrary_GetGameInfo(gameID, GAMEINFO_INSTALLED) == true) {
|
||||
customgame_btnActivate.SetExecute(customgame_btnactivate_start);
|
||||
customgame_btnInstall.SetExecute(__NULL__);
|
||||
} else {
|
||||
|
|
|
@ -224,8 +224,6 @@ menu_customize_init(void)
|
|||
}
|
||||
}
|
||||
search_end(searchy);
|
||||
} else {
|
||||
games[gameinfo_current].nosprays = 1;
|
||||
}
|
||||
|
||||
/* scan and cache the models */
|
||||
|
@ -240,8 +238,6 @@ menu_customize_init(void)
|
|||
precache_pic(g_models[i]);
|
||||
}
|
||||
search_end(searchy);
|
||||
} else {
|
||||
games[gameinfo_current].nomodels = 1;
|
||||
}
|
||||
|
||||
fn_customize = spawn(CWidget);
|
||||
|
@ -299,7 +295,7 @@ menu_customize_init(void)
|
|||
cz_sldReceiveVol.SetCallback(cz_sldReceiveVolChanged);
|
||||
Widget_Add(fn_customize, cz_sldReceiveVol);
|
||||
|
||||
if (games[gameinfo_current].nosprays == 0) {
|
||||
if (GameLibrary_GetInfo(GAMEINFO_NOSPRAYS) == false) {
|
||||
cz_psSpray = spawn(CPictureSwitch);
|
||||
cz_psSpray.SetPos(212,226);
|
||||
cz_psSpray.SetSize(99,124);
|
||||
|
@ -312,7 +308,7 @@ menu_customize_init(void)
|
|||
Widget_Add(fn_customize, cz_psSpray);
|
||||
}
|
||||
|
||||
if (games[gameinfo_current].nomodels == 0) {
|
||||
if (GameLibrary_GetInfo(GAMEINFO_NOPLAYERMODELS) == false) {
|
||||
#ifdef MODEL_PREVIEW
|
||||
static vector vecDistance = [ 45, 0, 0 ];
|
||||
static void ModelPreview_SetModel( string strModel ) {
|
||||
|
@ -485,7 +481,7 @@ menu_customize_draw(void)
|
|||
|
||||
|
||||
|
||||
if (games[gameinfo_current].nomodels == 0) {
|
||||
if (GameLibrary_GetInfo(GAMEINFO_NOPLAYERMODELS) == false) {
|
||||
drawfill([g_menuofs[0] + 410,g_menuofs[1] + 160], [170, 221], FRAME_COLOR, 1.0f);
|
||||
drawfill([g_menuofs[0] + 413,g_menuofs[1] + 163], [164,190], [0,0,0], 1.0f);
|
||||
WLabel_Static(410, 390, "Colors", 14, 14, [1,1,1],
|
||||
|
@ -516,7 +512,7 @@ menu_customize_draw(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (games[gameinfo_current].nosprays == 0)
|
||||
if (GameLibrary_GetInfo(GAMEINFO_NOSPRAYS) == false)
|
||||
WLabel_Static(212, 203, m_reslbl[IDS_PROFILE_LOGO], 14, 14, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ btn_training(void)
|
|||
{
|
||||
localcmd("stopmusic\n");
|
||||
localcmd("maxplayers 1\n");
|
||||
localcmd(games[gameinfo_current].trainingmap);
|
||||
localcmd(GameLibrary_GetInfo(GAMEINFO_TRAININGMAP));
|
||||
|
||||
/* TODO: Some mods may choose to put movies in this... */
|
||||
RichPresence_Clear();
|
||||
|
@ -195,7 +195,7 @@ menu_main_init(void)
|
|||
main_btnNewGame.SetImage(BTN_NEWGAME);
|
||||
main_btnNewGame.SetPos(70,208);
|
||||
/* new game not available in multiplayer_only */
|
||||
if (games[gameinfo_current].type != "Multiplayer")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TYPE) != "Multiplayer")
|
||||
main_btnNewGame.SetExecute(btn_newgame_start);
|
||||
Widget_Add(fn_main, main_btnNewGame);
|
||||
|
||||
|
@ -204,7 +204,7 @@ menu_main_init(void)
|
|||
main_btnTraining.SetImage(BTN_TRAINING);
|
||||
main_btnTraining.SetPos(70,236);
|
||||
/* some mods actively try to hide the option */
|
||||
if (games[gameinfo_current].trainingmap != "")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TRAININGMAP) != "")
|
||||
main_btnTraining.SetExecute(btn_training);
|
||||
Widget_Add(fn_main, main_btnTraining);
|
||||
|
||||
|
@ -220,7 +220,7 @@ menu_main_init(void)
|
|||
main_btnLoadGame.SetImage(BTN_LOADGAME);
|
||||
main_btnLoadGame.SetPos(70,292);
|
||||
/* disable in multiplayer_only */
|
||||
if (games[gameinfo_current].type != "Multiplayer")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TYPE) != "Multiplayer")
|
||||
main_btnLoadGame.SetExecute(btn_loadgame_start);
|
||||
Widget_Add(fn_main, main_btnLoadGame);
|
||||
|
||||
|
@ -229,7 +229,7 @@ menu_main_init(void)
|
|||
main_btnMultiplayer.SetImage(BTN_MULTIPLAYER);
|
||||
main_btnMultiplayer.SetPos(70,320);
|
||||
/* disable when it's singleplayer_only */
|
||||
if (games[gameinfo_current].type != "Singleplayer")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TYPE) != "Singleplayer")
|
||||
main_btnMultiplayer.SetExecute(btn_multiplayer_start);
|
||||
Widget_Add(fn_main, main_btnMultiplayer);
|
||||
|
||||
|
@ -296,14 +296,14 @@ menu_main_init(void)
|
|||
main_btn2NewGame.SetImage(BTN_NEWGAME);
|
||||
main_btn2NewGame.SetPos(70,236);
|
||||
/* disable in multiplayer_only */
|
||||
if (games[gameinfo_current].type != "Multiplayer")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TYPE) != "Multiplayer")
|
||||
main_btn2NewGame.SetExecute(btn_newgame_start);
|
||||
Widget_Add(fn_main2, main_btn2NewGame);
|
||||
|
||||
/* Training */
|
||||
main_btn2Training = spawn(CMainButton);
|
||||
main_btn2Training.SetImage(BTN_TRAINING);
|
||||
if (games[gameinfo_current].trainingmap)
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TRAININGMAP) != "")
|
||||
main_btn2Training.SetExecute(btn_training);
|
||||
main_btn2Training.SetPos(70,264);
|
||||
Widget_Add(fn_main2, main_btn2Training);
|
||||
|
@ -320,7 +320,7 @@ menu_main_init(void)
|
|||
main_btn2LoadGame.SetImage(BTN_SAVELOAD);
|
||||
main_btn2LoadGame.SetPos(70,320);
|
||||
/* disable in multiplayer_only */
|
||||
if (games[gameinfo_current].type != "Multiplayer")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TYPE) != "Multiplayer")
|
||||
main_btn2LoadGame.SetExecute(btn_loadgame_start);
|
||||
Widget_Add(fn_main2, main_btn2LoadGame);
|
||||
|
||||
|
@ -328,7 +328,7 @@ menu_main_init(void)
|
|||
main_btn2Multiplayer = spawn(CMainButton);
|
||||
main_btn2Multiplayer.SetImage(BTN_MULTIPLAYER);
|
||||
main_btn2Multiplayer.SetPos(70,348);
|
||||
if (games[gameinfo_current].type != "Singleplayer")
|
||||
if (GameLibrary_GetInfo(GAMEINFO_TYPE) != "Singleplayer")
|
||||
main_btn2Multiplayer.SetExecute(btn_multiplayer_start);
|
||||
Widget_Add(fn_main2, main_btn2Multiplayer);
|
||||
|
||||
|
@ -379,7 +379,7 @@ menu_main_draw(void)
|
|||
} else {
|
||||
#ifndef WEBMENU
|
||||
/* Don't even attempt to display the logo.avi otherwise */
|
||||
if (games[gameinfo_current].steambg == 0 && checkcommand("ffmpeg_videobitrate")) {
|
||||
if (autocvar_menu_steambg == false && checkcommand("ffmpeg_videobitrate")) {
|
||||
drawpic([g_menuofs[0],g_menuofs[1] + 70], g_bmp[LOGO_AVI],
|
||||
g_logosize, [1,1,1], 1.0f);
|
||||
g_logosize = gecko_get_texture_extent(g_bmp[LOGO_AVI]);
|
||||
|
|
|
@ -171,6 +171,12 @@ mp_btndisconnect(void)
|
|||
RichPresence_Clear();
|
||||
}
|
||||
|
||||
void
|
||||
mp_btnquickstart(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
menu_multiplayer_init(void)
|
||||
{
|
||||
|
@ -181,7 +187,7 @@ menu_multiplayer_init(void)
|
|||
/* unconnected menu */
|
||||
mp_btnQuickstart = spawn(CMainButton);
|
||||
mp_btnQuickstart.SetImage(BTN_QUICKSTART);
|
||||
//mp_btnQuickstart.SetExecute(btn_console);
|
||||
mp_btnQuickstart.SetExecute(mp_btnquickstart);
|
||||
mp_btnQuickstart.SetPos(50,140);
|
||||
Widget_Add(fn_multiplayer, mp_btnQuickstart);
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ ng_btneasy_start(void)
|
|||
g_menupage = PAGE_MAIN;
|
||||
localcmd("stopmusic\n");
|
||||
localcmd("set skill 1; maxplayers 1\n");
|
||||
localcmd(games[gameinfo_current].startmap);
|
||||
localcmd(GameLibrary_GetInfo(GAMEINFO_STARTMAP));
|
||||
RichPresence_Clear();
|
||||
RichPresence_Set("status", "Singleplayer: Easy");
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ ng_btnnormal_start(void)
|
|||
g_menupage = PAGE_MAIN;
|
||||
localcmd("stopmusic\n");
|
||||
localcmd("set skill 2; maxplayers 1\n");
|
||||
localcmd(games[gameinfo_current].startmap);
|
||||
localcmd(GameLibrary_GetInfo(GAMEINFO_STARTMAP));
|
||||
RichPresence_Clear();
|
||||
RichPresence_Set("status", "Singleplayer: Normal");
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ ng_btnhard_start(void)
|
|||
g_menupage = PAGE_MAIN;
|
||||
localcmd("stopmusic\n");
|
||||
localcmd("set skill 3; maxplayers 1\n");
|
||||
localcmd(games[gameinfo_current].startmap);
|
||||
localcmd(GameLibrary_GetInfo(GAMEINFO_STARTMAP));
|
||||
RichPresence_Clear();
|
||||
RichPresence_Set("status", "Singleplayer: Hard");
|
||||
}
|
||||
|
|
|
@ -38,19 +38,19 @@ up_btndone_start(void)
|
|||
cvar_set("menu_updating", "0");
|
||||
localsound("../media/launch_dnmenu1.wav");
|
||||
g_menupage = PAGE_CONFIGURATION;
|
||||
localcmd("seta menu_installedpackages 1;cfg_save\n");
|
||||
localcmd("pkg revert;seta menu_installedpackages 1;cfg_save\n");
|
||||
}
|
||||
|
||||
void
|
||||
up_btninstall_start(void)
|
||||
{
|
||||
Updates_Remove(up_lbUpdates.GetSelected());
|
||||
Updates_Install(up_lbUpdates.GetSelected());
|
||||
}
|
||||
|
||||
void
|
||||
up_btnremove_start(void)
|
||||
{
|
||||
Updates_Install(up_lbUpdates.GetSelected());
|
||||
Updates_Destroy(up_lbUpdates.GetSelected());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -76,7 +76,7 @@ up_lbupdates_changed(void)
|
|||
if (pkgid == -1)
|
||||
return;
|
||||
|
||||
newpic = sprintf(FN_UPDATE_IMGURL, updates[pkgid].name);
|
||||
newpic = Updates_GetInfo(pkgid, UPDATE_PREVIEWIMAGE);
|
||||
|
||||
if not (newpic)
|
||||
return;
|
||||
|
@ -94,7 +94,6 @@ up_sbupdates_changed(int val)
|
|||
void
|
||||
menu_updates_refresh(void)
|
||||
{
|
||||
Updates_Refresh();
|
||||
int updateCount = Updates_GetPackageCount();
|
||||
|
||||
up_sbUpdates.SetMax(updateCount);
|
||||
|
@ -119,19 +118,19 @@ menu_updates_init(void)
|
|||
up_btnApply = spawn(CMainButton);
|
||||
up_btnApply.SetImage(BTN_UPDATE);
|
||||
up_btnApply.SetExecute(up_btnapply_start);
|
||||
up_btnApply.SetPos(350+96,420+30);
|
||||
up_btnApply.SetPos(50 + 160,420+13);
|
||||
Widget_Add(fn_updates, up_btnApply);
|
||||
|
||||
up_btnInstall = spawn(CMainButton);
|
||||
up_btnInstall.SetImage(BTN_INSTALL);
|
||||
up_btnInstall.SetExecute(up_btninstall_start);
|
||||
up_btnInstall.SetPos(350,420);
|
||||
up_btnInstall.SetPos(380,400);
|
||||
Widget_Add(fn_updates, up_btnInstall);
|
||||
|
||||
up_btnDelete = spawn(CMainButton);
|
||||
up_btnDelete.SetImage(BTN_DELETE);
|
||||
up_btnDelete.SetExecute(up_btnremove_start);
|
||||
up_btnDelete.SetPos(350+200,420);
|
||||
up_btnDelete.SetPos(380,400+30);
|
||||
Widget_Add(fn_updates, up_btnDelete);
|
||||
|
||||
up_frUpdates = spawn(CFrame);
|
||||
|
@ -158,58 +157,43 @@ menu_updates_init(void)
|
|||
up_frPreview.SetPos(350,160);
|
||||
up_frPreview.SetSize(256+6,128+6);
|
||||
Widget_Add(fn_updates, up_frPreview);
|
||||
|
||||
Updates_Refresh();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Drawing */
|
||||
int g_pkgname_updating;
|
||||
void
|
||||
menu_updates_draw(void)
|
||||
{
|
||||
#ifndef WEBMENU
|
||||
static int old_enabled;
|
||||
|
||||
float fl = 0;
|
||||
|
||||
if (!g_updates_initialized) {
|
||||
int pkg_ready = 0;
|
||||
|
||||
/* we have no hard-coded list of supported packages, so query frag-net.com */
|
||||
if (!games[gameinfo_current].pkgname && !g_pkgname_updating) {
|
||||
string gamedir = games[gameinfo_current].gamedir;
|
||||
print(sprintf("Querying package names for %s\n", gamedir));
|
||||
uri_get(sprintf("http://www.frag-net.com/dl/packages_%s", uri_escape(gamedir)), MODSERVER_REQ_PKGNAMES);
|
||||
g_pkgname_updating = 1;
|
||||
}
|
||||
|
||||
/* don't query packages YET until we get a response */
|
||||
if (g_pkgname_updating == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* query until 1 package is ready */
|
||||
for (int i = 0; (Updates_GetInfo(i, GPMI_NAME)); i++) {
|
||||
string installed = Updates_GetInfo(i, GPMI_INSTALLED);
|
||||
/* increment to keep track */
|
||||
if (installed == "enabled")
|
||||
old_enabled++;
|
||||
|
||||
pkg_ready = 1;
|
||||
}
|
||||
|
||||
if (pkg_ready == 1) {
|
||||
menu_updates_refresh();
|
||||
g_updates_initialized = TRUE;
|
||||
}
|
||||
/* first draw run */
|
||||
if (g_updates_initialized == 0) {
|
||||
Updates_Init();
|
||||
g_updates_initialized = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
Widget_Draw(fn_updates);
|
||||
updaterStatus_t status = Updates_GetUpdaterStatus();
|
||||
|
||||
Header_Draw(HEAD_CONFIG);
|
||||
|
||||
/* we're still initializing... */
|
||||
if (g_updates_initialized == 2) {
|
||||
if (status == UPDATER_PENDING) {
|
||||
customgame_dlgWait.Draw();
|
||||
WField_Static(162, 180, "Contacting update server...", 320, 260,
|
||||
col_prompt_text, 1.0f, 2, font_label_p);
|
||||
return;
|
||||
} else if (status == UPDATER_INITIALIZED) {
|
||||
menu_updates_refresh();
|
||||
g_updates_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Widget_Draw(fn_updates);
|
||||
drawpic([g_menuofs[0]+550,g_menuofs[1]+10], g_bmp[FN_LOGO],[80,80], [1,1,1], 1.0f, 0);
|
||||
|
||||
WLabel_Static(50, 143, "Data files:", 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
|
@ -230,37 +214,22 @@ menu_updates_draw(void)
|
|||
1.0f, 0, font_arial);
|
||||
|
||||
int i = up_lbUpdates.GetSelected();
|
||||
i = updates[i].uid;
|
||||
|
||||
fl = 310;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_AUTHOR), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_AUTHOR), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_INSTALLED), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_STATUSSTRING), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_LICENSE), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_LICENSE), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_WEBSITE), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_WEBSITE), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial); fl += 18;
|
||||
WLabel_Static(420,fl, getpackagemanagerinfo(i, GPMI_VERSION), 11, 11, [1,1,1],
|
||||
WLabel_Static(420,fl, Updates_GetInfo(i, UPDATE_VERSION), 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
WLabel_Static(350, 143, "Preview:", 11, 11, [1,1,1],
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
/* check if we've got any more packages than upon init */
|
||||
int new_packages = 0;
|
||||
for (int b = 0; (getpackagemanagerinfo(b, GPMI_NAME)); b++) {
|
||||
string installed = getpackagemanagerinfo(b, GPMI_INSTALLED);
|
||||
|
||||
/* increment to keep track */
|
||||
if (installed == "enabled")
|
||||
new_packages++;
|
||||
}
|
||||
|
||||
if (old_enabled != new_packages) {
|
||||
old_enabled = new_packages;
|
||||
localcmd("menu_restart\nmenu_updates\n");
|
||||
}
|
||||
|
||||
if (g_updates_previewpic)
|
||||
drawpic([g_menuofs[0]+350+3,g_menuofs[1]+160+3], g_updates_previewpic, [256,128], [1,1,1], 1.0f);
|
||||
#endif
|
||||
|
|
|
@ -71,7 +71,7 @@ menu_viewreadme_init(void)
|
|||
|
||||
filestream rdme;
|
||||
string lstline;
|
||||
rdme = fopen(games[gameinfo_current].readme, FILE_READ);
|
||||
rdme = fopen(GameLibrary_GetInfo(GAMEINFO_READMEFILE), FILE_READ);
|
||||
if (rdme >= 0) {
|
||||
while((lstline = fgets(rdme))) {
|
||||
vr_lbReadme.AddWrapped(lstline);
|
||||
|
|
|
@ -19,6 +19,7 @@ Strings_Init(void)
|
|||
{
|
||||
filestream stringslst;
|
||||
string lstline;
|
||||
string gameTitle = GameLibrary_GetInfo(GAMEINFO_TITLE);
|
||||
|
||||
m_reslbl[IDS_LANGUAGE] = _("IDS_LANGUAGE");
|
||||
m_reslbl[IDS_BORDERLESS_REGFAIL] = _("IDS_BORDERLESS_REGFAIL");
|
||||
|
@ -209,19 +210,19 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_LOADSAVE_RETURN] = _("IDS_LOADSAVE_RETURN");
|
||||
m_reslbl[IDS_MAIN_RETURNHELP] = _("IDS_MAIN_RETURNHELP");
|
||||
m_reslbl[IDS_MAIN_NEWGAMEHELP] = _("IDS_MAIN_NEWGAMEHELP");
|
||||
m_reslbl[IDS_MAIN_TRAININGHELP] = sprintf(_("IDS_MAIN_TRAININGHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MAIN_TRAININGHELP] = sprintf(_("IDS_MAIN_TRAININGHELP"), gameTitle);
|
||||
m_reslbl[IDS_MAIN_LOADHELP] = _("IDS_MAIN_LOADHELP");
|
||||
m_reslbl[IDS_MAIN_LOADSAVEHELP] = _("IDS_MAIN_LOADSAVEHELP");
|
||||
m_reslbl[IDS_MAIN_CONFIGUREHELP] = _("IDS_MAIN_CONFIGUREHELP");
|
||||
m_reslbl[IDS_MAIN_READMEHELP] = _("IDS_MAIN_READMEHELP");
|
||||
m_reslbl[IDS_MAIN_ORDERHELP] = sprintf(_("IDS_MAIN_ORDERHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MAIN_QUITHELP] = sprintf(_("IDS_MAIN_QUITHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MAIN_ORDERHELP] = sprintf(_("IDS_MAIN_ORDERHELP"), gameTitle);
|
||||
m_reslbl[IDS_MAIN_QUITHELP] = sprintf(_("IDS_MAIN_QUITHELP"), gameTitle);
|
||||
m_reslbl[IDS_MAIN_QUICKHELP] = _("IDS_MAIN_QUICKHELP");
|
||||
m_reslbl[IDS_MAIN_MULTIPLAYERHELP] = sprintf(_("IDS_MAIN_MULTIPLAYERHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MAIN_MULTIPLAYERHELP] = sprintf(_("IDS_MAIN_MULTIPLAYERHELP"), gameTitle);
|
||||
m_reslbl[IDS_CHAT_PROMPT] = _("IDS_CHAT_PROMPT");
|
||||
m_reslbl[IDS_NEWGAME_EASYHELP] = sprintf(_("IDS_NEWGAME_EASYHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_NEWGAME_MEDIUMHELP] = sprintf(_("IDS_NEWGAME_MEDIUMHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_NEWGAME_DIFFICULTHELP] = sprintf(_("IDS_NEWGAME_DIFFICULTHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_NEWGAME_EASYHELP] = sprintf(_("IDS_NEWGAME_EASYHELP"), gameTitle);
|
||||
m_reslbl[IDS_NEWGAME_MEDIUMHELP] = sprintf(_("IDS_NEWGAME_MEDIUMHELP"), gameTitle);
|
||||
m_reslbl[IDS_NEWGAME_DIFFICULTHELP] = sprintf(_("IDS_NEWGAME_DIFFICULTHELP"), gameTitle);
|
||||
m_reslbl[IDS_NEWGAME_RETURNHELP] = _("IDS_NEWGAME_RETURNHELP");
|
||||
m_reslbl[IDS_NEWPROFILE_TITLE] = _("IDS_NEWPROFILE_TITLE");
|
||||
m_reslbl[IDS_NEWPROFILE_NAME] = _("IDS_NEWPROFILE_NAME");
|
||||
|
@ -235,7 +236,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_VIDEO_SCREENSIZE] = _("IDS_VIDEO_SCREENSIZE");
|
||||
m_reslbl[IDS_VIDEO_GAMMA] = _("IDS_VIDEO_GAMMA");
|
||||
m_reslbl[IDS_VIDEO_GLARE] = _("IDS_VIDEO_GLARE");
|
||||
m_reslbl[IDS_VIDEO_GAMMAHELP] = sprintf(_("IDS_VIDEO_GAMMAHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_VIDEO_GAMMAHELP] = sprintf(_("IDS_VIDEO_GAMMAHELP"), gameTitle);
|
||||
m_reslbl[IDS_VIDEO_GLAREHELP] = _("IDS_VIDEO_GLAREHELP");
|
||||
m_reslbl[IDS_VIDMODE_WINDOWED] = _("IDS_VIDMODE_WINDOWED");
|
||||
m_reslbl[IDS_VIDMODE_MOUSE] = _("IDS_VIDMODE_MOUSE");
|
||||
|
@ -254,7 +255,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_STATUS_SKIPSERVER] = _("IDS_STATUS_SKIPSERVER");
|
||||
m_reslbl[IDS_STATUS_ELPASEDTIME] = _("IDS_STATUS_ELPASEDTIME");
|
||||
m_reslbl[IDS_TRAINING_EXITCURRENT] = _("IDS_TRAINING_EXITCURRENT");
|
||||
m_reslbl[IDS_MAIN_QUITPROMPTINGAME] = sprintf(_("IDS_MAIN_QUITPROMPTINGAME"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MAIN_QUITPROMPTINGAME] = sprintf(_("IDS_MAIN_QUITPROMPTINGAME"), gameTitle);
|
||||
m_reslbl[IDS_MAIN_QUITPROMPT] = _("IDS_MAIN_QUITPROMPT");
|
||||
m_reslbl[IDS_CONTROLS_CANCELPROMPT] = _("IDS_CONTROLS_CANCELPROMPT");
|
||||
m_reslbl[IDS_LOAD_LOADPROMPT] = _("IDS_LOAD_LOADPROMPT");
|
||||
|
@ -305,11 +306,11 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_BTN_QUICK] = _("IDS_BTN_QUICK");
|
||||
m_reslbl[IDS_PROFILE_LOGO] = _("IDS_PROFILE_LOGO");
|
||||
m_reslbl[IDS_BTN_BROWSE] = _("IDS_BTN_BROWSE");
|
||||
m_reslbl[IDS_MULTI_BROWSEHELP] = sprintf(_("IDS_MULTI_BROWSEHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MULTI_BROWSEHELP] = sprintf(_("IDS_MULTI_BROWSEHELP"), gameTitle);
|
||||
m_reslbl[IDS_BTN_CHAT] = _("IDS_BTN_CHAT");
|
||||
m_reslbl[IDS_MULTI_CHATHELP] = sprintf(_("IDS_MULTI_CHATHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MULTI_CHATHELP] = sprintf(_("IDS_MULTI_CHATHELP"), gameTitle);
|
||||
m_reslbl[IDS_BTN_LAN] = _("IDS_BTN_LAN");
|
||||
m_reslbl[IDS_MULTI_LANHELP] = sprintf(_("IDS_MULTI_LANHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_MULTI_LANHELP] = sprintf(_("IDS_MULTI_LANHELP"), gameTitle);
|
||||
m_reslbl[IDS_BTN_CUSTOMIZE] = _("IDS_BTN_CUSTOMIZE");
|
||||
m_reslbl[IDS_MULTI_CUSTOMIZEHELP] = _("IDS_MULTI_CUSTOMIZEHELP");
|
||||
m_reslbl[IDS_CREATEROOM_ROOMPASSWORD] = _("IDS_CREATEROOM_ROOMPASSWORD");
|
||||
|
@ -340,12 +341,12 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_QUICKSTART_TITLE] = _("IDS_QUICKSTART_TITLE");
|
||||
m_reslbl[IDS_BTN_LISTROOMS] = _("IDS_BTN_LISTROOMS");
|
||||
m_reslbl[IDS_BTN_GORE] = _("IDS_BTN_GORE");
|
||||
m_reslbl[IDS_BTN_AUTOPATCH] = sprintf(_("IDS_BTN_AUTOPATCH"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_BTN_AUTOPATCH] = sprintf(_("IDS_BTN_AUTOPATCH"), gameTitle);
|
||||
m_reslbl[IDS_CONFIGURE_GOREHELP] = _("IDS_CONFIGURE_GOREHELP");
|
||||
m_reslbl[IDS_CONFIGURE_AUTOPATCHHELP] = sprintf(_("IDS_CONFIGURE_AUTOPATCHHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_CONFIGURE_AUTOPATCHHELP] = sprintf(_("IDS_CONFIGURE_AUTOPATCHHELP"), gameTitle);
|
||||
m_reslbl[IDS_CHAT_NOSERVERS] = _("IDS_CHAT_NOSERVERS");
|
||||
m_reslbl[IDS_CHAT_NOPROFILE] = _("IDS_CHAT_NOPROFILE");
|
||||
m_reslbl[IDS_INIT_DX6REQUIRED] = sprintf(_("IDS_INIT_DX6REQUIRED"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_INIT_DX6REQUIRED] = sprintf(_("IDS_INIT_DX6REQUIRED"), gameTitle);
|
||||
m_reslbl[IDS_FNET_VALIDATIONFAIL] = _("IDS_FNET_VALIDATIONFAIL");
|
||||
m_reslbl[IDS_FNET_VALIDATIONFAIL2] = _("IDS_FNET_VALIDATIONFAIL2");
|
||||
m_reslbl[IDS_FNET_AUTHOUTOFORDER] = _("IDS_FNET_AUTHOUTOFORDER");
|
||||
|
@ -353,7 +354,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_FNET_ENCRYPTBAD] = _("IDS_FNET_ENCRYPTBAD");
|
||||
m_reslbl[IDS_FNET_BADPUBLICKEY] = _("IDS_FNET_BADPUBLICKEY");
|
||||
m_reslbl[IDS_FNET_AUTHNOMEM] = _("IDS_FNET_AUTHNOMEM");
|
||||
m_reslbl[IDS_CD_NEEDCDKEY] = sprintf(_("IDS_CD_NEEDCDKEY"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_CD_NEEDCDKEY] = sprintf(_("IDS_CD_NEEDCDKEY"), gameTitle);
|
||||
m_reslbl[IDS_CD_BADKEY] = _("IDS_CD_BADKEY");
|
||||
m_reslbl[IDS_CD_BADKEYTYPED] = _("IDS_CD_BADKEYTYPED");
|
||||
m_reslbl[IDS_MD5_HASHFAIL] = _("IDS_MD5_HASHFAIL");
|
||||
|
@ -372,7 +373,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_CHAT_NOROOMLIST] = _("IDS_CHAT_NOROOMLIST");
|
||||
m_reslbl[IDS_SAVELOAD_NUMBEROFGAMESCHANGED] = _("IDS_SAVELOAD_NUMBEROFGAMESCHANGED");
|
||||
m_reslbl[IDS_MAIN_EXITMULTIPLAYERPROMPT] = _("IDS_MAIN_EXITMULTIPLAYERPROMPT");
|
||||
m_reslbl[IDS_CD_ENTERPROMPT] = sprintf(_("IDS_CD_ENTERPROMPT"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_CD_ENTERPROMPT] = sprintf(_("IDS_CD_ENTERPROMPT"), gameTitle);
|
||||
m_reslbl[IDS_MULTISELECT_EXITGAMEPROMPT] = _("IDS_MULTISELECT_EXITGAMEPROMPT");
|
||||
m_reslbl[IDS_MULTI_ADDSERVERPROMPT] = _("IDS_MULTI_ADDSERVERPROMPT");
|
||||
m_reslbl[IDS_ROOM_NEEDPASS] = _("IDS_ROOM_NEEDPASS");
|
||||
|
@ -416,7 +417,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_GORE_BADPW] = _("IDS_GORE_BADPW");
|
||||
m_reslbl[IDS_BTN_ADVANCEDSVR] = _("IDS_BTN_ADVANCEDSVR");
|
||||
m_reslbl[IDS_OPTS_AUTOAIM] = _("IDS_OPTS_AUTOAIM");
|
||||
m_reslbl[IDS_OPTS_AUTOAIMHELP] = sprintf(_("IDS_OPTS_AUTOAIMHELP"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_OPTS_AUTOAIMHELP] = sprintf(_("IDS_OPTS_AUTOAIMHELP"), gameTitle);
|
||||
m_reslbl[IDS_BTN_PREVIEWS] = _("IDS_BTN_PREVIEWS");
|
||||
m_reslbl[IDS_MAIN_PREVIEWSHELP] = _("IDS_MAIN_PREVIEWSHELP");
|
||||
m_reslbl[IDS_SECONDS_LEFT] = _("IDS_SECONDS_LEFT");
|
||||
|
@ -452,8 +453,8 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_VID_RESELECT] = _("IDS_VID_RESELECT");
|
||||
m_reslbl[IDS_VID_INITFAIL] = _("IDS_VID_INITFAIL");
|
||||
m_reslbl[IDS_NET_FNETCONNFAIL] = _("IDS_NET_FNETCONNFAIL");
|
||||
m_reslbl[IDS_NET_CORRUPT] = sprintf(_("IDS_NET_CORRUPT"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_CDKEY_BAD] = sprintf(_("IDS_CDKEY_BAD"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_NET_CORRUPT] = sprintf(_("IDS_NET_CORRUPT"), gameTitle);
|
||||
m_reslbl[IDS_CDKEY_BAD] = sprintf(_("IDS_CDKEY_BAD"), gameTitle);
|
||||
m_reslbl[IDS_MULTI_REFRESH] = _("IDS_MULTI_REFRESH");
|
||||
m_reslbl[IDS_CHAT_NOROOM] = _("IDS_CHAT_NOROOM");
|
||||
m_reslbl[IDS_RUN_PATCH] = _("IDS_RUN_PATCH");
|
||||
|
@ -464,7 +465,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_LOGO_POWEROF2] = _("IDS_LOGO_POWEROF2");
|
||||
m_reslbl[IDS_MODEM_CUSTOM] = _("IDS_MODEM_CUSTOM");
|
||||
m_reslbl[IDS_MODEM_RATE] = _("IDS_MODEM_RATE");
|
||||
m_reslbl[IDS_REGISTRY_UPDATE] = sprintf(_("IDS_REGISTRY_UPDATE"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_REGISTRY_UPDATE] = sprintf(_("IDS_REGISTRY_UPDATE"), gameTitle);
|
||||
m_reslbl[IDS_CHAT_JOIN] = _("IDS_CHAT_JOIN");
|
||||
m_reslbl[IDS_CHAT_FLOOD] = _("IDS_CHAT_FLOOD");
|
||||
m_reslbl[IDS_CHAT_SEARCH] = _("IDS_CHAT_SEARCH");
|
||||
|
@ -476,21 +477,21 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_CHAT_NOSUCHROOM] = _("IDS_CHAT_NOSUCHROOM");
|
||||
m_reslbl[IDS_CHAT_ROOMFULL] = _("IDS_CHAT_ROOMFULL");
|
||||
m_reslbl[IDS_CREATESV_NOADVANCED] = _("IDS_CREATESV_NOADVANCED");
|
||||
m_reslbl[IDS_FNET_CDINUSE] = sprintf(_("IDS_FNET_CDINUSE"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_FNET_CDINUSE] = sprintf(_("IDS_FNET_CDINUSE"), gameTitle);
|
||||
m_reslbl[IDS_CHAT_JOINHINT] = _("IDS_CHAT_JOINHINT");
|
||||
m_reslbl[IDS_FNET_BANNED] = _("IDS_FNET_BANNED");
|
||||
m_reslbl[IDS_CONTENT_NOMULTIPLAYER] = _("IDS_CONTENT_NOMULTIPLAYER");
|
||||
m_reslbl[IDS_PATCH_ERROR] = sprintf(_("IDS_PATCH_ERROR"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_PATCH_ERROR] = sprintf(_("IDS_PATCH_ERROR"), gameTitle);
|
||||
m_reslbl[IDS_PATCH_NOUTIL] = _("IDS_PATCH_NOUTIL");
|
||||
m_reslbl[IDS_PATCH_FAIL] = _("IDS_PATCH_FAIL");
|
||||
m_reslbl[IDS_PATCH_BADINSTALL] = sprintf(_("IDS_PATCH_BADINSTALL"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_PATCH_BADINSTALL] = sprintf(_("IDS_PATCH_BADINSTALL"), gameTitle);
|
||||
m_reslbl[IDS_CONNECT_FAILURE] = _("IDS_CONNECT_FAILURE");
|
||||
m_reslbl[IDS_MULTI_NEEDPASSWORD] = _("IDS_MULTI_NEEDPASSWORD");
|
||||
m_reslbl[IDS_VID_HINT] = _("IDS_VID_HINT");
|
||||
m_reslbl[IDS_MULTI_LOGODISCONNECT] = _("IDS_MULTI_LOGODISCONNECT");
|
||||
m_reslbl[IDS_3D_WARNING] = sprintf(_("IDS_3D_WARNING"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_3D_WARNING] = sprintf(_("IDS_3D_WARNING"), gameTitle);
|
||||
m_reslbl[IDS_3DSITE_URL] = _("IDS_3DSITE_URL");
|
||||
m_reslbl[IDS_FNET_MODIFIED] = sprintf(_("IDS_FNET_MODIFIED"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_FNET_MODIFIED] = sprintf(_("IDS_FNET_MODIFIED"), gameTitle);
|
||||
m_reslbl[IDS_ADVANCEDMP_OFFSETS] = _("IDS_ADVANCEDMP_OFFSETS");
|
||||
m_reslbl[IDS_AUDIO_OFFSET] = _("IDS_AUDIO_OFFSET");
|
||||
m_reslbl[IDS_CONFIGURE_OFFSET] = _("IDS_CONFIGURE_OFFSET");
|
||||
|
@ -559,7 +560,7 @@ Strings_Init(void)
|
|||
m_reslbl[IDS_NO] = _("IDS_NO");
|
||||
m_reslbl[IDS_UPDATE] = _("IDS_UPDATE");
|
||||
m_reslbl[IDS_MODREQ_TITLE] = _("IDS_MODREQ_TITLE");
|
||||
m_reslbl[IDS_DOWNLOAD_WARNING] = sprintf(_("IDS_DOWNLOAD_WARNING"), games[gameinfo_current].game);
|
||||
m_reslbl[IDS_DOWNLOAD_WARNING] = sprintf(_("IDS_DOWNLOAD_WARNING"), gameTitle);
|
||||
m_reslbl[IDS_WARN_CHECKPROMPT] = _("IDS_WARN_CHECKPROMPT");
|
||||
m_reslbl[IDS_MOD_VERSION] = _("IDS_MOD_VERSION");
|
||||
m_reslbl[IDS_MOD_REINSTALL] = _("IDS_MOD_REINSTALL");
|
||||
|
|
|
@ -55,15 +55,29 @@ CModList::Draw(void)
|
|||
{
|
||||
int visible;
|
||||
int pos;
|
||||
string gameType;
|
||||
string gameTitle;
|
||||
string gameURL;
|
||||
int gameSize;
|
||||
string gameVersion;
|
||||
bool gameInstalled;
|
||||
|
||||
drawfill([g_menuofs[0] + m_x, g_menuofs[1] + m_y], [m_size[0], m_size[1]],
|
||||
[0,0,0], 1.0f);
|
||||
|
||||
visible = floor(m_size[1] / 29);
|
||||
visible = bound(0, visible, gameinfo_count - 1);
|
||||
visible = bound(0, visible, GameLibrary_GetGameCount() - 1);
|
||||
pos = m_y;
|
||||
|
||||
for (int i = m_scroll; i <= (visible + m_scroll); i++) {
|
||||
vector colo;
|
||||
gameType = GameLibrary_GetGameInfo(i, GAMEINFO_TYPE);
|
||||
gameTitle = GameLibrary_GetGameInfo(i, GAMEINFO_TITLE);
|
||||
gameURL = GameLibrary_GetGameInfo(i, GAMEINFO_WEBSITE);
|
||||
gameSize = GameLibrary_GetGameInfo(i, GAMEINFO_SIZE);
|
||||
gameVersion = GameLibrary_GetGameInfo(i, GAMEINFO_VERSION);
|
||||
gameInstalled = GameLibrary_GetGameInfo(i, GAMEINFO_INSTALLED);
|
||||
|
||||
if (m_selected == i) {
|
||||
colo = ML_COL_2;
|
||||
drawfill([g_menuofs[0] + m_x, g_menuofs[1] + pos], [m_size[0], 29],
|
||||
|
@ -72,33 +86,33 @@ CModList::Draw(void)
|
|||
colo = ML_COL_1;
|
||||
}
|
||||
|
||||
if (games[i].type != "") {
|
||||
if (gameType!= "") {
|
||||
drawsetcliparea(g_menuofs[0] + m_x + 2, g_menuofs[1] + pos + 3, 50,30);
|
||||
WLabel_Static(m_x + 2, pos + 3, games[i].type,
|
||||
WLabel_Static(m_x + 2, pos + 3, gameType,
|
||||
11, 11, colo, 1.0f, 0, font_arial);
|
||||
drawresetcliparea();
|
||||
}
|
||||
|
||||
/* Game */
|
||||
drawsetcliparea(g_menuofs[0] + m_x + 57, g_menuofs[1] + pos + 3, 112,30);
|
||||
WLabel_Static(m_x + 57, pos + 3, games[i].game, 11, 11, colo,
|
||||
WLabel_Static(m_x + 57, pos + 3, gameTitle, 11, 11, colo,
|
||||
1.0f, 0, font_arial);
|
||||
drawresetcliparea();
|
||||
/* URL */
|
||||
WLabel_Static(m_x + 2, pos + 18, sprintf("Info: %s", games[i].url_info), 11, 11, ML_COL_4,
|
||||
WLabel_Static(m_x + 2, pos + 18, sprintf("Info: %s", gameURL), 11, 11, ML_COL_4,
|
||||
1.0f, 0, font_arial);
|
||||
/* Version */
|
||||
WLabel_Static(m_x + 177, pos + 3, games[i].version, 11, 11, colo,
|
||||
WLabel_Static(m_x + 177, pos + 3, gameVersion, 11, 11, colo,
|
||||
1.0f, 0, font_arial);
|
||||
/* Size */
|
||||
float size = games[i].size / 1024000;
|
||||
float size = gameSize / 1024000;
|
||||
WLabel_Static(m_x + 227, pos + 3, sprintf("%.1fmb", size), 11, 11, colo,
|
||||
1.0f, 0, font_arial);
|
||||
/* Rating */
|
||||
WLabel_Static(m_x + 277, pos + 3, "0.0", 11, 11, colo,
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
if (games[i].installed == 1) {
|
||||
if (gameInstalled == true) {
|
||||
/* Installed */
|
||||
WLabel_Static(m_x + 327, pos + 3, "Yes", 11, 11, ML_COL_3,
|
||||
1.0f, 0, font_arial);
|
||||
|
@ -131,7 +145,7 @@ CModList::Input(float type, float x, float y, float devid)
|
|||
int pos[2];
|
||||
|
||||
visible = floor(m_size[1] / 29);
|
||||
visible = bound(0, visible, gameinfo_count - 1);
|
||||
visible = bound(0, visible, GameLibrary_GetGameCount() - 1);
|
||||
|
||||
pos[0] = m_x;
|
||||
pos[1] = m_y;
|
||||
|
|
|
@ -66,6 +66,9 @@ CUpdateList::Draw(void)
|
|||
|
||||
for (int i = m_scroll; i < (visible + m_scroll); i++) {
|
||||
vector colo;
|
||||
string updateTitle = Updates_GetInfo(i, UPDATE_TITLE);
|
||||
updateState_t updateState = Updates_GetInfo(i, UPDATE_STATE);
|
||||
updateAction_t updateAction = Updates_GetInfo(i, UPDATE_ACTION);
|
||||
|
||||
if (m_selected == i) {
|
||||
colo = ML_COL_2;
|
||||
|
@ -75,60 +78,55 @@ CUpdateList::Draw(void)
|
|||
colo = ML_COL_1;
|
||||
}
|
||||
|
||||
int uid = updates[i].uid;
|
||||
string status = Updates_GetInfo(uid, GPMI_INSTALLED);
|
||||
|
||||
switch (status) {
|
||||
case "":
|
||||
if (updates[i].installed == "") {
|
||||
colo = [1,0,0];
|
||||
} else if (updates[i].installed == "pending") {
|
||||
colo = [0,1,0];
|
||||
} else if (updates[i].installed == "enabled") {
|
||||
colo = colo;
|
||||
}
|
||||
switch (updateState) {
|
||||
case UPDATESTATE_ENABLED:
|
||||
colo = ML_COL_1;
|
||||
break;
|
||||
case "pending":
|
||||
colo[0] *= 0.5;
|
||||
colo[1] *= 0.5;
|
||||
colo[2] *= 0.5;
|
||||
case UPDATESTATE_CORRUPT:
|
||||
colo = [1, 0, 0]; /* red */
|
||||
break;
|
||||
case "enabled":
|
||||
colo = colo;
|
||||
break;
|
||||
case "present":
|
||||
colo[0] *= 0.5;
|
||||
colo[1] *= 0.5;
|
||||
colo[2] *= 0.5;
|
||||
break;
|
||||
case "corrupt":
|
||||
colo = [1,0,0] * sin(time);
|
||||
break;
|
||||
default:
|
||||
float p = stof(status) / 100;
|
||||
case UPDATESTATE_PENDING:
|
||||
float p = Updates_GetInfo(i, UPDATE_DLPERCENTAGE) / 100;
|
||||
colo = [0,1,0] * p;
|
||||
drawfill([g_menuofs[0] + m_x, g_menuofs[1] + pos], [m_size[0] * p, 18],
|
||||
colo, 0.5f);
|
||||
|
||||
colo = [0.25,0.25,0.25] + ([0.75,0.75,0.75] * p);
|
||||
break;
|
||||
case UPDATESTATE_DISABLED:
|
||||
case UPDATESTATE_NONE:
|
||||
colo = [0.5, 0.5, 0.5]; /* grey */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: make this integrate with the above better */
|
||||
if (updates[i].installed == "rem") {
|
||||
if ((time*2) & 1)
|
||||
colo = [1,0,0];
|
||||
else
|
||||
colo = [0,0,0];
|
||||
} else if (updates[i].installed == "in") {
|
||||
if ((time*2) & 1)
|
||||
if ((time*2) & 1) {
|
||||
switch (updateAction) {
|
||||
case UPDATEACTION_INSTALL: /* blinking orange */
|
||||
colo = [1,1,0];
|
||||
else
|
||||
colo = [0,0,0];
|
||||
break;
|
||||
case UPDATEACTION_REINSTALL:
|
||||
colo = [0,1,0];
|
||||
break;
|
||||
case UPDATEACTION_UNINSTALL: /* blinking red */
|
||||
colo = [1,0,0];
|
||||
break;
|
||||
case UPDATEACTION_AUTOINSTALL: /* blinking orange/grey */
|
||||
colo = [0.5,0.5,0];
|
||||
break;
|
||||
case UPDATEACTION_DISABLE: /* blinking grey/color */
|
||||
colo = [0.5,0.5,0.5];
|
||||
break;
|
||||
case UPDATEACTION_RETAIN:
|
||||
case UPDATEACTION_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Game */
|
||||
WLabel_Static(m_x + 3, pos + 3, updates[i].title, 11, 11, colo,
|
||||
WLabel_Static(m_x + 3, pos + 3, updateTitle, 11, 11, colo,
|
||||
1.0f, 0, font_arial);
|
||||
|
||||
pos += 18;
|
||||
|
|
|
@ -23,4 +23,22 @@
|
|||
#include "servers.h"
|
||||
#include "tcp.h"
|
||||
#include "updates.h"
|
||||
#include "gamelibrary.h"
|
||||
#include "gamelibrary.h"
|
||||
#include "maplibrary.h"
|
||||
|
||||
/** Definitions for FTE's internal package manager. We don't want you to talk to this one directly within Nuclide. */
|
||||
typedef enum
|
||||
{
|
||||
GPMI_NAME, /**< name of the package, for use with the pkg command. */
|
||||
GPMI_CATEGORY, /**< category text */
|
||||
GPMI_TITLE, /**< name of the package, for showing the user. */
|
||||
GPMI_VERSION, /**< version info (may have multiple with the same name but different versions) */
|
||||
GPMI_DESCRIPTION, /**< some blurb */
|
||||
GPMI_LICENSE, /**< what license its distributed under */
|
||||
GPMI_AUTHOR, /**< name of the person(s) who created it */
|
||||
GPMI_WEBSITE, /**< where to contribute/find out more info/etc */
|
||||
GPMI_INSTALLED, /**< current state */
|
||||
GPMI_ACTION, /**< desired state */
|
||||
GPMI_AVAILABLE, /**< whether it may be downloaded or not. */
|
||||
GPMI_FILESIZE, /**< size to download. */
|
||||
} packageType_t;
|
|
@ -14,6 +14,65 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*! @file gamelibrary.h
|
||||
@brief Game library parsing and querying of metadata.
|
||||
|
||||
The GameLibrary concerns itself with everything around what a game is,
|
||||
how to install, activate and deactivate it. Mods are included in this,
|
||||
so we'll proceed calling them 'games' or 'custom games'.
|
||||
|
||||
A game can be installed through two primary means:
|
||||
|
||||
- Manual install, like from a .zip or some installer or archive
|
||||
- Engine package manager install, through our own user interface
|
||||
|
||||
And between these, they can come with different metadata/manifests.
|
||||
|
||||
It assumed that every game has either a FTE Manifest description,
|
||||
a gameinfo.txt (Source Engine format) or liblist.gam (GoldSrc format)
|
||||
that describes various aspects of the game. Like which version it is, what
|
||||
map will be loaded when you press 'New Game' and so on.
|
||||
|
||||
If that info is not available, some placeholder data will be used instead.
|
||||
However, games installed via the package manager will at least for the
|
||||
custom game menus not use the on-disk manifest file, but information
|
||||
provided by the package manager. Once you switch into said game everything
|
||||
within will be pulled from a file on disk, such as a liblist.gam or gameinfo.txt.
|
||||
|
||||
The menu needs to call GameLibrary_Init() once for parsing the currently running
|
||||
game its own metadata. If you want to index custom games, aka mods, you need
|
||||
to do so with GameLibrary_InitCustom() afterwards.
|
||||
|
||||
Because indexing mods can take a very long time depending on the amount
|
||||
that is stored on disk, you may want to call GameLibrary_InitCustom() at
|
||||
a later time.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GAMEINFO_TITLE, /**< (string) The title of the game. E.g. "Action Game" */
|
||||
GAMEINFO_GAMEDIR, /**< (string) The game directory name. E.g. "data" */
|
||||
GAMEINFO_FALLBACKDIR, /**< (string) The directory to be loaded before the game directory. */
|
||||
GAMEINFO_BASEDIR, /**< (string) The first game directory to be loaded. */
|
||||
GAMEINFO_WEBSITE, /**< (string) The game its official website. */
|
||||
GAMEINFO_VERSION, /**< (string) Version number string. */
|
||||
GAMEINFO_SIZE, /**< (int) The size of the game, in bytes. */
|
||||
GAMEINFO_TYPE, /**< (string) The game type. E.g. "Singleplayer" */
|
||||
GAMEINFO_NOPLAYERMODELS,/**< (bool) If the game allows player model selection. */
|
||||
GAMEINFO_NOSPRAYS, /**< (bool) If the game allows custom spray logos. */
|
||||
GAMEINFO_STARTMAP, /**< (string) The command for starting a new game. */
|
||||
GAMEINFO_TRAININGMAP, /**< (string) The command for starting the training. */
|
||||
GAMEINFO_MINVERSION, /**< (string) The minimum base game version. */
|
||||
GAMEINFO_CHATROOM, /**< (string) The chatroom for this game. E.g. #action */
|
||||
GAMEINFO_READMEFILE, /**< (string) File name of the readme documentation. */
|
||||
GAMEINFO_INTROVIDEO, /**< (string) File name of the intro video to play. */
|
||||
GAMEINFO_MENUMAP, /**< (string) Name of the map to be used as a background. */
|
||||
GAMEINFO_AUTHOR, /**< (string) Name of the author. */
|
||||
GAMEINFO_AUTHORSITE, /**< (string) The author their website. */
|
||||
GAMEINFO_PACKAGELIST, /**< (string) List of packages, separated by white-space. */
|
||||
GAMEINFO_INSTALLED, /**< (bool) Whether the game is installed. */
|
||||
} gameInfo_t;
|
||||
|
||||
/** Called when initializing the current game. Does not cache custom game/mod info. */
|
||||
void GameLibrary_Init(void);
|
||||
/** Called when you want to initialize custom games/mods. Might want to call this later
|
||||
|
@ -30,4 +89,57 @@ void GameLibrary_Deactivate(void);
|
|||
/** Returns true/false depending on if a Game installation is in progress. */
|
||||
bool GameLibrary_IsInstalling(void);
|
||||
/** Returns a 0-100% value of game install progress, tracking across multiple packages. */
|
||||
float GameLibrary_InstallProgress(void);
|
||||
float GameLibrary_InstallProgress(void);
|
||||
/** Returns the total amount of games currently available. */
|
||||
int GameLibrary_GetGameCount(void);
|
||||
/** Return the ID for the currently active game. */
|
||||
int GameLibrary_GetCurrentGame(void);
|
||||
/** Retrieves fields for a given game. See gameInfo_t for a list of fields you can query. */
|
||||
__variant GameLibrary_GetGameInfo(int, gameInfo_t);
|
||||
/** Retrieves fields for the currently running game. See gameInfo_t for a list of fields you can query. */
|
||||
__variant GameLibrary_GetInfo(gameInfo_t);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GAMEINFO_NONE, /**< No gameinfo available. This is probably the engine making assumptions. */
|
||||
GAMEINFO_MANIFEST, /**< Game info was read from a manifest within the path. */
|
||||
GAMEINFO_GITXT, /**< Game info stems from a Source Engine style gameinfo.txt file. */
|
||||
GAMEINFO_LIBLIST, /**< Game info stems from a GoldSrc style liblist.gam file. */
|
||||
GAMEINFO_PACKAGE,
|
||||
} gi_type;
|
||||
|
||||
#ifndef DOXYGEN
|
||||
typedef struct
|
||||
{
|
||||
string game;
|
||||
string gamedir;
|
||||
string base_dir;
|
||||
string url_info;
|
||||
string url_dl;
|
||||
string version;
|
||||
string readme;
|
||||
int size;
|
||||
int svonly;
|
||||
int cldll;
|
||||
string type;
|
||||
string minversion;
|
||||
string pkgname;
|
||||
string pkgfile;
|
||||
int pkgid;
|
||||
int nomodels;
|
||||
int nosprays;
|
||||
int installed;
|
||||
string mpentity;
|
||||
string gamedll;
|
||||
string startmap;
|
||||
string trainingmap;
|
||||
string fallback_dir;
|
||||
string chatroom;
|
||||
string menumap;
|
||||
string introvideo;
|
||||
gi_type info_type;
|
||||
} gameinfo_t;
|
||||
|
||||
int gameinfo_count;
|
||||
gameinfo_t *games;
|
||||
#endif
|
|
@ -17,6 +17,8 @@
|
|||
int g_iModInstallCache;
|
||||
string g_strModInstallCache;
|
||||
|
||||
var int gameinfo_current = -1;
|
||||
|
||||
/* local game/mod info parsing */
|
||||
static void
|
||||
GameLibrary_Set(int id)
|
||||
|
@ -26,6 +28,27 @@ GameLibrary_Set(int id)
|
|||
cvar_set("com_fullgamename", games[id].game);
|
||||
}
|
||||
|
||||
static int
|
||||
GameLibrary_IDForPackageName(string packageName)
|
||||
{
|
||||
string f;
|
||||
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string name;
|
||||
name = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
|
||||
/* Spike started randomly putting version numbers into package names */
|
||||
f = sprintf("%s=%s", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
/** Looks for a single file inside a gamedir, including its pk3s and returns a valid filehandle if it is found. */
|
||||
static filestream
|
||||
GameLibrary_FindInGameDir(string filename, string gamedirname)
|
||||
|
@ -162,8 +185,8 @@ GameLibrary_LibListParse(int id, string strKey, string strValue)
|
|||
}
|
||||
break;
|
||||
case "minversion":
|
||||
case "hlversion":
|
||||
games[id].hlversion = strValue;
|
||||
case "minversion":
|
||||
games[id].minversion = strValue;
|
||||
break;
|
||||
case "nomodels":
|
||||
games[id].nomodels = (int)stof(strValue);
|
||||
|
@ -186,7 +209,7 @@ GameLibrary_LibListParse(int id, string strKey, string strValue)
|
|||
/* newly added with Nuclide */
|
||||
case "pkgname":
|
||||
games[id].pkgname = strValue;
|
||||
games[id].pkgid = Updates_IDForName(games[id].pkgname);
|
||||
games[id].pkgid = GameLibrary_IDForPackageName(games[id].pkgname);
|
||||
break;
|
||||
case "pkgfile":
|
||||
games[id].pkgfile = strValue;
|
||||
|
@ -203,9 +226,6 @@ GameLibrary_LibListParse(int id, string strKey, string strValue)
|
|||
case "introvideo":
|
||||
games[id].introvideo = strValue;
|
||||
break;
|
||||
case "steambg":
|
||||
games[id].steambg = (int)stof(strValue);
|
||||
break;
|
||||
case "base_dir":
|
||||
games[id].base_dir = strValue;
|
||||
break;
|
||||
|
@ -377,13 +397,12 @@ GameLibrary_SetDefaults(int id, string gamedirname)
|
|||
games[id].startmap = "map c0a0\n";
|
||||
games[id].trainingmap = "map t0a0\n";
|
||||
games[id].cldll = 1;
|
||||
games[id].hlversion = "1000";
|
||||
games[id].minversion = "1000";
|
||||
games[id].svonly = 0;
|
||||
games[id].installed = 1;
|
||||
games[id].chatroom = gamedirname;
|
||||
games[id].readme = "readme.txt";
|
||||
games[id].pkgid = -1;
|
||||
games[id].steambg = 0;
|
||||
|
||||
#if 0
|
||||
if (games[id].gamedir == "valve") {
|
||||
|
@ -393,21 +412,61 @@ GameLibrary_SetDefaults(int id, string gamedirname)
|
|||
#endif
|
||||
}
|
||||
|
||||
/** Checks if a given game directory was installed manually. */
|
||||
static bool
|
||||
GameLibrary_CheckLocalPresence(string gameDir)
|
||||
{
|
||||
string testPkgDir = __NULL__;
|
||||
bool returnSuccess = true;
|
||||
|
||||
for (int x = 0i; (testPkgDir = getgamedirinfo(x, 0)); x++) {
|
||||
if (gameDir == testPkgDir) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GameLibrary_InitCustom(void)
|
||||
{
|
||||
int id;
|
||||
int foundself = 0;
|
||||
string gamedirname;
|
||||
string gamedirname = __NULL__;
|
||||
gameinfo_count = 0;
|
||||
int packageinfo_count = 0i;
|
||||
int c = 0i;
|
||||
|
||||
/* first count let's all manually installed mods */
|
||||
for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) {
|
||||
gameinfo_count++;
|
||||
}
|
||||
|
||||
/* count the package installed mods after */
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string packageName = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
string installStatus = getpackagemanagerinfo(i, GPMI_INSTALLED);
|
||||
string prefix = substring(packageName, 0, 3);
|
||||
|
||||
/* only care about installed mods (custom games) */
|
||||
if (prefix == "cg_" && installStatus == "enabled") {
|
||||
string gameDir = substring(packageName, 3, -1);
|
||||
tokenizebyseparator(gameDir, "=");
|
||||
gameDir = argv(0);
|
||||
|
||||
/* check if this mod was installed manually already */
|
||||
if (GameLibrary_CheckLocalPresence(gameDir) == true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
packageinfo_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* re-allocate the game list */
|
||||
memfree(games);
|
||||
games = memalloc(sizeof(gameinfo_t) * gameinfo_count);
|
||||
games = memalloc(sizeof(gameinfo_t) * (gameinfo_count + packageinfo_count));
|
||||
|
||||
/* The things we do for frequent flyer mileage. */
|
||||
if (!games)
|
||||
|
@ -431,14 +490,56 @@ GameLibrary_InitCustom(void)
|
|||
NSLog("[MENU] Found nothing for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_NONE;
|
||||
}
|
||||
c = id + 1;
|
||||
}
|
||||
|
||||
/* iterate through all packages again */
|
||||
for (int i = 0i; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string packageName = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
string installStatus = getpackagemanagerinfo(i, GPMI_INSTALLED);
|
||||
string prefix = substring(packageName, 0, 3);
|
||||
|
||||
/* same check as above in the counter */
|
||||
if (prefix == "cg_" && installStatus == "enabled") {
|
||||
string gameDir = substring(packageName, 3, -1);
|
||||
tokenizebyseparator(gameDir, "=");
|
||||
gameDir = argv(0);
|
||||
|
||||
if (GameLibrary_CheckLocalPresence(gameDir) == true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string titleString = getpackagemanagerinfo(i, GPMI_TITLE);
|
||||
string versionString = getpackagemanagerinfo(i, GPMI_VERSION);
|
||||
string authorString = getpackagemanagerinfo(i, GPMI_AUTHOR);
|
||||
string sizeString = getpackagemanagerinfo(i, GPMI_FILESIZE);
|
||||
string websiteString = getpackagemanagerinfo(i, GPMI_WEBSITE);
|
||||
|
||||
//print(sprintf("Adding packaged game %S\n", gameDir));
|
||||
GameLibrary_SetDefaults(c, gameDir);
|
||||
|
||||
games[c].game = substring(titleString, 5, -1); /* strip 'Mod: '*/
|
||||
games[c].url_info = websiteString;
|
||||
games[c].version = versionString;
|
||||
games[c].size = (int)stof(sizeString);
|
||||
games[c].type = "Both";
|
||||
games[c].info_type = GAMEINFO_PACKAGE;
|
||||
games[c].pkgname = strcat("cg_", gameDir, ";game_", gameDir, ";");
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
/* now we can pretend that these weren't their own thing */
|
||||
gameinfo_count += packageinfo_count;
|
||||
|
||||
/* we may have some mods, but we're not running any of them. Fatal */
|
||||
if (gameinfo_current == -1) {
|
||||
print("^1FATAL ERROR: NO LIBLIST.GAM FOR CURRENT MOD FOUND!\n");
|
||||
crash();
|
||||
return;
|
||||
}
|
||||
|
||||
print(sprintf("GameLibrary initialized (%i entries).\n", gameinfo_count));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -460,7 +561,6 @@ GameLibrary_Init(void)
|
|||
|
||||
/* only run this when not in web-client mode */
|
||||
#ifndef WEBMENU
|
||||
|
||||
if (GameLibrary_CheckManifest(id, gamedirname) == 1) {
|
||||
NSLog("[MENU] Found manifest for %s", gamedirname);
|
||||
games[id].info_type = GAMEINFO_MANIFEST;
|
||||
|
@ -523,8 +623,8 @@ GameLibrary_InstallProgress(void)
|
|||
int pkgid;
|
||||
|
||||
/* package query */
|
||||
pkgid = Updates_IDForName(argv(i));
|
||||
st = Updates_GetInfo(pkgid, GPMI_INSTALLED);
|
||||
pkgid = GameLibrary_IDForPackageName(argv(i));
|
||||
st = getpackagemanagerinfo(pkgid, GPMI_INSTALLED);
|
||||
|
||||
/* filter out statuses so we can calculate percentage */
|
||||
switch (st) {
|
||||
|
@ -557,10 +657,11 @@ static void
|
|||
GameLibrary_InstallStart(int gameid)
|
||||
{
|
||||
int count;
|
||||
|
||||
count = tokenize(games[gameid].pkgname);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int pkgid = Updates_IDForName(argv(i));
|
||||
int pkgid = GameLibrary_IDForPackageName(argv(i));
|
||||
localcmd(sprintf("pkg add %s\n", argv(i)));
|
||||
print(sprintf("Marking package %s for install.\n",
|
||||
argv(i)));
|
||||
|
@ -577,7 +678,12 @@ GameLibrary_Install(int gameID)
|
|||
{
|
||||
string st;
|
||||
|
||||
st = Updates_GetInfo(games[gameID].pkgid, GPMI_INSTALLED);
|
||||
if (gameID >= gameinfo_count || gameID < 0i) {
|
||||
print(sprintf("GameLibrary_Install: Invalid game id %i!\n", gameID));
|
||||
return;
|
||||
}
|
||||
|
||||
st = getpackagemanagerinfo(games[gameID].pkgid, GPMI_INSTALLED);
|
||||
|
||||
print(st);
|
||||
print("\n");
|
||||
|
@ -595,6 +701,11 @@ GameLibrary_Install(int gameID)
|
|||
void
|
||||
GameLibrary_Activate(int gameID)
|
||||
{
|
||||
if (gameID >= gameinfo_count || gameID < 0i) {
|
||||
print(sprintf("GameLibrary_Activate: Invalid game id %i!\n", gameID));
|
||||
return;
|
||||
}
|
||||
|
||||
GameLibrary_Set(gameID);
|
||||
|
||||
if (games[gameID].info_type == GAMEINFO_MANIFEST)
|
||||
|
@ -623,4 +734,99 @@ GameLibrary_Deactivate(void)
|
|||
localcmd("menu_restart\n");
|
||||
localcmd("menu_customgame\n");
|
||||
localcmd("menu_musicstart\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the ID for the currently activate game. */
|
||||
int
|
||||
GameLibrary_GetCurrentGame(void)
|
||||
{
|
||||
return gameinfo_current;
|
||||
}
|
||||
|
||||
int
|
||||
GameLibrary_GetGameCount(void)
|
||||
{
|
||||
return gameinfo_count;
|
||||
}
|
||||
|
||||
__variant
|
||||
GameLibrary_GetInfo(gameInfo_t infoType)
|
||||
{
|
||||
return GameLibrary_GetGameInfo(gameinfo_current, infoType);
|
||||
}
|
||||
|
||||
__variant
|
||||
GameLibrary_GetGameInfo(int gameID, gameInfo_t infoType)
|
||||
{
|
||||
if (gameID >= gameinfo_count || gameID < 0i) {
|
||||
print(sprintf("GameLibrary_GetGameInfo: Invalid game id %i!\n", gameID));
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
switch (infoType) {
|
||||
case GAMEINFO_TITLE:
|
||||
return (string)games[gameID].game;
|
||||
break;
|
||||
case GAMEINFO_GAMEDIR:
|
||||
return (string)games[gameID].gamedir;
|
||||
break;
|
||||
case GAMEINFO_FALLBACKDIR:
|
||||
return (string)games[gameID].fallback_dir;
|
||||
break;
|
||||
case GAMEINFO_BASEDIR:
|
||||
return (string)games[gameID].base_dir;
|
||||
break;
|
||||
case GAMEINFO_WEBSITE:
|
||||
return (string)games[gameID].url_info;
|
||||
break;
|
||||
case GAMEINFO_VERSION:
|
||||
return (string)games[gameID].version;
|
||||
break;
|
||||
case GAMEINFO_SIZE:
|
||||
return (int)games[gameID].size;
|
||||
break;
|
||||
case GAMEINFO_TYPE:
|
||||
return (string)games[gameID].type;
|
||||
break;
|
||||
case GAMEINFO_NOPLAYERMODELS:
|
||||
return games[gameID].nomodels == 1 ? true : false;
|
||||
break;
|
||||
case GAMEINFO_NOSPRAYS:
|
||||
return games[gameID].nosprays == 1 ? true : false;
|
||||
break;
|
||||
case GAMEINFO_STARTMAP:
|
||||
return (string)games[gameID].startmap;
|
||||
break;
|
||||
case GAMEINFO_TRAININGMAP:
|
||||
return (string)games[gameID].trainingmap;
|
||||
break;
|
||||
case GAMEINFO_MINVERSION:
|
||||
return (string)games[gameID].minversion;
|
||||
break;
|
||||
case GAMEINFO_CHATROOM:
|
||||
return (string)games[gameID].chatroom;
|
||||
break;
|
||||
case GAMEINFO_READMEFILE:
|
||||
return (string)games[gameID].readme;
|
||||
break;
|
||||
case GAMEINFO_INTROVIDEO:
|
||||
return (string)games[gameID].introvideo;
|
||||
break;
|
||||
case GAMEINFO_MENUMAP:
|
||||
return (string)games[gameID].menumap;
|
||||
break;
|
||||
case GAMEINFO_AUTHOR:
|
||||
return (string)"Unknown";
|
||||
break;
|
||||
case GAMEINFO_AUTHORSITE:
|
||||
return (string)"Unknown";
|
||||
break;
|
||||
case GAMEINFO_PACKAGELIST:
|
||||
return (string)games[gameID].pkgname;
|
||||
break;
|
||||
case GAMEINFO_INSTALLED:
|
||||
return games[gameID].installed == 1 ? true : false;
|
||||
default:
|
||||
return __NULL__;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,4 +9,5 @@ tcp.qc
|
|||
util.qc
|
||||
updates.qc
|
||||
gamelibrary.qc
|
||||
maplibrary.qc
|
||||
#endlist
|
||||
|
|
47
src/platform/maplibrary.h
Normal file
47
src/platform/maplibrary.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*! @file maplibrary.h
|
||||
@brief Map library parsing and querying of metadata.
|
||||
|
||||
Menus need to be aware of what levels aka maps are available for modes like
|
||||
multiplayer. The MapLibrary is by configured to only parse levels from the
|
||||
current game directory (much like GoldSrc) and optionally can blacklist
|
||||
maps based on a variety of criteria which may be configurable at some point
|
||||
in time.
|
||||
|
||||
The menu needs to call MapLibrary_Init() at least once, after which you can
|
||||
query the total amount of maps that are available via MapLibrary_GetMapCount().
|
||||
|
||||
You can then iterate over the individual entries with MapLibrary_GetInfo().
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MAPINFO_NAME, /**< (string) Name of the map. E.g. e1m1 */
|
||||
MAPINFO_TITLE, /**< (string) Title of the map. E.g. "Abyss of Cake" */
|
||||
MAPINFO_AUTHOR, /**< (string) Author of the map. E.g. "John Doe" */
|
||||
MAPINFO_TYPE /**< (string) Type of map.*/
|
||||
} mapType_t;
|
||||
|
||||
/** Initialize the map library, MapLibrary_GetMapCount() will return the amount of maps available. */
|
||||
void MapLibrary_Init(void);
|
||||
|
||||
/** Returns the total amount of maps available. */
|
||||
int MapLibrary_GetMapCount(void);
|
||||
|
||||
/** Retrieve information about a given mapID. See mapType_t for which fields you can query. */
|
||||
__variant MapLibrary_GetInfo(int, mapType_t);
|
178
src/platform/maplibrary.qc
Normal file
178
src/platform/maplibrary.qc
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
string name;
|
||||
string title;
|
||||
string author;
|
||||
string type;
|
||||
} mapLibrary_t;
|
||||
|
||||
mapLibrary_t *g_mapLibrary;
|
||||
var int g_mapLibrary_count = 0i;
|
||||
var int map_blacklist_count = 0i;
|
||||
string *map_blacklist;
|
||||
|
||||
static string
|
||||
MapLibrary_GetMapGamedir(void)
|
||||
{
|
||||
string gdir = cvar_string("fs_game");
|
||||
|
||||
/* HACK: work around FTEQW's path choice */
|
||||
if (gdir == "ftehl")
|
||||
gdir = "valve";
|
||||
|
||||
return gdir;
|
||||
}
|
||||
|
||||
static bool
|
||||
MapLibrary_MapInGameDir(string fileName, string gameDir)
|
||||
{
|
||||
bool list = true;
|
||||
|
||||
/* only look for maps in the current gamedir, requires SEARCH_FULLPACKAGE */
|
||||
if (gameDir != MapLibrary_GetMapGamedir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ignore test_ prefix maps */
|
||||
if (substring(fileName, 0, 5) == "test_") {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* see if any of our blacklisted names match */
|
||||
for (int b = 0i; b < map_blacklist_count; b++) {
|
||||
if (fileName == map_blacklist[b]) {
|
||||
list = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
MapLibrary_Init(void)
|
||||
{
|
||||
int i = 0i;
|
||||
int c = 0i;
|
||||
int mapCount = 0i;
|
||||
string mapFile, mapDir;
|
||||
searchhandle mapsearch;
|
||||
string gameDir;
|
||||
|
||||
/* already initialized */
|
||||
if (g_mapLibrary_count != 0i)
|
||||
return;
|
||||
|
||||
g_mapLibrary_count = 0i;
|
||||
gameDir = MapLibrary_GetMapGamedir();
|
||||
|
||||
/* map blacklist code */
|
||||
filestream fs_blacklist;
|
||||
fs_blacklist = fopen("scripts/map_blacklist", FILE_READ);
|
||||
|
||||
if (fs_blacklist >= 0) {
|
||||
string temp;
|
||||
|
||||
while ((temp = fgets(fs_blacklist))) {
|
||||
map_blacklist_count++;
|
||||
}
|
||||
|
||||
map_blacklist = memalloc(sizeof(string) * map_blacklist_count);
|
||||
fseek(fs_blacklist, 0);
|
||||
|
||||
while ((temp = fgets(fs_blacklist))) {
|
||||
map_blacklist[i] = temp;
|
||||
i++;
|
||||
}
|
||||
|
||||
fclose(fs_blacklist);
|
||||
}
|
||||
|
||||
/* search for all maps in the current PATH */
|
||||
mapsearch = search_begin("maps/*.bsp", SEARCH_NAMESORT | SEARCH_FULLPACKAGE, TRUE);
|
||||
mapCount = search_getsize(mapsearch);
|
||||
|
||||
/* we now iterate over the search entries to filter results out */
|
||||
for (i = 0i; i < mapCount; i++) {
|
||||
mapFile = substring(search_getfilename(mapsearch, i), 5, -1);
|
||||
|
||||
/* the strlen(gameDir) is technically wrong, but it'll work anyway because
|
||||
we only care about maps in the current game directory */
|
||||
mapDir = substring(search_getpackagename(mapsearch, i), 0, strlen(gameDir));
|
||||
|
||||
if (MapLibrary_MapInGameDir(mapFile, mapDir) == true) {
|
||||
g_mapLibrary_count++;
|
||||
}
|
||||
}
|
||||
search_end(mapsearch);
|
||||
|
||||
g_mapLibrary = (mapLibrary_t *)memalloc(sizeof(mapLibrary_t) * g_mapLibrary_count);
|
||||
|
||||
/* let's do it again, but this time we'll sort the data into our array */
|
||||
mapsearch = search_begin("maps/*.bsp", SEARCH_NAMESORT | SEARCH_FULLPACKAGE, TRUE);
|
||||
mapCount = search_getsize(mapsearch);
|
||||
|
||||
for (i = 0i; i < mapCount; i++) {
|
||||
mapFile = substring(search_getfilename(mapsearch, i), 5, -1);
|
||||
mapDir = substring(search_getpackagename(mapsearch, i), 0, strlen(gameDir));
|
||||
|
||||
if (MapLibrary_MapInGameDir(mapFile, mapDir) == true) {
|
||||
g_mapLibrary[c].name = mapFile;
|
||||
g_mapLibrary[c].title = mapFile;
|
||||
g_mapLibrary[c].author = "Unknown";
|
||||
g_mapLibrary[c].type = "Unknown";
|
||||
c++;
|
||||
}
|
||||
}
|
||||
search_end(mapsearch);
|
||||
|
||||
print(sprintf("MapLibrary initialized (%i entries).\n", g_mapLibrary_count));
|
||||
}
|
||||
|
||||
int
|
||||
MapLibrary_GetMapCount(void)
|
||||
{
|
||||
return g_mapLibrary_count;
|
||||
}
|
||||
|
||||
__variant
|
||||
MapLibrary_GetInfo(int mapID, mapType_t infoType)
|
||||
{
|
||||
if (mapID >= g_mapLibrary_count || mapID < 0i) {
|
||||
print(sprintf("MapLibrary_GetInfo: Invalid map id %i!\n", mapID));
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
switch (infoType) {
|
||||
case MAPINFO_NAME:
|
||||
return g_mapLibrary[mapID].name;
|
||||
break;
|
||||
case MAPINFO_TITLE:
|
||||
return g_mapLibrary[mapID].title;
|
||||
break;
|
||||
case MAPINFO_AUTHOR:
|
||||
return g_mapLibrary[mapID].author;
|
||||
break;
|
||||
case MAPINFO_TYPE:
|
||||
return g_mapLibrary[mapID].type;
|
||||
break;
|
||||
default:
|
||||
return __NULL__;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,28 @@
|
|||
*/
|
||||
|
||||
#ifndef WEBMENU
|
||||
/* the same as GameLibrary_IDForPackageName */
|
||||
static int
|
||||
ModServer_IDForPackageName(string packageName)
|
||||
{
|
||||
string f;
|
||||
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string name;
|
||||
name = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
|
||||
/* Spike started randomly putting version numbers into package names */
|
||||
f = sprintf("%s=%s", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
void*
|
||||
memrealloc(__variant *oldptr, int elementsize, int old_num, int new_num)
|
||||
{
|
||||
|
@ -51,7 +73,7 @@ ModServer_ParseList(string data)
|
|||
|
||||
for (int x = 0; x < gameinfo_count; x++) {
|
||||
/* skip mods we already have. */
|
||||
if (gamedir == games[x].gamedir) {
|
||||
if (gamedir == GameLibrary_GetGameInfo(x, GAMEINFO_GAMEDIR)) {
|
||||
skip = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -104,7 +126,7 @@ ModServer_ParseItem(string data)
|
|||
games[id].startmap = "c0a0";
|
||||
games[id].trainingmap = "t0a0";
|
||||
games[id].cldll = 1;
|
||||
games[id].hlversion = "1110";
|
||||
games[id].minversion = "1110";
|
||||
games[id].svonly = 0;
|
||||
games[id].installed = 0;
|
||||
games[id].pkgid = -1;
|
||||
|
@ -141,8 +163,8 @@ ModServer_ParseItem(string data)
|
|||
case "gameinfo_type":
|
||||
games[id].type = argv(i+1);
|
||||
break;
|
||||
case "gameinfo_hlversion":
|
||||
games[id].hlversion = argv(i+1);
|
||||
case "gameinfo_minversion":
|
||||
games[id].minversion = argv(i+1);
|
||||
break;
|
||||
case "gameinfo_nomodels":
|
||||
games[id].nomodels = stof(argv(i+1));
|
||||
|
@ -161,7 +183,7 @@ ModServer_ParseItem(string data)
|
|||
break;
|
||||
case "gameinfo_pkgname":
|
||||
games[id].pkgname = argv(i+1);
|
||||
games[id].pkgid = Updates_IDForName(games[id].pkgname);
|
||||
games[id].pkgid = ModServer_IDForPackageName(games[id].pkgname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -169,6 +191,8 @@ ModServer_ParseItem(string data)
|
|||
}
|
||||
}
|
||||
|
||||
void Updater_URI_Callback(float id, float code, string data, int resourcebytes);
|
||||
|
||||
/* Called as an eventual result of the uri_get builtin. */
|
||||
void
|
||||
ModServer_URI_Callback(float id, float code, string data, int resourcebytes)
|
||||
|
@ -202,8 +226,7 @@ ModServer_URI_Callback(float id, float code, string data, int resourcebytes)
|
|||
ModServer_ParseItem(data);
|
||||
break;
|
||||
case MODSERVER_REQ_PKGNAMES:
|
||||
games[gameinfo_current].pkgname = data;
|
||||
g_pkgname_updating = 0;
|
||||
Updater_URI_Callback(id, code, data, resourcebytes);
|
||||
break;
|
||||
default:
|
||||
print(sprintf("^1ModServer_URI_Callback^7: Unknown request id %d with code %d\n", id, code));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -14,54 +14,93 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
string(float id, float b) getgamedirinfo = #0;
|
||||
string(int packageidx, int desiredfield) getpackagemanagerinfo = #0;
|
||||
/*! @file updates.h
|
||||
@brief Game and content update handler functions.
|
||||
|
||||
The updater is an abstraction of the engine its own package manager.
|
||||
Not all packages the engine offers are related to the game you're currently
|
||||
running. Therefore we offer our own API within Nuclide to deal with game updates.
|
||||
|
||||
You want to call Updates_Init() once, after which Updates_GetUpdaterStatus() should be queried to determine when the Updater is ready. That is not necessary, but it might be helpful to throw up a loading screen while that is returning UPDATER_PENDING.
|
||||
|
||||
Once Updates_GetUpdaterStatus() reports UPDATER_INITIALIZED, you can expect the loading to be fully done.
|
||||
|
||||
The function Updates_GetPackageCount() will report the total amount of update packages available for the game. These are not 'new' updates, they contain every package associated with the game that can and should be installed and kept updated.
|
||||
|
||||
Use Updates_GetInfo() to retrieve metadata about individual packages.
|
||||
*/
|
||||
|
||||
/** Different types you can pass to `Updates_GetInfo(...)` to learn details about a given Update entry. */
|
||||
typedef enum
|
||||
{
|
||||
GPMI_NAME, /**< name of the package, for use with the pkg command. */
|
||||
GPMI_CATEGORY, /**< category text */
|
||||
GPMI_TITLE, /**< name of the package, for showing the user. */
|
||||
GPMI_VERSION, /**< version info (may have multiple with the same name but different versions) */
|
||||
GPMI_DESCRIPTION, /**< some blurb */
|
||||
GPMI_LICENSE, /**< what license its distributed under */
|
||||
GPMI_AUTHOR, /**< name of the person(s) who created it */
|
||||
GPMI_WEBSITE, /**< where to contribute/find out more info/etc */
|
||||
GPMI_INSTALLED, /**< current state */
|
||||
GPMI_ACTION, /**< desired state */
|
||||
GPMI_AVAILABLE, /**< whether it may be downloaded or not. */
|
||||
GPMI_FILESIZE, /**< size to download. */
|
||||
UPDATE_NAME, /**< (string) name of the package, for use with the pkg command. */
|
||||
UPDATE_CATEGORY, /**< (string) category text */
|
||||
UPDATE_TITLE, /**< (string) name of the package, for showing the user. */
|
||||
UPDATE_VERSION, /**< (string) version info (may have multiple with the same name but different versions) */
|
||||
UPDATE_DESCRIPTION, /**< (string) some blurb */
|
||||
UPDATE_LICENSE, /**< (string) what license its distributed under */
|
||||
UPDATE_AUTHOR, /**< (string) name of the person(s) who created it */
|
||||
UPDATE_WEBSITE, /**< (string) where to contribute/find out more info/etc */
|
||||
UPDATE_STATE, /**< (updateState_t) The current state of the update. */
|
||||
UPDATE_ACTION, /**< (updateAction_t) Pending action of the update. */
|
||||
UPDATE_FILESIZE, /**< (int) size to download in bytes. */
|
||||
UPDATE_PREVIEWIMAGE, /**< (string) Path to a preview image in 4:3 aspect ratio. */
|
||||
UPDATE_STATUSSTRING, /**< (string) Localizable string that gives you the update status. */
|
||||
UPDATE_DLPERCENTAGE, /**< (float) Download progress in percent (0-100). */
|
||||
} updateType_t;
|
||||
|
||||
typedef struct
|
||||
/** Return values from passing UPDATE_STATE to Updates_GetInfo() */
|
||||
typedef enum
|
||||
{
|
||||
string name;
|
||||
string category;
|
||||
string title;
|
||||
string version;
|
||||
string description;
|
||||
string license;
|
||||
string author;
|
||||
string website;
|
||||
string installed;
|
||||
int size;
|
||||
int uid;
|
||||
} update_t;
|
||||
UPDATESTATE_NONE, /**< Update is not installed, or unavailable. */
|
||||
UPDATESTATE_DISABLED, /**< Update is installed, but disabled. */
|
||||
UPDATESTATE_ENABLED, /**< Update is installed and enabled. */
|
||||
UPDATESTATE_CORRUPT, /**< Update on disk is corrupted. */
|
||||
UPDATESTATE_PENDING /**< Update is pending a change. Usually when we're downloading it. */
|
||||
} updateState_t;
|
||||
|
||||
int g_platform_update_count;
|
||||
update_t *updates;
|
||||
/** Return values from passing UPDATE_ACTION to Updates_GetInfo() */
|
||||
typedef enum
|
||||
{
|
||||
UPDATEACTION_NONE, /**< Update is not marked for any change. */
|
||||
UPDATEACTION_INSTALL, /**< Update marked for installation. */
|
||||
UPDATEACTION_REINSTALL, /**< Update marked as needing re-installation. */
|
||||
UPDATEACTION_UNINSTALL, /**< Update marked for removal. */
|
||||
UPDATEACTION_AUTOINSTALL, /**< Update marked as needing to be installed, due to a dependency. */
|
||||
UPDATEACTION_DISABLE, /**< Update has been marked for disabling. */
|
||||
UPDATEACTION_RETAIN /**< Update has been marked as being retained. */
|
||||
} updateAction_t;
|
||||
|
||||
#define FN_UPDATE_IMGURL "http://www.frag-net.com/dl/img/%s.jpg"
|
||||
/** These are the possible return values from Updates_GetUpdaterStatus().
|
||||
That way you can put up a loading screen for when the updater is still initiliazing,
|
||||
or be notified of when an updater is not available at all. */
|
||||
typedef enum
|
||||
{
|
||||
UPDATER_NONE, /**< Nuclide's updater has not been initialized. You need to call Update_Init(). */
|
||||
UPDATER_UNAVAILABLE, /**< Nuclide's updater is unavailable. This may be due to the update server being offline. */
|
||||
UPDATER_PENDING, /**< Nuclide's updater is pending. May change to UNAVAILABLE or INITIALIZED. */
|
||||
UPDATER_INITIALIZED /**< Nuclide's updater is initialized and may have entries. Use Updates_GetUpdateCount() to query how many. */
|
||||
} updaterStatus_t;
|
||||
|
||||
/** Call this in order to contact the update server and fill the list of updates. */
|
||||
void Updates_Init(void);
|
||||
void Updates_Refresh(void);
|
||||
/** Retrieve the status of the updater. See updaterStatus_t for valid return values. */
|
||||
updaterStatus_t Updates_GetUpdaterStatus(void);
|
||||
/** Returns the total amount of updates available for the currently running game. */
|
||||
int Updates_GetPackageCount(void);
|
||||
int Updates_IDForName(string);
|
||||
string Updates_NameForID(int);
|
||||
string Updates_GetInfo(int, updateType_t);
|
||||
/** Query a package (by ID) for its various info fields. See updateType_t for available fields. */
|
||||
__variant Updates_GetInfo(int, updateType_t);
|
||||
/** Returns if our current game has updates available for any installed packages. */
|
||||
bool Updates_Available(void);
|
||||
|
||||
/** Toggle the installation/disabling of an update. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Toggle(int);
|
||||
/** Mark an update as pending installion. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Install(int);
|
||||
/** Mark an update as pending deletion. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Remove(int);
|
||||
bool Updates_ApplyPendingChanges(void);
|
||||
/** Mark an update as pending uninstallation. May return true/false if it succeeded in marking the package. */
|
||||
bool Updates_Destroy(int);
|
||||
/** Apply all pending changes to packages. May return true/false if it succeeded in doing so. */
|
||||
bool Updates_ApplyPendingChanges(void);
|
||||
/** Called by the console command `platformRefreshUpdates`, which your menu needs to implement. Otherwise you will not see pending changes reflected in your menu interface. */
|
||||
void Updates_RefreshState(void);
|
|
@ -1,13 +1,72 @@
|
|||
/** needs to be called upon menu-init, and call Updates_Refresh() if auto-updates
|
||||
are enabled. if a chooser does not want updates, then we won't. */
|
||||
/*
|
||||
* Copyright (c) 2016-2023 Vera Visions LLC.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
string name;
|
||||
string category;
|
||||
string title;
|
||||
string version;
|
||||
string description;
|
||||
string license;
|
||||
string author;
|
||||
string website;
|
||||
string installed;
|
||||
updateState_t state;
|
||||
updateAction_t pending_action;
|
||||
int size;
|
||||
int uid;
|
||||
string preview_image;
|
||||
float dlpercentage;
|
||||
} update_t;
|
||||
|
||||
string(float id, float b) getgamedirinfo = #0;
|
||||
string(int packageidx, int desiredfield) getpackagemanagerinfo = #0;
|
||||
|
||||
#define FN_UPDATE_IMGURL "http://www.frag-net.com/dl/img/%s.jpg"
|
||||
int g_platform_update_count;
|
||||
update_t *updates;
|
||||
|
||||
var updaterStatus_t updater_package_status = UPDATER_NONE;
|
||||
|
||||
void
|
||||
Updates_Init(void)
|
||||
{
|
||||
/*localcmd("pkg addsource https://www.frag-net.com/pkgs/list\n");*/
|
||||
print("Update system initialized.\n");
|
||||
string packages;
|
||||
|
||||
/* first, see if our game info sets any packages. */
|
||||
packages = GameLibrary_GetInfo(GAMEINFO_PACKAGELIST);
|
||||
|
||||
/* we have no hard-coded list of supported packages, so query frag-net.com */
|
||||
if (!packages) {
|
||||
string gamedir = cvar_string("fs_game");
|
||||
print(sprintf("Querying package names for %s\n", gamedir));
|
||||
uri_get(sprintf("http://www.frag-net.com/dl/packages_%s", uri_escape(gamedir)), MODSERVER_REQ_PKGNAMES);
|
||||
updater_package_status = UPDATER_PENDING;
|
||||
} else {
|
||||
updater_package_status = UPDATER_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
updaterStatus_t
|
||||
Updates_GetUpdaterStatus(void)
|
||||
{
|
||||
return updater_package_status;
|
||||
}
|
||||
|
||||
/** will return a cached value */
|
||||
int
|
||||
Updates_GetPackageCount(void)
|
||||
{
|
||||
|
@ -20,9 +79,10 @@ Updates_IsRecommended(string packageName)
|
|||
{
|
||||
string newName = "";
|
||||
int countPkg = 0i;
|
||||
string packageList = GameLibrary_GetInfo(GAMEINFO_PACKAGELIST);
|
||||
|
||||
/* cancel out early if need be */
|
||||
if not (games[gameinfo_current].pkgname)
|
||||
if not (packageList)
|
||||
return true;
|
||||
|
||||
/* get rid of the version string FTEQW appends */
|
||||
|
@ -30,7 +90,7 @@ Updates_IsRecommended(string packageName)
|
|||
newName = argv(0);
|
||||
|
||||
/* iterate over the recommended packages */
|
||||
countPkg = (int)tokenizebyseparator(games[gameinfo_current].pkgname, ";");
|
||||
countPkg = (int)tokenizebyseparator(packageList, ";");
|
||||
|
||||
for (int i = 0i; i < countPkg; i++) {
|
||||
/* there's a match */
|
||||
|
@ -42,8 +102,68 @@ Updates_IsRecommended(string packageName)
|
|||
return false;
|
||||
}
|
||||
|
||||
/** called whenever we need to re-initialize the updates struct */
|
||||
void
|
||||
static void
|
||||
Updates_RefreshStateValues(int packageID)
|
||||
{
|
||||
int pkgUID = updates[packageID].uid;
|
||||
string installedState = getpackagemanagerinfo(pkgUID, GPMI_INSTALLED);
|
||||
string actionState = getpackagemanagerinfo(pkgUID, GPMI_ACTION);
|
||||
|
||||
switch (actionState) {
|
||||
case "user":
|
||||
updates[packageID].pending_action = UPDATEACTION_INSTALL;
|
||||
break;
|
||||
case "reinstall":
|
||||
updates[packageID].pending_action = UPDATEACTION_REINSTALL;
|
||||
break;
|
||||
case "purge":
|
||||
updates[packageID].pending_action = UPDATEACTION_UNINSTALL;
|
||||
break;
|
||||
case "auto":
|
||||
updates[packageID].pending_action = UPDATEACTION_AUTOINSTALL;
|
||||
break;
|
||||
case "disable":
|
||||
updates[packageID].pending_action = UPDATEACTION_DISABLE;
|
||||
break;
|
||||
case "retain":
|
||||
/*updates[packageID].pending_action = UPDATEACTION_RETAIN;
|
||||
break;*/
|
||||
default:
|
||||
updates[packageID].pending_action = UPDATEACTION_NONE;
|
||||
}
|
||||
|
||||
switch (installedState) {
|
||||
case "present":
|
||||
updates[packageID].state = UPDATESTATE_DISABLED;
|
||||
break;
|
||||
case "enabled":
|
||||
updates[packageID].state = UPDATESTATE_ENABLED;
|
||||
break;
|
||||
case "corrupt":
|
||||
updates[packageID].state = UPDATESTATE_CORRUPT;
|
||||
break;
|
||||
case "pending":
|
||||
updates[packageID].state = UPDATESTATE_PENDING;
|
||||
break;
|
||||
default:
|
||||
updates[packageID].state = UPDATESTATE_NONE;
|
||||
}
|
||||
|
||||
updates[packageID].dlpercentage = stof(installedState);
|
||||
|
||||
/* HACK: the engine doesn't seem to set pending while installing, so let us do the job then */
|
||||
if (updates[packageID].dlpercentage > 0)
|
||||
updates[packageID].state = UPDATESTATE_PENDING;
|
||||
|
||||
/* HACK: enabled AND pending installation? smells like an engine bug! */
|
||||
if (updates[packageID].state == UPDATESTATE_ENABLED) {
|
||||
if (updates[packageID].pending_action == UPDATEACTION_INSTALL) {
|
||||
updates[packageID].pending_action = UPDATEACTION_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Updates_Refresh(void)
|
||||
{
|
||||
int c = 0i;
|
||||
|
@ -55,7 +175,7 @@ Updates_Refresh(void)
|
|||
}
|
||||
|
||||
/* count all updates that we've got in our package sources */
|
||||
for (int i = 0i; (Updates_GetInfo(i, GPMI_NAME)); i++) {
|
||||
for (int i = 0i; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
g_platform_update_count++;
|
||||
}
|
||||
|
||||
|
@ -66,21 +186,23 @@ Updates_Refresh(void)
|
|||
int id = i;
|
||||
|
||||
/* skip not recommended packages */
|
||||
if (Updates_IsRecommended(Updates_GetInfo(id, GPMI_NAME)) == false)
|
||||
if (Updates_IsRecommended(getpackagemanagerinfo(id, GPMI_NAME)) == false)
|
||||
continue;
|
||||
|
||||
updates[c].name = Updates_GetInfo(id, GPMI_NAME);
|
||||
updates[c].category = Updates_GetInfo(id, GPMI_CATEGORY);
|
||||
updates[c].title = Updates_GetInfo(id, GPMI_TITLE);
|
||||
updates[c].version = Updates_GetInfo(id, GPMI_VERSION);
|
||||
updates[c].description = Updates_GetInfo(id, GPMI_DESCRIPTION);
|
||||
updates[c].license = Updates_GetInfo(id, GPMI_LICENSE);
|
||||
updates[c].author = Updates_GetInfo(id, GPMI_AUTHOR);
|
||||
updates[c].website = Updates_GetInfo(id, GPMI_WEBSITE);
|
||||
updates[c].installed = Updates_GetInfo(id, GPMI_INSTALLED);
|
||||
updates[c].size = (int)stof(Updates_GetInfo(id, GPMI_FILESIZE));
|
||||
updates[c].name = getpackagemanagerinfo(id, GPMI_NAME);
|
||||
updates[c].category = getpackagemanagerinfo(id, GPMI_CATEGORY);
|
||||
updates[c].title = getpackagemanagerinfo(id, GPMI_TITLE);
|
||||
updates[c].version = getpackagemanagerinfo(id, GPMI_VERSION);
|
||||
updates[c].description = getpackagemanagerinfo(id, GPMI_DESCRIPTION);
|
||||
updates[c].license = getpackagemanagerinfo(id, GPMI_LICENSE);
|
||||
updates[c].author = getpackagemanagerinfo(id, GPMI_AUTHOR);
|
||||
updates[c].website = getpackagemanagerinfo(id, GPMI_WEBSITE);
|
||||
|
||||
updates[c].size = (int)stof(getpackagemanagerinfo(id, GPMI_FILESIZE));
|
||||
updates[c].uid = i;
|
||||
precache_pic(sprintf(FN_UPDATE_IMGURL, updates[c].name));
|
||||
updates[c].preview_image = sprintf(FN_UPDATE_IMGURL, updates[c].name);
|
||||
Updates_RefreshStateValues(c);
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
|
@ -88,94 +210,179 @@ Updates_Refresh(void)
|
|||
g_platform_update_count = c;
|
||||
}
|
||||
|
||||
/** Returns the package ID for a given name. Will return -1 when not available. */
|
||||
int
|
||||
Updates_IDForName(string packageName)
|
||||
{
|
||||
string f;
|
||||
|
||||
for (int i = 0; (getpackagemanagerinfo(i, GPMI_NAME)); i++) {
|
||||
string name;
|
||||
name = getpackagemanagerinfo(i, GPMI_NAME);
|
||||
|
||||
/* Spike started randomly putting version numbers into package names */
|
||||
f = sprintf("%s=%s", packageName, getpackagemanagerinfo(i, GPMI_VERSION));
|
||||
|
||||
if (name == f) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* no package id whatsoever */
|
||||
return (-1i);
|
||||
}
|
||||
|
||||
/** Returns the package name for a given ID. Returns __NULL__ when not available. */
|
||||
string
|
||||
Updates_NameForID(int packageID)
|
||||
{
|
||||
string packageName = getpackagemanagerinfo(packageID, GPMI_NAME);
|
||||
|
||||
if not (packageName)
|
||||
return __NULL__;
|
||||
|
||||
return packageName;
|
||||
}
|
||||
|
||||
/** Query a package (by ID) for its various info fields. See updateType_t for available fields. */
|
||||
string
|
||||
__variant
|
||||
Updates_GetInfo(int packageID, updateType_t fieldType)
|
||||
{
|
||||
return getpackagemanagerinfo(packageID, (int)fieldType);
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_GetInfo: Invalid package id %i!\n", packageID));
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
switch (fieldType) {
|
||||
case UPDATE_NAME:
|
||||
return (string)updates[packageID].name;
|
||||
break;
|
||||
case UPDATE_CATEGORY:
|
||||
return (string)updates[packageID].category;
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
return (string)updates[packageID].title;
|
||||
break;
|
||||
case UPDATE_VERSION:
|
||||
return (string)updates[packageID].version;
|
||||
break;
|
||||
case UPDATE_DESCRIPTION:
|
||||
return (string)updates[packageID].description;
|
||||
break;
|
||||
case UPDATE_LICENSE:
|
||||
return (string)updates[packageID].license;
|
||||
break;
|
||||
case UPDATE_AUTHOR:
|
||||
return (string)updates[packageID].author;
|
||||
break;
|
||||
case UPDATE_WEBSITE:
|
||||
return (string)updates[packageID].website;
|
||||
break;
|
||||
case UPDATE_STATE:
|
||||
return (updateState_t)updates[packageID].state;
|
||||
break;
|
||||
case UPDATE_ACTION:
|
||||
return (updateAction_t)updates[packageID].pending_action;
|
||||
break;
|
||||
case UPDATE_FILESIZE:
|
||||
return (int)updates[packageID].size;
|
||||
break;
|
||||
case UPDATE_PREVIEWIMAGE:
|
||||
return (string)updates[packageID].preview_image;
|
||||
break;
|
||||
case UPDATE_STATUSSTRING:
|
||||
/* if we have a action, focus on that */
|
||||
switch (updates[packageID].pending_action) {
|
||||
case UPDATEACTION_INSTALL:
|
||||
if (updates[packageID].dlpercentage > 0.0) {
|
||||
return sprintf("%d %%", updates[packageID].dlpercentage);
|
||||
} else {
|
||||
return _("UPDATE_PENDING_INSTALL");
|
||||
}
|
||||
break;
|
||||
case UPDATEACTION_REINSTALL:
|
||||
return _("UPDATE_PENDING_REINSTALL");
|
||||
break;
|
||||
case UPDATEACTION_UNINSTALL:
|
||||
return _("UPDATE_PENDING_UNINSTALL");
|
||||
break;
|
||||
case UPDATEACTION_AUTOINSTALL:
|
||||
return _("UPDATE_PENDING_AUTOINSTALL");
|
||||
break;
|
||||
case UPDATEACTION_DISABLE:
|
||||
return _("UPDATE_PENDING_DISABLE");
|
||||
break;
|
||||
case UPDATEACTION_RETAIN:
|
||||
return _("UPDATE_PENDING_RETAIN");
|
||||
break;
|
||||
default:
|
||||
switch (updates[packageID].state) {
|
||||
case UPDATESTATE_DISABLED:
|
||||
return _("UPDATE_DISABLED");
|
||||
break;
|
||||
case UPDATESTATE_ENABLED:
|
||||
return _("UPDATE_ENABLED");
|
||||
break;
|
||||
case UPDATESTATE_CORRUPT:
|
||||
return _("UPDATE_CORRUPT");
|
||||
break;
|
||||
default:
|
||||
return _("UPDATE_NOTINSTALLED");
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case UPDATE_DLPERCENTAGE:
|
||||
return updates[packageID].dlpercentage;
|
||||
break;
|
||||
default:
|
||||
return __NULL__;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns if our current game has updates available for any installed packages. */
|
||||
bool
|
||||
Updates_Available(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Toggle the installation of a package. Will return true if it was done. */
|
||||
bool
|
||||
Updates_Toggle(int packageID)
|
||||
{
|
||||
switch (updates[packageID].installed) {
|
||||
case "":
|
||||
case "rem":
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Toggle: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (updates[packageID].pending_action) {
|
||||
case UPDATEACTION_INSTALL:
|
||||
case UPDATEACTION_REINSTALL:
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
break;
|
||||
case UPDATEACTION_UNINSTALL:
|
||||
case UPDATEACTION_DISABLE:
|
||||
localcmd(sprintf("pkg add %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "pending";
|
||||
break;
|
||||
default:
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "rem";
|
||||
if (updates[packageID].state == UPDATESTATE_ENABLED) {
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
} else {
|
||||
localcmd(sprintf("pkg add %s\n", updates[packageID].name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
localcmd(sprintf("platformRefreshUpdates %i\n", packageID));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Mark a package as pending installion. May return true/false if it succeeded in marking the package. */
|
||||
bool
|
||||
Updates_Install(int packageID)
|
||||
{
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Install: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
localcmd(sprintf("pkg add %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "pending";
|
||||
localcmd(sprintf("platformRefreshUpdates %i\n", packageID));
|
||||
print(sprintf("Marking package %s for install.\n", updates[packageID].title));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Mark a package as pending deletion. May return true/false if it succeeded in marking the package. */
|
||||
bool
|
||||
Updates_Remove(int packageID)
|
||||
{
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Remove: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
localcmd(sprintf("pkg rem %s\n", updates[packageID].name));
|
||||
updates[packageID].installed = "rem";
|
||||
localcmd(sprintf("platformRefreshUpdates %i\n", packageID));
|
||||
print(sprintf("Marking package %s for 'removal'.\n", updates[packageID].title));
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Apply all pending changes to packages. May return true/false if it succeeded in doing so. */
|
||||
bool
|
||||
Updates_Destroy(int packageID)
|
||||
{
|
||||
if (packageID >= g_platform_update_count || packageID < 0i) {
|
||||
print(sprintf("Updates_Destroy: Invalid package id %i!\n", packageID));
|
||||
return false;
|
||||
}
|
||||
|
||||
localcmd(sprintf("pkg del %s\n", updates[packageID].name));
|
||||
localcmd(sprintf("platformRefreshUpdates %i\n", packageID));
|
||||
print(sprintf("Marking package %s for 'deletion'.\n", updates[packageID].title));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Updates_ApplyPendingChanges(void)
|
||||
{
|
||||
|
@ -183,4 +390,42 @@ Updates_ApplyPendingChanges(void)
|
|||
localcmd("pkg apply\n");
|
||||
print("Applying package changes.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* I hate having to put this in, but because we can only interact with the
|
||||
engine its own package manager via console commands (they are delayed as
|
||||
as result) we cannot query the result of our `pkg` commands right after
|
||||
calling them via localcmd(). Therefore menus need to implement the console
|
||||
command `platformRefreshUpdates` which calls this very function below.
|
||||
All in the hopes of improving performance just a tiny bit. */
|
||||
void
|
||||
Updates_RefreshState(void)
|
||||
{
|
||||
/* at least try to be a bit clever about it. */
|
||||
if (argv(0) == "platformRefreshUpdates") {
|
||||
Updates_RefreshStateValues((int)stof(argv(1)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* just force refresh them all otherwise. */
|
||||
for (int i = 0i; i < g_platform_update_count; i++) {
|
||||
Updates_RefreshStateValues(i);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Updater_URI_Callback(float id, float code, string data, int resourcebytes)
|
||||
{
|
||||
/* game does not have a recommended package listing remotely? make something up. */
|
||||
if (code == 404) {
|
||||
string gameDir = cvar_string("fs_game");
|
||||
games[GameLibrary_GetCurrentGame()].pkgname = strcat("cg_", gameDir, ";game_", gameDir, ";");
|
||||
|
||||
} else {
|
||||
//print(sprintf("URI: %d %d %S %i\n", id, code, data, resourcebytes));
|
||||
games[GameLibrary_GetCurrentGame()].pkgname = data;
|
||||
}
|
||||
|
||||
updater_package_status = UPDATER_INITIALIZED;
|
||||
Updates_Refresh();
|
||||
}
|
Loading…
Reference in a new issue